Skip to content

Unify SECURITY_ATTRIBUTES code from FileSystemAclExtensions and SafeFileHandle #64017

@carlossanlop

Description

@carlossanlop

Follow up of the PR comment where this was suggested: #61297 (comment) (but wait for that PR to be merged).

Unify these two methods:

fixed (byte* pSecurityDescriptor = security.GetSecurityDescriptorBinaryForm())
{
var secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES
{
nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES),
bInheritHandle = ((share & FileShare.Inheritable) != 0) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
lpSecurityDescriptor = (IntPtr)pSecurityDescriptor
};
using (DisableMediaInsertionPrompt.Create())
{
handle = Interop.Kernel32.CreateFile(fullPath, (int)rights, share, &secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
ValidateFileHandle(handle, fullPath);
}
}

private static unsafe SafeFileHandle CreateFile(string fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
{
Interop.Kernel32.SECURITY_ATTRIBUTES secAttrs = default;
if ((share & FileShare.Inheritable) != 0)
{
secAttrs = new Interop.Kernel32.SECURITY_ATTRIBUTES
{
nLength = (uint)sizeof(Interop.Kernel32.SECURITY_ATTRIBUTES),
bInheritHandle = Interop.BOOL.TRUE
};
}
int fAccess =
((access & FileAccess.Read) == FileAccess.Read ? Interop.Kernel32.GenericOperations.GENERIC_READ : 0) |
((access & FileAccess.Write) == FileAccess.Write ? Interop.Kernel32.GenericOperations.GENERIC_WRITE : 0);
// Our Inheritable bit was stolen from Windows, but should be set in
// the security attributes class. Don't leave this bit set.
share &= ~FileShare.Inheritable;
// Must use a valid Win32 constant here...
if (mode == FileMode.Append)
{
mode = FileMode.OpenOrCreate;
}
int flagsAndAttributes = (int)options;
// For mitigating local elevation of privilege attack through named pipes
// make sure we always call CreateFile with SECURITY_ANONYMOUS so that the
// named pipe server can't impersonate a high privileged client security context
// (note that this is the effective default on CreateFile2)
flagsAndAttributes |= (Interop.Kernel32.SecurityOptions.SECURITY_SQOS_PRESENT | Interop.Kernel32.SecurityOptions.SECURITY_ANONYMOUS);
SafeFileHandle fileHandle = Interop.Kernel32.CreateFile(fullPath, fAccess, share, &secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
if (fileHandle.IsInvalid)
{
// Return a meaningful exception with the full path.
// NT5 oddity - when trying to open "C:\" as a Win32FileStream,
// we usually get ERROR_PATH_NOT_FOUND from the OS. We should
// probably be consistent w/ every other directory.
int errorCode = Marshal.GetLastPInvokeError();
if (errorCode == Interop.Errors.ERROR_PATH_NOT_FOUND && fullPath!.Length == PathInternal.GetRootLength(fullPath))
{
errorCode = Interop.Errors.ERROR_ACCESS_DENIED;
}
throw Win32Marshal.GetExceptionForWin32Error(errorCode, fullPath);
}

Since they are both very similar.

cc @adamsitnik @jozkee

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions