KillOnParentExit rejects the Microsoft Store PowerShell execution alias with access denied
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 48/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- csharp
调研方向
Start with SafeProcessHandle.StartCore in src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs, the Windows startup path linked in the report. Reproduce the failure with the supplied program on Windows using the Store PowerShell alias, then compare it with the physical executable and the existing bounded replacement-job retry. Done when the alias starts with KillOnParentExit enabled, or the API reports and documents the unsupported case clearly.
由索引模型根据 Issue 内容生成。
描述
Description
ProcessStartInfo.KillOnParentExit=true causes Process.Start to reject the Microsoft Store PowerShell execution alias with native error 5 on .NET 11 GA. The same alias starts successfully when the option is false, including suspended creation. Applications that enable parent-exit cleanup therefore cannot launch this otherwise working executable.
Reproduction Steps
Install Microsoft Store PowerShell (tested package Microsoft.PowerShell 7.6.9.0 x64) with its execution alias enabled. Create a console project targeting net11.0 with implicit usings and nullable enabled, and replace Program.cs with:
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
if (!OperatingSystem.IsWindows()) return;
Console.WriteLine($"Runtime {Environment.Version}; {RuntimeInformation.OSDescription}; {RuntimeInformation.ProcessArchitecture}");
var executable = args.Length > 0 ? Path.GetFullPath(args[0]) : Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"Microsoft", "WindowsApps", "Microsoft.PowerShell_8wekyb3d8bbwe", "pwsh.exe");
using var launcher = Process.GetCurrentProcess();
using var outer = JoinJob(launcher);
using var inner = JoinJob(launcher);
foreach (var suspended in new[] { false, true })
foreach (var lifetime in new[] { false, true, false })
{
using var child = new Process { StartInfo = new ProcessStartInfo(executable)
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
InheritedHandles = [],
CreateNoWindow = true,
CreateNewProcessGroup = true,
KillOnParentExit = lifetime,
StartSuspended = suspended,
ArgumentList = { "--version" },
}};
try
{
child.Start();
if (suspended) child.SafeHandle.Resume();
child.StandardInput.Close();
var stdout = child.StandardOutput.ReadToEndAsync();
var stderr = child.StandardError.ReadToEndAsync();
await Task.WhenAll(child.WaitForExitAsync(), stdout, stderr).WaitAsync(TimeSpan.FromSeconds(10));
Console.WriteLine($"KillOnParentExit={lifetime}; StartSuspended={suspended}; Exit={child.ExitCode}; Output={(await stdout).Trim()}; Error={(await stderr).Trim()}");
}
catch (Win32Exception exception)
{
Console.WriteLine($"KillOnParentExit={lifetime}; StartSuspended={suspended}; NativeErrorCode={exception.NativeErrorCode}; {exception.Message}");
}
finally
{
try
{
if (!child.HasExited) child.Kill();
await child.WaitForExitAsync().WaitAsync(TimeSpan.FromSeconds(5));
}
catch (InvalidOperationException) { } // Start failed; there is no owned child.
}
}
static SafeFileHandle JoinJob(Process launcher)
{
// Plain, non-killing jobs; no resource limits, UI limits or breakaway changes.
var job = Native.CreateJobObjectW(0, null);
if (job.IsInvalid || !Native.AssignProcessToJobObject(job, launcher.SafeHandle))
{
var error = Marshal.GetLastPInvokeError();
job.Dispose();
throw new Win32Exception(error);
}
return job;
}
static class Native
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]
internal static extern SafeFileHandle CreateJobObjectW(nint attributes, string? name);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AssignProcessToJobObject(SafeFileHandle job, SafeProcessHandle process);
}
Run dotnet run with SDK 11.0.100. The default executable is the package-specific alias beneath the current user's local application data. An explicit executable path can instead be passed after --.
The program joins two ordinary, non-killing jobs before launching children. It neither changes pre-existing jobs nor requests breakaway. Every successfully created child is waited and cleaned up through its own process handle.
Expected behavior
The alias should start with parent-exit cleanup enabled, or the API should explicitly document and identify this unsupported executable type.
Actual behavior
Both StartSuspended=false and StartSuspended=true produce this false/true/false sequence:
KillOnParentExit=False: Exit=0; Output=PowerShell 7.6.9
KillOnParentExit=True: Win32Exception; NativeErrorCode=5; Access is denied.
KillOnParentExit=False: Exit=0; Output=PowerShell 7.6.9
The exception comes from SafeProcessHandle.StartCore during Process.Start. The runtime's bounded replacement-job retry does not make the alias start.
With the same redirected streams, restricted inheritance, process group, and nested jobs, the physical C:\Program Files\PowerShell\7\pwsh.exe (also PowerShell 7.6.9) succeeds for every combination. dotnet.exe --version and cmd.exe /d /c echo probe-ok also succeed with and without the option. This report claims the tested alias failure; it does not infer a general Windows job limitation.
Regression?
Not established. This is distinct from #134990: ordinary executable launches after containment changes now work in the GA runtime.
Known Workarounds
Launching the physical PowerShell executable succeeds. Disabling KillOnParentExit lets the alias start but removes the requested lifetime guarantee.
Configuration
- SDK: 11.0.100.
- Runtime: 11.0.0, commit
297acf930f. - OS:
Microsoft Windows 10.0.26300, x64. - Microsoft Store package:
Microsoft.PowerShell 7.6.9.0, x64. - PowerShell output:
PowerShell 7.6.9.
Other information
Checked open and closed runtime issues for KillOnParentExit with alias, package, WindowsApps, and PowerShell terms. The Windows startup implementation on v11.0.0 and main at 719ca2546bd31a54244731185c55c8fc208204bf still supplies the lifetime job through the extended startup attributes. No alias-specific fix was found in main or the .NET 11 release notes.
Discovered while investigating ModularPipelines #6302. Please support this alias launch with KillOnParentExit, or document its restriction with an actionable error.
- 主要语言
- C#
- 星标
- 18.4k
- 派生
- 5.8k
- 平均合并
- 2 天 19 小时
- 30 天内合并 PR
- 590
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
dotnet/runtime 的其他 Issue
-
area-Setup untriaged
难度 2/5 1-3 小时 新手友好度 76/100
dotnet/runtime#137376 · 1 条评论 ·
维护者通常 1 天内回复
-
area-System.Memory untriaged
难度 2/5 1-3 小时 新手友好度 75/100
dotnet/runtime#137334 · 4 条评论 ·
维护者通常 1 天内回复
-
ImmutableSortedSet<T>.Builder: enumerating through IEnumerable<T> doesn't throw on modification and can return wrong items可能已有人在做 @aw0lid 于 3 天前认领。 未关闭area-System.Collections
难度 2/5 1-3 小时 新手友好度 78/100
dotnet/runtime#137167 · 1 条评论 ·
维护者通常 1 天内回复
-
DbTransaction.SupportsSavepoints docs say Release/ReleaseAsync are expected to throw, but they are no-ops by design可能已有人在做 @alaricd 于 7 天前认领。 未关闭area-System.Transactions untriaged
难度 2/5 1-3 小时 新手友好度 72/100
dotnet/runtime#137040 · 1 条评论 ·
维护者通常 1 天内回复
-
FileSystemGlobbing: Matcher throws ArgumentOutOfRangeException when the rootDir is the same value as the file可能已有人在做 @makazeu 于 7 天前认领。 未关闭area-Extensions-FileSystem
难度 2/5 1-3 小时 新手友好度 78/100
dotnet/runtime#136989 · 1 条评论 ·
维护者通常 1 天内回复
相似的 Issue
-
bug emitter:client:csharp
难度 2/5 1-3 小时 新手友好度 84/100
microsoft/typespec#12572 · 1 条评论 · 1 个 reaction ·
维护者通常 1 天内回复
-
needs-area-label
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 2 天内回复
-
AWS Lambda: KeyNotFoundException drops HTTP-triggered transactions when allowAllHeaders is disabled未关闭bug
难度 2/5 1-3 小时 新手友好度 70/100
newrelic/newrelic-dotnet-agent#3949 · 1 条评论 ·
维护者通常 1 天内回复
-
area-networking
难度 2/5 1-3 小时 新手友好度 78/100
dotnet/aspnetcore#70545 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 87/100
维护者通常 1 天内回复