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

[API Proposal]: Add API to check if process had administrator privileges #68770

Closed
Tracked by #79053
tmds opened this issue May 2, 2022 · 22 comments
Closed
Tracked by #79053

[API Proposal]: Add API to check if process had administrator privileges #68770

tmds opened this issue May 2, 2022 · 22 comments
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime
Milestone

Comments

@tmds
Copy link
Member

tmds commented May 2, 2022

Background and motivation

Some code is meant to be executed as an administrator. This API makes it easy to check if the process is considered to have administrator privileges.

API Proposal

namespace System;

static class Environment
{
    public static bool IsPrivilegedProcess { get; }
}

Comments

  • On Unix, this would check if geteuid() == 0. AdminHelpers has a IsProcessElevated method which may have the appropriate implementation for Windows also.

    public static unsafe bool IsProcessElevated()

  • When searching open-source code that implements this for Linux, about half of the cases implement this using getuid instead of geteuid, so they're likely getting it wrong. Having an API would make it easy to get right.

API Usage

if (Environment.IsPrivilegedProcess)
{
    Console.WriteLine("Trust me, I know what I'm doing.");
}

Alternative Designs

It could be on the Process class, but that class essentially represents an arbitrary process, and we do not plan to implement (nor do we see a need) to gather this info for a different process. Also, we already have Environment.Is64BitProcess

We considered various names -- the goal is to have something that doesn't appear to be specific to *nix or specific to Windows (using terms such as root, superuser, administrator, or elevated)

Risks

No response

@tmds tmds added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label May 2, 2022
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label May 2, 2022
@tmds
Copy link
Member Author

tmds commented May 2, 2022

cc @eerhardt

@ghost
Copy link

ghost commented May 2, 2022

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

Some code is meant to be executed as an administrator. This API makes it easy to check if the process is considered to have administrator privileges.

API Proposal

namespace System;

static class Environment
{
    public static bool IsProcessElevated { get; }
}

Comments

  • On Unix, this would check if geteuid() == 0. AdminHelpers has a IsProcessElevated method which may have the appropriate implementation for Windows also.

    public static unsafe bool IsProcessElevated()

  • When searching open-source code that implements this for Linux, about half of the cases implement this using getuid instead of geteuid.

API Usage

if (Environment.IsProcessElevated)
{
    Console.WriteLine("Trust me, I know what I'm doing.");
}

Alternative Designs

No response

Risks

No response

Author: tmds
Assignees: -
Labels:

api-suggestion, area-System.Runtime, untriaged

Milestone: -

@danmoseley
Copy link
Member

For context, we've pointed folks to Mono.Posix in the past but I think we have agreement that (like the API to change Unix file modes) this is fundamental enough it should be in the platform.

@danmoseley
Copy link
Member

danmoseley commented May 2, 2022

@tmds would "Elevated" mean anything to a non Windows developer? Conversely, would "IsSuperuser" (assuming that's the right term - not "RunningAsRoot" or "RunningAsSuperuser") mean something to a Windows developer?

edit: it's not so much a familiarity issue, as picking a word that makes clear what it does on each OS. It would be reasonable for someone to expect that "IsProcessElevated" would throw on *nix OS.

@danmoseley
Copy link
Member

danmoseley commented May 2, 2022

One other thought, I suspect that in Windows you can modify the elevation status of a thread (at least downwards). If this API was called on such a thread, we might have to decide whether we return the status of the thread or not. I don't know whether there's an analog on *nix.

@eerhardt
Copy link
Member

eerhardt commented May 2, 2022

I don't know whether there's an analog on *nix.

You can call https://www.man7.org/linux/man-pages/man2/seteuid.2.html, but that changes it for the whole process. I've never seen something that changes it for a single thread.

@tmds
Copy link
Member Author

tmds commented May 2, 2022

@tmds would "Elevated" mean anything to a non Windows developer? Conversely, would "IsSuperuser" (assuming that's the right term - not "RunningAsRoot" or "RunningAsSuperuser") mean something to a Windows developer?

Root/SuperUser are the appropriate Unix names.

How about: IsRunningAsAdministrator?

You can call https://www.man7.org/linux/man-pages/man2/seteuid.2.html, but that changes it for the whole process. I've never seen something that changes it for a single thread.

Yes, that is what POSIX prescribes.

The Linux kernel actually tracks it per thread. The user-space functions are implemented so the change applies process-wide to match POSIX behavior.

@danmoseley
Copy link
Member

@GrabYourPitchforks @bartonjs as security people, thoughts about naming here, or other feedback?

Throwing out another suggestion that's maybe more OS generic: bool HasElevatedPrivileges { get; } (although 'privileges' are a first class concept in the Windows security model, I think 'elevated privileges' is clearly distinct, and not a term specific to Winodws.

@bartonjs
Copy link
Member

bartonjs commented May 2, 2022

IsPrivilegedProcess, maybe?

NIST security glossary entry for 'privileged process': A computer process that is authorized (and, therefore, trusted) to perform security-relevant functions that ordinary processes are not authorized to perform.

So that'd be a process running as

  • Windows
    • NT AUTHORITY\LocalSystem
    • BUILTIN\Administrator
    • Any administrative account in an elevated context. (Or, if UAC is disabled "any administrative account")
  • UNIX
    • geteuid() == 0

@danmoseley
Copy link
Member

IsPrivilegedProcess sounds good to me. And being on Environment, not Process also seems right, as there's already Is64BitProcess there, and the Process type mostly is instance except for static methods to get Processes; plus we'd need to implement it for remote processes...

@danmoseley
Copy link
Member

@tmds as per usual practice I edited the top post with that suggestion. Feel free to edit/suggest others as it's your proposal.

Marking ready for review.

@danmoseley danmoseley added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner labels May 2, 2022
@danmoseley danmoseley added this to the 7.0.0 milestone Jun 28, 2022
@deeprobin
Copy link
Contributor

I like the proposed API shape.


On Windows it is technically not so easy to elevate a process at runtime via UAC (there are some possibilities via undocumented APIs). On Unix you could setuid to 0.

However, you can drop the privileges under Windows. This would be a good addition to this API in my opinion.

See Advapi32: AdjustTokenPrivileges
See Linux privilege dropping


namespace System;

static class Environment
{
    public static bool IsPrivilegedProcess { get; }

    public static bool DropPrivileges();
    // only supported on unix:
    public static bool RequestPrivileges();
}

@GrabYourPitchforks
Copy link
Member

Agree that "privileged" seems like the right name.

Nit: Windows actually has several definitions of privileged beyond the NIST glossary Jeremy linked to. For example, the DRM processing pipelines in Windows use "privileged" to refer to a process that can access protected media, even though these pipelines aren't running with SYSTEM-equivalent permissions.

But that's splitting hairs and I think we should stick with "privileged" as the friendly name and just doc what it means.

@terrajobst
Copy link
Member

terrajobst commented Jul 26, 2022

Video

  • Looks good as proposed
namespace System;

public partial class Environment
{
    public static bool IsPrivilegedProcess { get; }
}

@terrajobst terrajobst added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Jul 26, 2022
@deeprobin
Copy link
Contributor

An API implementation always needs test cases.

@tmds
How do you want to test the behavior here? To test this we need to elevate the Test Runner & then drop privilegies to test the other case.
However, I feel that this testing approach could often lead to errors.

@eerhardt
Copy link
Member

eerhardt commented Jul 26, 2022

For Unix, we have RemoteExecutor which has a RunAsSudo option. That will spawn a new process running as root, and inside that process Environment.IsPrivilegedProcess should return true.

@danmoseley
Copy link
Member

On Windows, tests should determine whether they are running privileged (I believe they all do in our automated runs); if not, test IsPrivilegedProcess is false, but if yes, test IsPrivilegedProcess is true then spawn a child process that is not privileged (may require a pinvoke) and test IsPrivilegedProcess is false.

For determining whether privileged the test could pretty much copy/paste the implementation of IsPrivilegedProcess. Or, as I have seen done in the past, see whether it can write (and then clean up) a randomly named file in the Windows directory..

@jeffhandley
Copy link
Member

@danmoseley FYI I'm moving this out to 8.0.0 since we weren't able to drive it to consensus for 7.0.0. I'd like to treat this as a high-value feature for 8.0.0 though.

@jeffhandley jeffhandley removed this from the 7.0.0 milestone Aug 8, 2022
@jeffhandley jeffhandley added this to the 8.0.0 milestone Aug 8, 2022
@iSazonov
Copy link
Contributor

Is any stopper to implement this?


To reset admin on Windows we can run subprocess with runas /trustlevel:0x20000. What could the test subprocess be?

@deeprobin
Copy link
Contributor

Is any stopper to implement this?

As far as I know, there is no stopper.

However, I have already started to implement this for Windows. Of course there are missing things like tests, documentation, ...
If you like you can continue to work on the basis of my branch deeprobin:issue-68770, because I won't get to it before December.

@tmds
Copy link
Member Author

tmds commented Nov 21, 2022

Implemented in #77355 by @iSazonov for .NET 8.0.

@tmds tmds closed this as completed Nov 21, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Dec 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime
Projects
None yet
Development

No branches or pull requests

9 participants