docker / for-win

Bug reports for Docker Desktop for Windows
https://www.docker.com/products/docker#/windows
1.86k stars 289 forks source link

Ownership of files set via bind mount is set to user who accesses the file first #12742

Closed paslandau closed 1 year ago

paslandau commented 2 years ago

After updating to Docker Desktop Version: 4.8.2, files shared between the host system (Windows 10) and a docker container are no longer owned by root but the ownership is set according to the user who accesses the file the first time. In addition, previously "it didn't matter" that root was the owner - all files in the shared folder had -rwxrwxrwx permissions (i.e. no restrictions at all), now it is -rwxr-xr-x. FYI: The ownership settings on the Windows host system do not matter. The "expected" behavior is also mentioned as such in the docs:

Docker Desktop sets permissions to read/write/execute for users, groups and others 0777 or a+rwx. This is not configurable. See Permissions errors on data directories for shared volumes.

as well as in the troubleshooting guide:

Permissions errors on data directories for shared volumes When sharing files from Windows, Docker Desktop sets permissions on shared volumes to a default value of 0777 (read, write, execute permissions for user and for group).

The default permissions on shared volumes are not configurable. If you are working with applications that require permissions different from the shared volume defaults at container runtime, you need to either use non-host-mounted volumes or find a way to make the applications work with the default file permissions.

See also, Can I change permissions on shared volumes for container-specific deployment requirements? in the FAQs.

Concrete example:

Files on the Windows 10 host system

/directory
  - file1
  - file2

start a docker container in /directory and share /directory with the container via bind mount /directory:/codebase

docker run --rm --name test -itd -v /$(pwd):/codebase busybox

Files in the docker container

/codebase
  - file1
  - file2

Now, depending on "which user" accesses a file for the very first time in the container, it becomes the owner of that file. The access can be a simple ls (so "access" might not be the correct term to use here, but I'm lacking a better one).

E.g. running

docker exec --user 999 test ls -l codebase/file2

will set the owner of file2 in the container to 999.

Running (as root)

docker exec test ls -l codebase/file2

will still show 999 as owner.

Running (as root)

docker exec test ls -l codebase/file1

will show root as owner for file1

See "Steps to reproduce the behavior" at the end for a concrete reproduction example.


Actual behavior

Ownership of files on a bind mount is set depeding on first access

Expected behavior

Ownership of files should be root by default (as previously)

Information

$ docker version
Client:
 Cloud integration: v1.0.24
 Version:           20.10.14
 API version:       1.41
 Go version:        go1.16.15
 Git commit:        a224086
 Built:             Thu Mar 24 01:53:11 2022
 OS/Arch:           windows/amd64
 Context:           default
 Experimental:      true

Server: Docker Desktop 4.8.2 (79419)
 Engine:
  Version:          20.10.14
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       87a90dc
  Built:            Thu Mar 24 01:46:14 2022
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.5.11
  GitCommit:        3df54a852345ae127d1fa3092b95168e4a88e2f8
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Output of & "C:\Program Files\Docker\Docker\resources\com.docker.diagnose.exe" check

$ "C:\Program Files\Docker\Docker\resources\com.docker.diagnose.exe" check
time="2022-05-23T16:44:33+02:00" level=info msg="unable to query WSL distros: exit status 0xffffffff"
Starting diagnostics

[PASS] DD0027: is there available disk space on the host?
[SKIP] DD0028: is there available VM disk space?
[PASS] DD0031: does the Docker API work?
[PASS] DD0004: is the Docker engine running?
[PASS] DD0011: are the LinuxKit services running?
[PASS] DD0016: is the LinuxKit VM running?
[PASS] DD0001: is the application running?
[PASS] DD0018: does the host support virtualization?
[PASS] DD0002: does the bootloader have virtualization enabled?
[PASS] DD0020: is the Hyper-V Windows Feature enabled?
[PASS] DD0017: can a VM be started?
[PASS] DD0015: are the binary symlinks installed?
[PASS] DD0003: is the Docker CLI working?
[PASS] DD0013: is the $PATH ok?
[PASS] DD0005: is the user in the docker-users group?
[PASS] DD0007: is the backend responding?
[PASS] DD0014: are the backend processes running?
[PASS] DD0008: is the native API responding?
[PASS] DD0009: is the vpnkit API responding?
[PASS] DD0010: is the Docker API proxy responding?
[PASS] DD0006: is the Docker Desktop Service responding?
[PASS] DD0012: is the VM networking working?
[PASS] DD0032: do Docker networks overlap with host IPs?
[SKIP] DD0030: is the image access management authorized?
[PASS] DD0033: does the host have Internet access?
No fatal errors detected.

Steps to reproduce the behavior

#!/usr/bin/env bash
set -x

rm -rf file*
echo "Creating test files"
echo "file1" > file1
echo "file2" > file2

echo "Starting docker container with bind mount to the current directory"
docker run --rm --name test -itd -v /$(pwd):/codebase busybox

echo "Checking owner for 'file1' as user with id 1337"
docker exec --user 1337 test ls -l codebase/file1

echo "Checking owner for 'file2' as user with id 999"
docker exec --user 999 test ls -l codebase/file2

echo "Stopping docker container"
docker stop test

echo "Starting docker container with bind mount to the current directory (again)"
docker run --rm --name test -itd -v /$(pwd):/codebase busybox

echo "Checking owner for 'file1' as user with id 42"
docker exec --user 42 test ls -l codebase/file1

echo "Checking owner for 'file2' witho no specific user (will be root)"
docker exec test ls -l codebase/file2

Output

+ rm -rf file1 file2
+ echo 'Creating test files'
Creating test files
+ echo file1
+ echo file2
+ echo 'Starting docker container with bind mount to the current directory'
Starting docker container with bind mount to the current directory
++ pwd
+ docker run --rm --name test -itd -v //c/codebase/foo/basr:/codebase busybox
a5ac823cf5f8f7c1a58fbbae88c9fd953942a66d7be7380641f77556f2006e7d
+ echo 'Checking owner for '\''file1'\'' as user with id 1337'
Checking owner for 'file1' as user with id 1337
+ docker exec --user 1337 test ls -l codebase/file1
-rwxr-xr-x    1 1337     root             6 May 23 14:24 codebase/file1
+ echo 'Checking owner for '\''file2'\'' as user with id 999'
Checking owner for 'file2' as user with id 999
+ docker exec --user 999 test ls -l codebase/file2
-rwxr-xr-x    1 999      root             6 May 23 14:24 codebase/file2
+ echo 'Stopping docker container'
Stopping docker container
+ docker stop test
test
+ echo 'Starting docker container with bind mount to the current directory (again)'
Starting docker container with bind mount to the current directory (again)
++ pwd
+ docker run --rm --name test -itd -v //c/codebase/foo/basr:/codebase busybox
301eb679519f778ef9dbb7ac9b1bfafbb33f2eea1831d6cccb1f3ec21a53fe1f
+ echo 'Checking owner for '\''file1'\'' as user with id 42'
Checking owner for 'file1' as user with id 42
+ docker exec --user 42 test ls -l codebase/file1
-rwxr-xr-x    1 42       root             6 May 23 14:24 codebase/file1
+ echo 'Checking owner for '\''file2'\'' witho no specific user (will be root)'
Checking owner for 'file2' witho no specific user (will be root)
+ docker exec test ls -l codebase/file2
-rwxr-xr-x    1 root     root             6 May 23 14:24 codebase/file2

Possible related issues

djs55 commented 2 years ago

@paslandau Thanks for the report.

After updating to Docker Desktop Version: 4.8.2

Could you tell me which version you upgraded from?

paslandau commented 2 years ago

@djs55 I upgraded from 4.8.1 - but I believe the bug also exsisted in 4.8.1, I just didn't encounter it (I verified this by using a different Laptop with 4.8.1 still on it)

paslandau commented 2 years ago

FYI: The issue originally appeared for me, because I am sharing a .git directory between the host system and a docker container. git complained about the parent directory being owned by somebody else than the current user, e.g. via

fatal: unsafe repository ('/git' is owned by someone else)

The issue can be replicated via

# intialize new .git directory on the host system
git init

# run an "alpine/git" container and bind mount the current directory containing the .git directory as a non-root user
docker run --rm --name test --user 999 -v /$(pwd):/git alpine/git status

# results in
fatal: unsafe repository ('/git' is owned by someone else)
To add an exception for this directory, call:

        git config --global --add safe.directory /git

However, if I simply call ls first on the shared directory, the ownership is set to the current non-root user and a call to git status succeeds

# override the entrypoint to run `ls` first on the current directory `.`  and execute `git status` only afterwards
docker run --rm --name test --user 999 -v /$(pwd):/git --entrypoint sh alpine/git -c "ls . && git status"

# results in no error:
On branch master

No commits yet

nothing to commit (create/copy files and use "git add" to track)
M4rcDev commented 2 years ago

Same behavior with macOS:

Information

docker version output:

Client:
 Cloud integration: v1.0.24
 Version:           20.10.14
 API version:       1.41
 Go version:        go1.16.15
 Git commit:        a224086
 Built:             Thu Mar 24 01:49:20 2022
 OS/Arch:           darwin/arm64
 Context:           default
 Experimental:      true

Server: Docker Desktop 4.8.2 (79419)
 Engine:
  Version:          20.10.14
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.15
  Git commit:       87a90dc
  Built:            Thu Mar 24 01:45:44 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.5.11
  GitCommit:        3df54a852345ae127d1fa3092b95168e4a88e2f8
 runc:
  Version:          1.0.3
  GitCommit:        v1.0.3-0-gf46b6ba
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Output of /Applications/Docker.app/Contents/MacOS/com.docker.diagnose check

Starting diagnostics
[PASS] DD0027: is there available disk space on the host?
[PASS] DD0028: is there available VM disk space?
[PASS] DD0031: does the Docker API work?
[PASS] DD0004: is the Docker engine running?
[PASS] DD0011: are the LinuxKit services running?
[PASS] DD0016: is the LinuxKit VM running?
[PASS] DD0001: is the application running?
[PASS] DD0018: does the host support virtualization?
[PASS] DD0017: can a VM be started?
[PASS] DD0015: are the binary symlinks installed?
[PASS] DD0003: is the Docker CLI working?
[PASS] DD0013: is the $PATH ok?
[PASS] DD0007: is the backend responding?
[PASS] DD0014: are the backend processes running?
[PASS] DD0008: is the native API responding?
[PASS] DD0009: is the vpnkit API responding?
[PASS] DD0010: is the Docker API proxy responding?
[PASS] DD0012: is the VM networking working?
[PASS] DD0032: do Docker networks overlap with host IPs?
[SKIP] DD0030: is the image access management authorized?
[PASS] DD0019: is the com.docker.vmnetd process responding?
[PASS] DD0033: does the host have Internet access?
No fatal errors detected.

Output of the reproduce script:

+ rm -rf file1 file2
+ echo 'Creating test files'
Creating test files
+ echo file1
+ echo file2
+ echo 'Starting docker container with bind mount to the current directory'
Starting docker container with bind mount to the current directory
++ pwd
+ docker run --rm --name test -itd -v //Users/CENSORED/dockertest:/codebase busybox
b177b3486ed0994249ef6eb12c831d307673db2ba4d63c9a870db8d10ef623e3
+ echo 'Checking owner for '\''file1'\'' as user with id 1337'
Checking owner for 'file1' as user with id 1337
+ docker exec --user 1337 test ls -l codebase/file1
-rw-r--r--    1 1337     root             6 May 27 20:46 codebase/file1
+ echo 'Checking owner for '\''file2'\'' as user with id 999'
Checking owner for 'file2' as user with id 999
+ docker exec --user 999 test ls -l codebase/file2
-rw-r--r--    1 999      root             6 May 27 20:46 codebase/file2
+ echo 'Stopping docker container'
Stopping docker container
+ docker stop test
test
+ echo 'Starting docker container with bind mount to the current directory
(again)'
Starting docker container with bind mount to the current directory
(again)
++ pwd
+ docker run --rm --name test -itd -v //Users/marc.maurer/dockertest:/codebase busybox
296ad392c66d46c49f071836031f08daa55884e8c85bbc84ec49c7ad10498d1d
+ echo 'Checking owner for '\''file1'\'' as user with id 42'
Checking owner for 'file1' as user with id 42
+ docker exec --user 42 test ls -l codebase/file1
-rw-r--r--    1 42       root             6 May 27 20:46 codebase/file1
+ echo 'Checking owner for '\''file2'\'' witho no specific user (will be root)'
Checking owner for 'file2' witho no specific user (will be root)
+ docker exec test ls -l codebase/file2
-rw-r--r--    1 root     root             6 May 27 20:46 codebase/file2
lirc571 commented 2 years ago

This behaviour looks similar to https://github.com/docker/for-mac/issues/5480

ostefano commented 1 year ago

Latest Docker Desktop on Mac is still impacted by this issue. In my setup the Virtualization framework is enabled, but VirtioFS is disabled.

ostefano commented 1 year ago

I have tried disabling Use gRPC FUSE for file sharing without luck. File/dir ownership is still switched to root after the first time the file/dir is accessed.

docker-robott commented 1 year ago

There hasn't been any activity on this issue for a long time. If the problem is still relevant, mark the issue as fresh with a /remove-lifecycle stale comment. If not, this issue will be closed in 30 days.

Prevent issues from auto-closing with a /lifecycle frozen comment.

/lifecycle stale

docker-robott commented 1 year ago

Closed issues are locked after 30 days of inactivity. This helps our team focus on active issues.

If you have found a problem that seems similar to this, please open a new issue.

/lifecycle locked