Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Environment.IsPrivilegedProcess #77355

Merged
merged 8 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal static partial class Advapi32
[LibraryImport(Interop.Libraries.Advapi32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static unsafe partial bool GetTokenInformation(
SafeAccessTokenHandle TokenHandle,
SafeTokenHandle TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
void* TokenInformation,
uint TokenInformationLength,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

internal static partial class Interop
{
internal static partial class Advapi32
{
[Flags]
internal enum TOKEN_ACCESS_LEVELS : uint
{
AssignPrimary = 0x00000001,
Duplicate = 0x00000002,
Impersonate = 0x00000004,
Query = 0x00000008,
QuerySource = 0x00000010,
AdjustPrivileges = 0x00000020,
AdjustGroups = 0x00000040,
AdjustDefault = 0x00000080,
AdjustSessionId = 0x00000100,

Read = 0x00020000 | Query,

Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,

AllAccess = 0x000F0000 |
AssignPrimary |
Duplicate |
Impersonate |
Query |
QuerySource |
AdjustPrivileges |
AdjustGroups |
AdjustDefault |
AdjustSessionId,

MaximumAllowed = 0x02000000
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ public static unsafe bool IsProcessElevated()
return(userId == 0);
}

SafeAccessTokenHandle token;
if (!Interop.Advapi32.OpenProcessToken(Interop.Kernel32.GetCurrentProcess(), TokenAccessLevels.Read, out token))
SafeTokenHandle token;
if (!Interop.Advapi32.OpenProcessToken(Interop.Kernel32.GetCurrentProcess(), (int)TokenAccessLevels.Read, out token))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "Open process token failed");
}
Expand Down
6 changes: 4 additions & 2 deletions src/libraries/Common/tests/TestUtilities/TestUtilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
Link="Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs" />
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.RtlGetVersion.cs"
Link="Common\Interop\Windows\NtDll\Interop.RtlGetVersion.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.OpenProcessToken_SafeAccessTokenHandle.cs"
Link="Common\Interop\Windows\Advapi32\Interop.OpenProcessToken_SafeAccessTokenHandle.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.OpenProcessToken.cs"
Link="Common\Interop\Windows\Advapi32\Interop.OpenProcessToken.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs"
Link="Common\Interop\Windows\Interop.Libraries.cs" />
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.CloseHandle.cs"
Expand All @@ -79,6 +79,8 @@
<Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs"
Link="Common\Interop\Windows\Interop.BOOL.cs" />

<Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeTokenHandle.cs"
Link="Common\Microsoft\Win32\SafeHandles\SafeTokenHandle.cs"/>
<Compile Include="$(CommonPath)System\IO\PathInternal.Windows.cs"
Link="Common\System\IO\PathInternal.Windows.cs" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1414,9 +1414,15 @@
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.EventWriteTransfer.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.EventWriteTransfer.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.GetTokenInformation_void.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.GetTokenInformation_void.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.LookupAccountNameW.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.LookupAccountNameW.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.OpenProcessToken.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.OpenProcessToken.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.RegCloseKey.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.RegCloseKey.cs</Link>
</Compile>
Expand Down Expand Up @@ -1450,6 +1456,15 @@
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.RegSetValueEx.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.RegSetValueEx.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.TOKEN_ACCESS_LEVELS.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.TOKEN_ACCESS_LEVELS.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.TOKEN_ELEVATION.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.TOKEN_ELEVATION.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Advapi32\Interop.TOKEN_INFORMATION_CLASS.cs">
<Link>Common\Interop\Windows\Advapi32\Interop.TOKEN_INFORMATION_CLASS.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\BCrypt\Interop.BCryptGenRandom.cs">
<Link>Common\Interop\Windows\BCrypt\Interop.BCryptGenRandom.cs</Link>
</Compile>
Expand Down Expand Up @@ -1882,6 +1897,9 @@
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetModuleHandle.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GetModuleHandle.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Microsoft\Win32\SafeHandles\SafeTokenHandle.cs">
<Link>Common\Microsoft\Win32\SafeHandles\SafeTokenHandle.cs</Link>
</Compile>
<Compile Include="$(CommonPath)System\IO\FileSystem.Attributes.Windows.cs">
<Link>Common\System\IO\FileSystem.Attributes.Windows.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public static string MachineName

public static string UserName => Interop.Sys.GetUserNameFromPasswd(Interop.Sys.GetEUid());

private static bool IsAdminProcess()
{
uint userId = Interop.Sys.GetEUid();
return (userId == 0);
}
stephentoub marked this conversation as resolved.
Show resolved Hide resolved

[MethodImplAttribute(MethodImplOptions.NoInlining)] // Avoid inlining PInvoke frame into the hot path
private static int GetProcessId() => Interop.Sys.GetPid();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -83,6 +84,30 @@ private static string ExpandEnvironmentVariablesCore(string name)
return builder.ToString();
}

private static unsafe bool IsAdminProcess()
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
{
SafeTokenHandle token;
if (Interop.Advapi32.OpenProcessToken(Interop.Kernel32.GetCurrentProcess(), (int)Interop.Advapi32.TOKEN_ACCESS_LEVELS.Read, out token))
{
using (token)
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
{
Interop.Advapi32.TOKEN_ELEVATION elevation = default;

if (Interop.Advapi32.GetTokenInformation(
token,
Interop.Advapi32.TOKEN_INFORMATION_CLASS.TokenElevation,
&elevation,
(uint)sizeof(Interop.Advapi32.TOKEN_ELEVATION),
out _))
{
return elevation.TokenIsElevated != Interop.BOOL.FALSE;
}
}
}

throw Win32Marshal.GetExceptionForLastWin32Error();
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
}

private static bool Is64BitOperatingSystemWhen32BitProcess =>
Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out bool isWow64) && isWow64;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ public static partial class Environment
/// </summary>
internal static bool IsSingleProcessor => ProcessorCount == 1;

/// <summary>
/// Gets whether the current process is authorized to perform security-relevant functions.
/// </summary>
public static bool IsPrivilegedProcess { get; } = IsAdminProcess();
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
stephentoub marked this conversation as resolved.
Show resolved Hide resolved

// Unconditionally return false since .NET Core does not support object finalization during shutdown.
public static bool HasShutdownStarted => false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<Compile Include="System\IO\Path.IsPathFullyQualified.cs" />
<Compile Include="System\BitConverterArray.cs" />
<Compile Include="System\BitConverterBase.cs" />
<Compile Include="System\Environment.IsPrivilegedProcess.cs" />
<Compile Include="System\Environment.UserDomainName.cs" />
<Compile Include="System\Environment.UserName.cs" />
<Compile Include="System\Diagnostics\Stopwatch.cs" />
Expand Down Expand Up @@ -82,7 +83,7 @@

<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.GetHostName.cs" Condition="'$(TargetPlatformIdentifier)' == 'Unix' or '$(TargetPlatformIdentifier)' == 'Browser'" Link="Common\Interop\Unix\System.Native\Interop.GetHostName.cs" />
<Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs" Link="Common\Interop\Unix\Interop.Libraries.cs" />
<Compile Include="$(CommonTestPath)System\Diagnostics\DebuggerAttributes.cs" Link="Common\System\Diagnostics\DebuggerAttributes.cs" />
<Compile Include="$(CommonTestPath)System\Diagnostics\DebuggerAttributes.cs" Link="Common\System\Diagnostics\DebuggerAttributes.cs" />
<Compile Include="$(CommonTestPath)System\IO\PathFeatures.cs" Link="Common\System\IO\PathFeatures.cs" />
<Compile Include="$(CommonTestPath)System\ShouldNotBeInvokedException.cs" Link="Common\System\ShouldNotBeInvokedException.cs" />
<Compile Include="$(CommonTestPath)System\Security\Cryptography\ByteUtils.cs" Link="Common\System\Security\Cryptography\ByteUtils.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;
using Xunit;

namespace System.Tests
{
public class Environment_IsPrivilegedProcess
{
[Fact]
danmoseley marked this conversation as resolved.
Show resolved Hide resolved
public void TestIsPrivilegedProcess()
{
if (AdminHelpers.IsProcessElevated())
{
Assert.True(Environment.IsPrivilegedProcess);
}
else
{
Assert.False(Environment.IsPrivilegedProcess);
}
stephentoub marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
1 change: 1 addition & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,7 @@ public static partial class Environment
public static bool HasShutdownStarted { get { throw null; } }
public static bool Is64BitOperatingSystem { get { throw null; } }
public static bool Is64BitProcess { get { throw null; } }
public static bool IsPrivilegedProcess { get { throw null; } }
public static string MachineName { get { throw null; } }
public static string NewLine { get { throw null; } }
public static System.OperatingSystem OSVersion { get { throw null; } }
Expand Down