Fix apphost/bundle creation failure on chmod-hostile filesystems#129342
Open
elinor-fung wants to merge 1 commit into
Open
Fix apphost/bundle creation failure on chmod-hostile filesystems#129342elinor-fung wants to merge 1 commit into
elinor-fung wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates Microsoft.NET.HostModel’s apphost and single-file bundle output writing logic to better handle Unix permission setting on filesystems where a separate chmod step can fail (e.g., EPERM on certain bind mounts). It centralizes “create executable at file creation time” and “enforce permissions when needed” behavior into HostModelUtils, and adds a Unix-only regression test for apphost overwrite behavior.
Changes:
- Add
HostModelUtils.CreateFileStreamForHost(usesFileStreamOptions.UnixCreateModeon Unix) andHostModelUtils.SetPermissionsForHost(conditional permission enforcement). - Update
HostWriterandBundlerto use the shared helpers instead of unconditional post-writeSetUnixFileMode. - Add a Unix-only test ensuring apphost overwrites a pre-existing non-executable destination with executable permissions; remove the net472-only Unix
chmodshim.
Show a summary per file
| File | Description |
|---|---|
| src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost/CreateAppHost.cs | Adds Unix-only regression coverage for overwriting an existing non-executable apphost destination. |
| src/installer/managed/Microsoft.NET.HostModel/Utils/UnixUtils.cs | Removes the net472-only Unix chmod shim (no longer needed with #if NET gating). |
| src/installer/managed/Microsoft.NET.HostModel/HostModelUtils.cs | Introduces shared helpers for “create with exec perms” and “conditional chmod enforcement” on Unix. |
| src/installer/managed/Microsoft.NET.HostModel/Bundle/Bundler.cs | Switches bundle output creation to the new helpers and centralizes permission enforcement. |
| src/installer/managed/Microsoft.NET.HostModel/AppHost/HostWriter.cs | Switches apphost destination stream creation to the new helper and uses shared permission enforcement. |
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 2
752cf33 to
5071bc7
Compare
CreateAppHost and single-file bundle generation failed inside rootless
podman devcontainers because File.SetUnixFileMode (chmod 755) returns
EPERM on bind-mounted Windows folders that appear root-owned to the
non-root container user, surfacing as:
System.UnauthorizedAccessException: Access to the path '.../apphost' is denied.
---> System.IO.IOException: Operation not permitted
at System.IO.File.SetUnixFileMode(...)
at Microsoft.NET.HostModel.AppHost.HostWriter.CreateAppHost(...)
Set the executable permissions when the file is created (via the open
syscall using FileStreamOptions.UnixCreateMode) instead of relying on a
separate chmod, which is not permitted on such filesystems. The
post-write chmod is now only attempted when the file is missing the
required permissions, so it is skipped on filesystems where the file was
already created executable and still enforces exact permissions (e.g.
under a restrictive umask) where chmod is supported.
Both HostWriter (apphost) and Bundler (single-file) now share the
CreateFileStreamForHost and SetPermissionsForHost helpers. The net472
libc chmod shim (UnixUtils.cs) is removed: net472 only runs on Windows in
the modern SDK, where Unix permissions do not apply.
Fixes dotnet#129040
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
5071bc7 to
4272452
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
dotnet buildand single-filedotnet publishfail inside rootless podman devcontainers becauseFile.SetUnixFileMode(chmod 755) returnsEPERMon bind-mounted Windows folders. Under rootless podman's default user-namespace mapping, the bind-mounted files appear root-owned to the non-root container user (e.g.vscode, uid 1000), so a non-owner cannotchmodthem — even though they are writable. This surfaces as:Fixes #129040.
cc @dotnet/appmodel @AaronRobinsonMSFT
Change
Set the executable permissions when the file is created (via the
opensyscall, usingFileStreamOptions.UnixCreateMode) instead of relying on a separatechmod, which is not permitted on such filesystems. The post-writechmodis now only attempted when the file is actually missing the required permissions, so it is:chmodis supported, enforcing exact0755(e.g. under a restrictiveumask, whereUnixCreateModealone would be masked).Both
HostWriter(apphost) andBundler(single-file bundle) are affected by the same bug and now share two helpers inHostModelUtils:CreateFileStreamForHost— creates the output stream, requesting0755at creation time on Unix.SetPermissionsForHost— best-effort enforcement that onlychmods when needed.In
HostWriter,SetPermissionsForHostruns inside the existing try/catch so that if the result is genuinely non-executable, the broken apphost is deleted and the error is surfaced rather than silently shipped.The net472-only
libcchmodP/Invoke shim (Utils/UnixUtils.cs) is removed — it was the only consumer ofFile.SetUnixFileModeon net472, and net472 only runs on Windows in the modern SDK, where Unix permissions do not apply.Testing
ExecutableImageOverwritesExistingNonExecutableFile(Unix-only) verifying that creating an apphost over a pre-existing non-executable file still yields-rwxr-xr-x.ExecutableImagetest continues to cover the executable-permission invariant.dotnet buildandBundler.GenerateBundlefail without this change and succeed with it. The conditional-chmod fallback was also confirmed on a normal Linux filesystem.Note
This pull request was authored with the assistance of GitHub Copilot.