Bug: Improper permissions handling on directories using `–chmod` in COPY command
Contributing guidelines and issue reporting guide
- [x] I've read the contributing guidelines and wholeheartedly agree. I've also read the issue reporting guide.
Well-formed report checklist
- [x] I have found a bug that the documentation does not mention anything about my problem
- [x] I have found a bug that there are no open or closed issues that are related to my problem
- [x] I have provided version/information about my environment and done my best to provide a reproducer
Description of bug
Bug description
The command COPY --chmod=640 foo.bar /non-existent/path/foo.bar copies the foo.bar file to /non-existent/path/foo.bar, but it also sets the directory /non-existent/path/ permissions to 640. Prior to fixing #4945, the permissions for /non-existent/path/ were 755.
If I want users to access /non-existent/path/foo.bar, I now have to modify the above COPY command to COPY --chmod=750 foo.bar /non-existent/path/foo.bar, which gives the foo.bar file executable permissions. This outcome does not align with my expectations.
I expect that when creating a directory, regardless of the file permissions specified by the user, a -x permission should be set.
Reproduction
- Take this
Dockerfile
FROM busybox
COPY --chown=daemon:daemon --chmod=640 foo.bar /non-existent/path/foo.bar
touch foo.barDOCKER_BUILDKIT=1 docker build -t bla .docker run --entrypoint /bin/sh --user=daemon --rm -it bla -c "ls /non-existent/path/foo.bar"
Result:
ls: /non-existent/path/foo.bar: Permission denied
Version information
buildkit: v0.21.0
@thaJeztah wdyt?
So I ran in the same issue, I had initially --chmod=444, but now all the implicitly created directories also have only read permissions. This means I cannot access any file inside the folder.
My workaround for the moment is to write --chmod=ugo=rX which I did not find documented, but I found in a github issue. For this the permissions of the implicitly created folders are still 755
Hmm, right, interesting; so IIUC, the original issue that was fixed (and introduced this issue) was that the chmod didn't apply to directories;
- https://github.com/moby/buildkit/issues/4945
The report was slightly ambiguous, but re-reading it, I think it was mostly for the second case mentioned;
COPY --chown=1:1 --chmod=750 bla /bla
Where in the above, bla was a directory, so the expectation was to copy the directory to /bla inside the image and set its permissions; it's a bit ambiguous on what the expectations is for files inside the directory (i.e., if the chmod should be recursive?).
I guess to some extent it could be a match to how install (install -D) would handle this? Existing directories should probably not be touched (don't think it currently does?) and use default permissions;
-g, --group=GROUP set group ownership, instead of process' current group
-m, --mode=MODE set permission mode (as in chmod), instead of rwxr-xr-x
-o, --owner=OWNER set ownership (super-user only)
touch foo.bar
install -m 0444 foo.bar /non-existent/path/foo.bar
install: cannot create regular file '/non-existent/path/foo.bar': No such file or directory
install -D -m 0444 foo.bar /non-existent/path/foo.bar
ls -la /non-existent/path/foo.bar
-r--r--r-- 1 root root 0 May 7 13:05 /non-existent/path/foo.bar
ls -la /non-existent/path/
total 8
drwxr-xr-x 2 root root 4096 May 7 13:05 .
drwxr-xr-x 3 root root 4096 May 7 13:05 ..
-r--r--r-- 1 root root 0 May 7 13:05 foo.bar
ls -la /non-existent/
total 12
drwxr-xr-x 3 root root 4096 May 7 13:05 .
drwxr-xr-x 1 root root 4096 May 7 13:05 ..
drwxr-xr-x 2 root root 4096 May 7 13:05 path
mkdir -p /existing/path/
chmod -R 0700 /existing
install -D -m 0444 foo.bar /existing/path/foo.bar
ls -la /existing/path/foo.bar
-r--r--r-- 1 root root 0 May 7 13:06 /existing/path/foo.bar
ls -la /existing/path/
total 8
drwx------ 2 root root 4096 May 7 13:06 .
drwx------ 3 root root 4096 May 7 13:06 ..
-r--r--r-- 1 root root 0 May 7 13:06 foo.bar
ls -la /existing/
total 12
drwx------ 3 root root 4096 May 7 13:06 .
drwxr-xr-x 1 root root 4096 May 7 13:06 ..
drwx------ 2 root root 4096 May 7 13:06 path
One thing to probably account for is the COPY --parents option; should using that option preserve mode from the source? Not sure what cp does there (and what COPY --parents currently does).
My workaround for the moment is to write --chmod=ugo=rX which I did not find documented, but I found in a github issue. For this the permissions of the implicitly created folders are still 755
Hm, so that's a good point as well, and maybe the correct approach? Need to think about what's the most expected thing here (we definitely should look at the documentation though; was this already in the stable syntax, @tonistiigi ?)
was this already in the stable syntax,
Non-octal chmod is stable since 1.14
Docs update inbound
Is perhaps related / similar to https://github.com/moby/buildkit/issues/3602 ?
I experience similar behavior when the parent directories exists. With COPY --chmod=644 assets/ssh_known_hosts /etc/ssh/ the permissions of the existing parent directory /etc/ssh/ are changed from 755 to 644. When I remove --chmod=644, the permissions are unchanged.
docker info
Client: Version: 28.3.3 Context: default Debug Mode: false Plugins: buildx: Docker Buildx (Docker Inc.) Version: 0.26.1 Path: /usr/lib/docker/cli-plugins/docker-buildx compose: Docker Compose (Docker Inc.) Version: 2.39.2 Path: /usr/lib/docker/cli-plugins/docker-composeServer: Containers: 5 Running: 5 Paused: 0 Stopped: 0 Images: 45 Server Version: 28.3.3 Storage Driver: zfs Zpool: RPool Zpool Health: ONLINE Parent Dataset: RPool/docker Space Used By Parent: 94166941696 Space Available: 188206002176 Parent Quota: no Compression: zstd Logging Driver: json-file Cgroup Driver: systemd Cgroup Version: 2 Plugins: Volume: local Network: bridge host ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog CDI spec directories: /etc/cdi /var/run/cdi Swarm: inactive Runtimes: io.containerd.runc.v2 runc Default Runtime: runc Init Binary: docker-init containerd version: 75cb2b7193e4e490e9fbdc236c0e811ccaba3376.m runc version: init version: de40ad0 Security Options: seccomp Profile: builtin cgroupns Kernel Version: 6.12.41-2-lts Operating System: Arch Linux OSType: linux Architecture: x86_64 CPUs: 32 Total Memory: 125.7GiB Name: rndws01 ID: 3184585c-23f9-40f8-94b5-fa9b53e449ef Docker Root Dir: /var/lib/docker Debug Mode: false Username: lmsjk Experimental: false Insecure Registries: ::1/128 127.0.0.0/8 Live Restore Enabled: false