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 UnixFileMode APIs #69980

Merged
merged 42 commits into from
Jun 23, 2022
Merged

Implement UnixFileMode APIs #69980

merged 42 commits into from
Jun 23, 2022

Conversation

tmds
Copy link
Member

@tmds tmds commented May 30, 2022

Implements #67837.

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label May 30, 2022
@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@ghost
Copy link

ghost commented May 30, 2022

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

Issue Details

Implements #67837.

Author: tmds
Assignees: -
Labels:

area-System.IO, new-api-needs-documentation, community-contribution

Milestone: -

@tmds
Copy link
Member Author

tmds commented May 30, 2022

Currently this only has the Unix implementation, and there are no tests yet.

The implementation relies on some methods that are added in #60507. I'll rebase when that PR is merged.

Can you give me some pointers on what APIs I should use for this on Windows (to get/set the mode as WSL/NTFS metadata)?
And, if/what we'd like to do to have a umask on Windows?

cc @eerhardt @danmoseley @jozkee @stephentoub @adamsitnik

@danmoseley
Copy link
Member

danmoseley commented May 31, 2022

I looked into what it would mean to support this APi on Windows in the context of WSL2.

Per this Linux files are stored in NTFS using a file system plugin called VolFS. WSL2 can access Windows files using a plugin called DrvFS.

  1. DrvFS. Iff you enable the metadata option in WSL2 (eg with wsl.conf) then when writing files in the Windows filesystem (eg., in /mnt/c) from WSL, the access mask, uid and gid will be preserved by applying NTFS extended attributes (key value pairs associated with the file object, not the same as alternate data streams) whose names such as $LXMOD are documented. I'm not sure what use case they have in mind, because one could consider them an implementation detail. However, being documented, they can be read and written from Windows programs. More info

  2. VolFS. When storing Linux files in NTFS, the access mask, etc are clearly preserved for Linux to work at all. It's not clear whether this is done in the same way, or if it is, it's apparently not projected through the "\\wsl$" mount point by which you can access them from Windows. For example, \\wsl.localhost\Ubuntu-20.04\home\dan\.bash_history appears to have no extended attributes, and attempting to set some gives STATUS_NOT_IMPLEMENTED. The "actual" storage according to that document is in %LocalAppData%\lxss, but nothing is visible there (unless possibly it is only visible in a higher integrity level)3.
    Edit: I just realized this refers to WSL1. As I understand it, WSL2 is implemented as a true VM. So access via \\wsl$ is not backed by individual files in an NTFS volume so it is no surprise that EA’s aren’t present. I was testing with WSL2. I didn’t test WSL1.

To read extended attributes you can use NtQueryEaFile, but it's apparently not documented (only ZwQueryEaFile which drivers can use). I haven't found a documented Win32 that allows you to do it. @JeremyKuhne do you have insight here?

Although, even if it is documented, it's not clear to me that there is much value in wiring this up for Windows, because it apparently will only enable it for files in the Windows filesystem written by WSL distros and only then that have the non-default metadata config flag enabled. So perhaps this API should just throw on Windows.

BTW I found https://github.com/ladislav-zezula/FileTest a very helpful UI for experimenting with NtQueryEaFile.

@tmds
Copy link
Member Author

tmds commented May 31, 2022

Although, even if it is documented, it's not clear to me that there is much value in wiring this up for Windows, because it apparently will only enable it for files in the Windows filesystem written by WSL distros and only then that have the non-default metadata config flag enabled.

I also think the value is low.

If a user would like to have the unix permissions with WSL, they can set the mount options (metadata), and use Linux .NET binaries for working with the permissions.

So perhaps this API should just throw on Windows.

Proposing something:

For the APIs that create a file/directory, I think they shouldn't throw because that facilitates using them in cross-platform code.
For the API that set the mode, I think they should throw.
For the APIs that get the mode, I think we should return something. They could return 0777. We can leave out the w bit if they are readonly and return 0555.

@danmoseley
Copy link
Member

For the APIs that get the mode, I think we should return something. They could return 0777. We can leave out the w bit if they are readonly and return 0555.

That seems to be what chmod will do in WSL on a Windows file if 'metadata' flag is not used. But if it is set, it would now be a misleading result, as it should be interpreting the extended attributes.

@stephentoub
Copy link
Member

For the APIs that create a file/directory, I think they shouldn't throw because that facilitates using them in cross-platform code.

This is akin to someone asking that files have a specific permission level set and then silently ignoring it, e.g. "create this file so that only I can read it" and then it silently enables everyone to read it. That seems like a security incident waiting to happen.
cc: @GrabYourPitchforks

@tmds
Copy link
Member Author

tmds commented May 31, 2022

That seems to be what chmod will do in WSL on a Windows file if 'metadata' flag is not used. But if it is set, it would now be a misleading result, as it should be interpreting the extended attributes.

ok, let's avoid confusion and make it throw.

This is akin to someone asking that files have a specific permission level set and then silently ignoring it, e.g. "create this file so that only I can read it" and then it silently enables everyone to read it. That seems like a security incident waiting to happen.

The property/argument is named unixCreateMode to indicate it is only applied on Unix, and only when a new file is created.

If we're not going to ignore it on Windows, a user will need to conditionalize for Windows to make their code work xplat.

@stephentoub
Copy link
Member

If we're not going to ignore it on Windows, a user will need to conditionalize for Windows to make their code work xplat.

Presumably if they're trying to lock the file down, they'd need to do this anyway to use ACLs on Windows.

@tmds
Copy link
Member Author

tmds commented May 31, 2022

I like it when code that works for me on Linux doesn't throw PNSE on Windows.

Also, I think/hope a user setting unixCreateMode knows what it means.

And, not all use-cases that require unix permissions need a Windows ACL, like the tar extracting, for example.

I'll implement it to throw PNSE. We can revisit it later, if we want

@danmoseley
Copy link
Member

I agree with failing on Windows for now -- perhaps we will learn more from WSL team, or their support will evolve, which might make it more interesting.

@JeremyKuhne
Copy link
Member

To read extended attributes you can use NtQueryEaFile, but it's apparently not documented (only ZwQueryEaFile which drivers can use)

@danmoseley As long as the Zw* version is documented, the Nt* version is fair game.

if (actualMode != UserReadWrite)
{
throw new CryptographicException(SR.Format(SR.Cryptography_InvalidFilePermissions, stream.Name));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I've omitted the owner check that was in EnsureFilePermissions since it is implicit from only the owner having permissions and us being able to open the file.

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, big thanks for your contribution @tmds!

@@ -53,7 +54,9 @@ public abstract partial class TarEntry
// If the permissions weren't set at all, don't write the file's permissions.
if (permissions != 0)
{
Interop.CheckIo(Interop.Sys.FChMod(handle, permissions), destinationFileName);
#pragma warning disable CA1416 // Validate platform compatibility
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@buyaa-n @ViktorHofer the File.SetUnixFileMode method is marked as [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("windows")] and this particular C# file is compiled only for Unix:

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'Unix'">
<Compile Include="System\Formats\Tar\TarEntry.Unix.cs" />

Is it expected that the compiler produces warning?

[UnsupportedOSPlatform("windows")]
public static void SetUnixFileMode(SafeFileHandle fileHandle, UnixFileMode mode)
=> SetUnixFileModeCore(fileHandle, mode);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these methods throw PlatformNotSupportedException on Windows, I think that it would be good to include this information in the docs.

/// <exception cref="PlatformNotSupportedException">Not supported on Windows.</exception>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it need to be added when it is marked with the UnsupportedOSPlatformAttribute?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@buyaa-n what is the guidance for such scenarios?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idk what is the guidance for documenting, though I know that the attribute would showed up on the API doc like this:
image
https://docs.microsoft.com/en-us/dotnet/api/system.console.in?view=net-6.0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm only seeing 11 places that do this in the current codebase, but we throw PNSE in many, many other places. So I'm not sure this is strictly necessary.

@adamsitnik adamsitnik added this to the 7.0.0 milestone Jun 22, 2022
@@ -22,7 +22,9 @@ public static partial class ZipFileExtensions
// include the permissions, or was made on Windows.
if (permissions != 0)
{
Interop.CheckIo(Interop.Sys.FChMod(fs.SafeFileHandle, permissions), fs.Name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the Interop file be removed from this .csproj?

@@ -59,7 +59,6 @@
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.FChMod.cs" Link="Common\Interop\Unix\System.Native\Interop.FChMod.cs" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interop.FChMod.cs

Can the Interop.FChMod.cs file also be deleted from this .csproj?

@eerhardt
Copy link
Member

         Link="Common\Interop\Unix\System.Native\Interop.FChMod.cs" />

Also remove Interop.FChMod.cs from this .csproj


Refers to: src/libraries/System.Security.Cryptography/src/System.Security.Cryptography.csproj:587 in 168bdf5. [](commit_id = 168bdf5, deletion_comment = False)

Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! Thank you for all the great work here, @tmds!

My latest comments can be addressed in a follow up PR if we don't want to reset CI and want to merge today in order to make the preview 6 cutoff.

@carlossanlop
Copy link
Member

@eerhardt @adamsitnik we can merge this and then try to send the backport to prev6 via Tactics. We can request the build wizards to wait for this change before they generate a build.

cc @wtgodbe @vseanreesermsft

@carlossanlop carlossanlop merged commit ddc4f95 into dotnet:main Jun 23, 2022
adamsitnik added a commit to adamsitnik/runtime that referenced this pull request Jun 23, 2022
* Implement UnixFileMode APIs on Unix.

* Throw PNSE on Windows, add UnsupportedOSPlatform.

* Fix API compat issue.

* Borrow a few things from SafeFileHandle API PR to this compiles.

* Fix System.IO.FileSystem.AccessControl compilation.

* Add xml docs.

* Replace Interop.Sys.Permissions to System.IO.UnixFileMode.

* Throw PNSE immediately on Windows.

* Add ODE to xml docs of methods that accept a handle.

* Don't throw (PNSE) from FileSystemInfo.UnixFileMode getter on Windows.

* Minor style fix.

* Get rid of some casts.

Co-authored-by: Eric Erhardt <[email protected]>

* Add tests for creating a file/directory with UnixFileMode.

* Some CI envs don't have a umask exe, try retrieving via a shell builtin.

* Update expected test mode values.

* Fix OSX

* Fix Windows build.

* Add ArgumentException tests.

* Fix Windows build.

* Add get/set tests.

* Update test for Windows.

* Make setters target link instead of link target.

* Linux: fix SetUnixFileMode

* Fix OSX compilation.

* Try make all tests pass in CI.

* For link, operate on target permissions.

* Skip tests on Browser.

* Add tests for 'Get' that doesn't use a 'Set' first.

* Don't perform exist check for handles.

* Fix Get test for wasm.

* Review xml comments.

* Add comment to test.

* GetUnixFileMode for handle won't throw UnauthorizedAccessException.

* Apply suggestions from code review

Co-authored-by: Eric Erhardt <[email protected]>

* PR feedback.

* Update enum doc to say 'owner' instead of 'user'.

* Use UnixFileMode in library.

* Use UnixFileMode in library tests.

* Fix Windows build.

* Fix missing FileAccess when changing to FileStreamOptions API.

* PR feedback.

* Fix Argument_InvalidUnixCreateMode message.

Co-authored-by: Adam Sitnik <[email protected]>

Co-authored-by: Eric Erhardt <[email protected]>
Co-authored-by: Adam Sitnik <[email protected]>
ViktorHofer added a commit to ViktorHofer/runtime that referenced this pull request Jun 23, 2022
carlossanlop pushed a commit that referenced this pull request Jun 23, 2022
* Implement UnixFileMode APIs (#69980)

* Implement UnixFileMode APIs on Unix.

* Throw PNSE on Windows, add UnsupportedOSPlatform.

* Fix API compat issue.

* Borrow a few things from SafeFileHandle API PR to this compiles.

* Fix System.IO.FileSystem.AccessControl compilation.

* Add xml docs.

* Replace Interop.Sys.Permissions to System.IO.UnixFileMode.

* Throw PNSE immediately on Windows.

* Add ODE to xml docs of methods that accept a handle.

* Don't throw (PNSE) from FileSystemInfo.UnixFileMode getter on Windows.

* Minor style fix.

* Get rid of some casts.

Co-authored-by: Eric Erhardt <[email protected]>

* Add tests for creating a file/directory with UnixFileMode.

* Some CI envs don't have a umask exe, try retrieving via a shell builtin.

* Update expected test mode values.

* Fix OSX

* Fix Windows build.

* Add ArgumentException tests.

* Fix Windows build.

* Add get/set tests.

* Update test for Windows.

* Make setters target link instead of link target.

* Linux: fix SetUnixFileMode

* Fix OSX compilation.

* Try make all tests pass in CI.

* For link, operate on target permissions.

* Skip tests on Browser.

* Add tests for 'Get' that doesn't use a 'Set' first.

* Don't perform exist check for handles.

* Fix Get test for wasm.

* Review xml comments.

* Add comment to test.

* GetUnixFileMode for handle won't throw UnauthorizedAccessException.

* Apply suggestions from code review

Co-authored-by: Eric Erhardt <[email protected]>

* PR feedback.

* Update enum doc to say 'owner' instead of 'user'.

* Use UnixFileMode in library.

* Use UnixFileMode in library tests.

* Fix Windows build.

* Fix missing FileAccess when changing to FileStreamOptions API.

* PR feedback.

* Fix Argument_InvalidUnixCreateMode message.

Co-authored-by: Adam Sitnik <[email protected]>

Co-authored-by: Eric Erhardt <[email protected]>
Co-authored-by: Adam Sitnik <[email protected]>

* UnixFileMode: address remaining feedback. (#71188)

Co-authored-by: Tom Deseyn <[email protected]>
Co-authored-by: Eric Erhardt <[email protected]>
@carlossanlop
Copy link
Member

Hey @tmds, from this discussion #69980 (comment)

I can take care of replacing TarFileMode with UnixFileMode, since I am still actively working on Tar stuff. Just wanted to let you know so we don't step on each other toes.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.IO community-contribution Indicates that the PR has been added by a community member new-api-needs-documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.