docker / for-mac

Bug reports for Docker Desktop for Mac
https://www.docker.com/products/docker#/mac
2.44k stars 119 forks source link

linux access command giving the wrong answer for X_OK for a non-executable file in a shared volume #5029

Open r-owen opened 4 years ago

r-owen commented 4 years ago

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

1) On macOS (I have 10.14.6): create a directory containing at least one file that is not executable.

2) 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.

3) 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:

neben commented 4 years ago

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
mryan1539 commented 4 years ago

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"'
mryan1539 commented 4 years ago

I've found that this also seems to affect Docker Desktop 2.4.0 as well; 2.3.0.5 functions as expected.

stephen-turner commented 4 years ago

@djs55 PTAL

docker-robott commented 3 years ago

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

r-owen commented 3 years ago

/remove-lifecycle stale

stephen-turner commented 3 years ago

/lifecycle frozen

mryan1539 commented 3 years ago

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?

stephen-turner commented 3 years ago

Not exactly from the command line, but you can find it in the settings.json file.

vitaly commented 3 years ago

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?

posita commented 2 years ago

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.

mryan1539 commented 2 years ago

The new "Enable VirtioFS accelerated directory sharing" feature seems to have the same issue; I assume it forces gRPC FUSE back on.

josedaniel-escribano-clarity commented 1 year ago

any news on this?

noorul commented 1 year ago

I am not sure why is issue not getting any attention.

akamaryan commented 1 year ago

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.

BenjaminYde commented 1 year ago

got the same issue here

Cito commented 1 year ago

Still the same with Docker Desktop 4.19.0.

walzph commented 1 year ago

And still the same for Docker Desktop 4.21.1

noorul commented 1 year ago

Not sure why is this not getting the deserving love.

quiminbano commented 10 months ago

February of 2024 and I have the same issue.

hjerpe commented 7 months ago

I have the same error as of April 2024.

ashwin153 commented 3 months ago

I have the same issue.

6XGate commented 3 months ago

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.

dhruvkb commented 3 months ago

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.

hash0b commented 2 weeks ago

I came here while analysing check-executables-have-shebangs pre-commit check failing, in a VS Code Dev Container. I tried using the new Docker VMM (beta) today and the pre-commit check is no longer failing. Just thought to leave a note.