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

Crash when trying to run non-elevated from an elevate process #37129

Closed
enricogior opened this issue May 28, 2020 · 19 comments
Closed

Crash when trying to run non-elevated from an elevate process #37129

enricogior opened this issue May 28, 2020 · 19 comments

Comments

@enricogior
Copy link

Description

PowerToys needs to start a .NET Core application with non-elevated privileges from an elevated process.

We tried two different approaches, they both resulted in this crash report:

image

Application: PowerLauncher.exe
CoreCLR Version: 4.700.20.20201
.NET Core Version: 3.1.4
Description: The process was terminated due to an unhandled exception.
Exception Info: System.TypeInitializationException: The type initializer for 'System.Windows.Threading.Dispatcher' threw an exception.
 ---> System.ComponentModel.Win32Exception (5): Access is denied.
   at System.Diagnostics.ProcessManager.OpenProcess(Int32 processId, Int32 access, Boolean throwIfExited)
   at System.Diagnostics.NtProcessManager.GetModules(Int32 processId, Boolean firstModuleOnly)
   at System.Diagnostics.Process.get_Modules()
   at System.Windows.WpfDllVerifier.VerifyWpfDllSet(String[] additionalDlls)
   at System.Windows.Threading.Dispatcher..cctor()
   --- End of inner exception stack trace ---
   at System.Windows.Threading.Dispatcher.get_CurrentDispatcher()
   at System.Windows.Threading.DispatcherObject..ctor()
   at System.Windows.Application..ctor()
   at PowerLauncher.App..ctor() in C:\github\microsoft\PowerToys\src\modules\launcher\PowerLauncher\App.xaml.cs:line 33
   at PowerLauncher.App.Main() in C:\github\microsoft\PowerToys\src\modules\launcher\PowerLauncher\App.xaml.cs:line 44

First approch: start the application as suggested in this Raymond Chen's article
https://devblogs.microsoft.com/oldnewthing/20190425-00/?p=102443
It works for Win32 apps and for .Net Framework apps, it causes the crash when tested with the two .NET Core apps we have in PowerToys.

Second approach: use an intermediate process and drop the elevation in that process before starting the .NET Core app. It works when using SDDL_ML_MEDIUM but crashes when using SDDL_ML_MEDIUM_PLUS, in our scenario SDDL_ML_MEDIUM causes other issues so we can't use it.
https://github.com/microsoft/PowerToys/blob/e75a74565b8f7eb208af52dbb10632f943b66d21/src/common/common.cpp#L396-L421

Configuration

.NET Core 3.1.4
Windows 10 1909
x64

Regression?

Other information

I can provide a branch with the changes that cause the crash, if needed.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Diagnostics.Process untriaged New issue has not been triaged by the area owner labels May 28, 2020
@ghost
Copy link

ghost commented May 28, 2020

Tagging subscribers to this area: @eiriktsarpalis
Notify danmosemsft if you want to be subscribed.

@danmoseley
Copy link
Member

The .NET Framework and .NET Core implementations of Process.get_Modules() seem the same -- ending up calling OpenProcess(Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION | Interop.Advapi32.ProcessOptions.PROCESS_VM_READ, inherit: false, processId);

I wonder if dotnet/coreclr#28019 is related? But that fix was present beginning in 3.1.3 (I verified) and the above is 3.1.4

@stephentoub anything occur to you?

@danmoseley
Copy link
Member

@enricogior is it possible to try some other .NET Core versions? Specifically 3.1.2 or earlier. Any 5.0 preview might be an interesting datapoint as well.

@danmoseley
Copy link
Member

Or perhaps @ericstj has a theory.

@jkotas
Copy link
Member

jkotas commented May 29, 2020

The .NET Framework and .NET Core implementations of Process.get_Modules() seem the same

WpfDllVerifier that is calling Process.Modules is new in .NET Core.

It works for Win32 apps and for .Net Framework apps

Does it work for .Net Framework app that just calls foreach (ProcessModule procModule in Process.GetCurrentProcess().Modules) { Console.WriteLine(procModule); } ?

@jkotas
Copy link
Member

jkotas commented May 29, 2020

The most likely explanation for this behavior is that the techniques to launch non-elevated process from elevated one strip the rights for the process to inspect itself. An experiment with an app that calls ProcessModule procModule in Process.GetCurrentProcess().Modules would confirm or deny it.

@danmoseley
Copy link
Member

Thank you! I did not know that the Process.Modules call was new.

@enricogior
Copy link
Author

@danmosemsft

is it possible to try some other .NET Core versions? Specifically 3.1.2 or earlier. Any 5.0 preview might be an interesting datapoint as well.

I tried 3.1.0 and got the same problem.
I wanted to try 5.0 but after installing the SDK, VS 2019 16.6 doesn't show it as available option:

C:\Users\enrico>dotnet --list-sdks
3.1.201 [C:\Program Files\dotnet\sdk]
3.1.300 [C:\Program Files\dotnet\sdk]
5.0.100-preview.4.20258.7 [C:\Program Files\dotnet\sdk]

image

Is there any other step required?

@enricogior
Copy link
Author

@jkotas
when dropping the privileges using SDDL_ML_MEDIUM, the app starts without problems, but it doesn't have enough privileges for what we need. The crash happens when we use SDDL_ML_MEDIUM_PLUS that in theory should have higher privileges.

@danmoseley
Copy link
Member

@enricogior can you please try the experiment @jkotas suggested above - create a.NET Framework console app and paste in Process.GetCurrentProcess().Modules;. Then try launching that with your launcher . We are guessing it will have the same issue.

@ericstj
Copy link
Member

ericstj commented May 29, 2020

Agree with @jkotas assessment. In @oldnewthing's blog you see the technique you are using is copying permissions from some other process. You need to make sure the process you choose to copy has all the permissions that match an unelevated process. Likely Explorer doesn't have SeDebugPrivilege.

@enricogior
Copy link
Author

@danmosemsft
I will test it with a .NET Framework.

@ericstj
still I don't understand why it doesn't crash when using SDDL_ML_MEDIUM, but it crashes when using SDDL_ML_MEDIUM_PLUS.

@ericstj
Copy link
Member

ericstj commented Jun 1, 2020

I didn't dig deeper into your second method. It seems SDDL_ML_MEDIUM maps to SID S-1-16-8192 and SDDL_ML_MEDIUM_PLUS maps to S-1-16-8448. I couldn't find any documentation around what privilege these SIDs have nor if one has necessarily more than the other. I bet there is a tool that can read the default privilege for these SIDs like whoami does for a user, but I couldn't find it. You can examine the different privilege that Windows gives these using ProcessExplorer.

As an aside, I noticed a possible optimization here that could avoid this codepath in Process calling OpenProcess. It looks like GetCurrentProcess is recommended over OpenProcess when opening the current process, and as far as I can tell GetCurrentProcess wouldn't require SeDebugPrivilege which might avoid this issue. Now that might avoid this exception, but it would still be problematic since if your child process was expecting to do anything else that required SeDebugPrivilege it would fail. I don't think that's a great fix for you since it would still cause your child processes to fail if they tried to use this API (and wouldn't normally, when launched unelevated).

@danmoseley
Copy link
Member

danmoseley commented Jun 1, 2020

Perhaps the way forward @enricogior is to create a little Hello World style repro using pure native Win32 that simply calls OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, currentPid);. We're guessing that will fail too, at which point this becomes a question for Win32 security model experts .

Maybe we could work around this in our code, but that might change product behavior, and more importantly doesn't help most of your customers since they want to launch other apps and older versions of .NET Core which may still hit this

@enricogior
Copy link
Author

@ericstj @danmosemsft
sounds good, I'll get back to you with the results.
Thanks.

@adamsitnik adamsitnik added this to the Future milestone Jun 25, 2020
@adamsitnik
Copy link
Member

I'll get back to you with the results.

@enricogior any progress on this?

@enricogior
Copy link
Author

Hi @adamsitnik
we have been busy preparing the 0.19 release, hopefully next week I'll have some time to do the testing.

@adamsitnik
Copy link
Member

The call to WpfDllVerifier has been removed in WPF .NET 5 RC2: dotnet/wpf#3436

The issue should be fixed. @enricogior please feel free to reopen if it does not work for .NET 5 WPF for you.

@adamsitnik adamsitnik modified the milestones: Future, 5.0.0 Sep 28, 2020
@enricogior
Copy link
Author

@adamsitnik
thank you for the info.

@ghost ghost locked as resolved and limited conversation to collaborators Dec 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants