for-mac
for-mac copied to clipboard
linux access command giving the wrong answer for X_OK for a non-executable file in a shared volume
- [x] This is a bug report
- [ ] This is a feature request
- [x] I searched existing issues before opening this one
This may be the same as issue https://github.com/docker/for-mac/issues/5007 I can't quite tell. I expected False and in that ticket the user expected "access denied".
Expected behavior
The linux command access(path, F_OK) should return False for a file that is not executable.
Actual behavior
When the file is in a shared volume the access command above returns True for a file that is not executable. This despite ls -l
showing that the file is not executable.
Steps to reproduce the behavior
-
On macOS (I have 10.14.6): create a directory containing at least one file that is not executable.
-
Run a Docker image that runs CentOS Linux release 7.7.1908 (Core), mounting that directory into the image. It simplifies the test if the Docker image includes Python (I have 3.7.8 but it should not matter), but it suffices to have gcc.
-
Run the following code inside the image:
python -c "import os; print(os.access(<path-to-non-exe-file>, os.X_OK))"
I see True if the file is not executable and is on my shared volume, which is incorrect. I see the correct result of False if the file is not executable and is internal to the Docker image.
If you would rather not use Python then compile and run the following C++ code. I get the same results with it as I do with the Python test above.
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("one argument required: the path\n");
return 1;
}
char* path = argv[1];
int rval;
/* Check file existence. */
rval = access(path, F_OK);
if (rval == 0)
printf("%s exists\n", path);
else {
if (errno == ENOENT) {
printf("%s does not exist\n", path);
} else if (errno == EACCES) {
printf("%s is not accessible\n", path);
return 0;
}
}
/* Check executable access. */
rval = access(path, X_OK);
if (rval == 0) {
printf("%s is executable\n", path);
} else {
printf("%s is not executable\n", path);
}
}
Output of docker version
:
Client: Docker Engine - Community
Cloud integration 0.1.18
Version: 19.03.13
API version: 1.40
Go version: go1.13.15
Git commit: 4484c46d9d
Built: Wed Sep 16 16:58:31 2020
OS/Arch: darwin/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 19.03.13
API version: 1.40 (minimum version 1.12)
Go version: go1.13.15
Git commit: 4484c46d9d
Built: Wed Sep 16 17:07:04 2020
OS/Arch: linux/amd64
Experimental: true
containerd:
Version: v1.3.7
GitCommit: 8fba4e9a7d01810a393d5d25a3621dc101981175
runc:
Version: 1.0.0-rc10
GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd
docker-init:
Version: 0.18.0
GitCommit: fec3683
Output of docker info
:
$ docker info
Client:
Debug Mode: false
Server:
Containers: 3
Running: 2
Paused: 0
Stopped: 1
Images: 10
Server Version: 19.03.13
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 8fba4e9a7d01810a393d5d25a3621dc101981175
runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
init version: fec3683
Security Options:
seccomp
Profile: default
Kernel Version: 4.19.76-linuxkit
Operating System: Docker Desktop
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 9.737GiB
Name: docker-desktop
ID: VRRF:OCAS:J3SQ:5HIW:GK3Z:JA4A:VDKW:JHSQ:ET6Y:GTJ7:MONZ:7VK7
Docker Root Dir: /var/lib/docker
Debug Mode: true
File Descriptors: 55
Goroutines: 68
System Time: 2020-10-23T22:29:19.9940502Z
EventsListeners: 3
HTTP Proxy: gateway.docker.internal:3128
HTTPS Proxy: gateway.docker.internal:3129
Registry: https://index.docker.io/v1/
Labels:
Experimental: true
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine
Additional environment details (AWS, VirtualBox, physical, etc.)
macOS 10.14.6 And in the Docker image:
- CentOS Linux release 7.7.1908 (Core)
- gcc (crosstool-NG 1.24.0.123_1667d2b) 7.5.0
- Python 3.7.8
This can also be easily reproduced with the alpine postgres
image and bash
, where bash
falsely reports the non-executable file on a grpcfuse volume to be executable:
# docker run -v `pwd`/data:/data postgres bash -c 'FILE=data/foo.sh; touch $FILE; chmod -x $FILE; ls -l $FILE; if [ -x "$FILE" ]; then echo file is executable; fi'
-rw-r--r-- 1 root root 0 Nov 4 19:15 data/foo.sh
file is executable
Interestingly enough, sh
behaves correctly:
docker run -v `pwd`/data:/data postgres sh -c 'FILE=data/foo.sh; touch $FILE; chmod -x $FILE; ls -l $FILE; if [ -x "$FILE" ]; then echo file is executable; fi'
-rw-r--r-- 1 root root 0 Nov 4 19:17 data/foo.sh
The issue seems to affect access() and faccessat(), but not stat(). /bin/sh on alpine and /bin/ash both use stat(), while bash uses faccessat().
So (with Docker Desktop 2.5.0 on MacOS 10.15):
mkdir mount
touch mount/foo
# The following will output nothing (stat() is used):
docker run -it --mount source=`pwd`/mount,dst=/mount,type=bind alpine sh -c 'test -x /mount/foo && echo exectuable'
# The following will output "executable" (faccessat() is used):
docker run -it --mount source=`pwd`/mount,dst=/mount,type=bind alpine sh -c 'apk add bash > /dev/null; /bin/bash -c "test -x /mount/foo && echo exectuable"'
I've found that this also seems to affect Docker Desktop 2.4.0 as well; 2.3.0.5 functions as expected.
@djs55 PTAL
Issues go stale after 90 days of inactivity.
Mark the issue as fresh with /remove-lifecycle stale
comment.
Stale issues will be closed after an additional 30 days of inactivity.
Prevent issues from auto-closing with an /lifecycle frozen
comment.
If this issue is safe to close now please do so.
Send feedback to Docker Community Slack channels #docker-for-mac or #docker-for-windows. /lifecycle stale
/remove-lifecycle stale
/lifecycle frozen
I've found that this can be worked around by disabling gRPC FUSE. Is there some way to detect from the command-line whether gRPC FUSE is enabled or not? Failing that, is it possible to detect over the API?
Not exactly from the command line, but you can find it in the settings.json file.
so.. is there any solution to this? The legacy sharing (when you disable gRPC FUSE) has 1 second file timestamps resolution. which breaks my build process. and gRPC has broken 'test -x' in bash. which also breaks build process ;)
any ideas?
Is this a Docker issue or FUSE issue? Is there some way we can at least identify where a fix might exist?
This comes into play when doing VSCode Remote Container development for build/make processes that check for executable permissions.
The new "Enable VirtioFS accelerated directory sharing" feature seems to have the same issue; I assume it forces gRPC FUSE back on.
any news on this?
I am not sure why is issue not getting any attention.
It seems that both gRPC FUSE and VirtioFS in the very latest version (4.16.2) still suffer from this bug.
Worse, it seems that the legacy osxfs driver is now hanging on access to bind-mounted volumes (at least on MacOS 12.6.3 ARM), breaking the workaround of using it instead, completely breaking my use case for Docker Desktop.
got the same issue here
Still the same with Docker Desktop 4.19.0.
And still the same for Docker Desktop 4.21.1
Not sure why is this not getting the deserving love.
February of 2024 and I have the same issue.
I have the same error as of April 2024.
I have the same issue.
This seems to effect the stock official node
containers if you give it a CMD to a file that is within a bind mount to your local directory.
For what its worth, several of my colleagues and I switched to OrbStack instead of Docker Desktop and it does not have this problem. If it is a viable option for you, do consider giving it a try.