2
0

FileStream.Win32.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using Microsoft.Win32.SafeHandles;
  6. namespace System.IO
  7. {
  8. public partial class FileStream : Stream
  9. {
  10. private SafeFileHandle OpenHandle(FileMode mode, FileShare share, FileOptions options)
  11. {
  12. return CreateFileOpenHandle(mode, share, options);
  13. }
  14. private unsafe SafeFileHandle CreateFileOpenHandle(FileMode mode, FileShare share, FileOptions options)
  15. {
  16. Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = GetSecAttrs(share);
  17. int fAccess =
  18. ((_access & FileAccess.Read) == FileAccess.Read ? GENERIC_READ : 0) |
  19. ((_access & FileAccess.Write) == FileAccess.Write ? GENERIC_WRITE : 0);
  20. // Our Inheritable bit was stolen from Windows, but should be set in
  21. // the security attributes class. Don't leave this bit set.
  22. share &= ~FileShare.Inheritable;
  23. // Must use a valid Win32 constant here...
  24. if (mode == FileMode.Append)
  25. mode = FileMode.OpenOrCreate;
  26. int flagsAndAttributes = (int)options;
  27. // For mitigating local elevation of privilege attack through named pipes
  28. // make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
  29. // named pipe server can't impersonate a high privileged client security context
  30. // (note that this is the effective default on CreateFile2)
  31. flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS);
  32. using (DisableMediaInsertionPrompt.Create())
  33. {
  34. Debug.Assert(_path != null);
  35. return ValidateFileHandle(
  36. Interop.Kernel32.CreateFile(_path, fAccess, share, ref secAttrs, mode, flagsAndAttributes, IntPtr.Zero));
  37. }
  38. }
  39. private static bool GetDefaultIsAsync(SafeFileHandle handle)
  40. {
  41. return handle.IsAsync ?? !IsHandleSynchronous(handle, ignoreInvalid: true) ?? DefaultIsAsync;
  42. }
  43. private static unsafe bool? IsHandleSynchronous(SafeFileHandle fileHandle, bool ignoreInvalid)
  44. {
  45. if (fileHandle.IsInvalid)
  46. return null;
  47. uint fileMode;
  48. int status = Interop.NtDll.NtQueryInformationFile(
  49. FileHandle: fileHandle,
  50. IoStatusBlock: out Interop.NtDll.IO_STATUS_BLOCK ioStatus,
  51. FileInformation: &fileMode,
  52. Length: sizeof(uint),
  53. FileInformationClass: Interop.NtDll.FileModeInformation);
  54. switch (status)
  55. {
  56. case 0:
  57. // We were successful
  58. break;
  59. case Interop.NtDll.STATUS_INVALID_HANDLE:
  60. if (!ignoreInvalid)
  61. {
  62. throw Win32Marshal.GetExceptionForWin32Error(Interop.Errors.ERROR_INVALID_HANDLE);
  63. }
  64. else
  65. {
  66. return null;
  67. }
  68. default:
  69. // Something else is preventing access
  70. Debug.Fail("Unable to get the file mode information, status was" + status.ToString());
  71. return null;
  72. }
  73. // If either of these two flags are set, the file handle is synchronous (not overlapped)
  74. return (fileMode & (Interop.NtDll.FILE_SYNCHRONOUS_IO_ALERT | Interop.NtDll.FILE_SYNCHRONOUS_IO_NONALERT)) > 0;
  75. }
  76. private static void VerifyHandleIsSync(SafeFileHandle handle, int fileType, FileAccess access)
  77. {
  78. // As we can accurately check the handle type when we have access to NtQueryInformationFile we don't need to skip for
  79. // any particular file handle type.
  80. // If the handle was passed in without an explicit async setting, we already looked it up in GetDefaultIsAsync
  81. if (!handle.IsAsync.HasValue)
  82. return;
  83. // If we can't check the handle, just assume it is ok.
  84. if (!(IsHandleSynchronous(handle, ignoreInvalid: false) ?? true))
  85. throw new ArgumentException(SR.Arg_HandleNotSync, nameof(handle));
  86. }
  87. }
  88. }