mpartel / bindfs

Mount a directory elsewhere with changed permissions.
https://bindfs.org/
GNU General Public License v2.0
436 stars 64 forks source link

Behavior Question: Why does BindFS exhibit permission issues when bind mounted into a container? #126

Closed alder711 closed 1 year ago

alder711 commented 1 year ago

BindFS version: 1.17.2

I have a question regarding the behavior of BindFS when used with bind mounts into containers.

I run into the below issue when I try to set up a directory in a container that has group write permissions so that users who are not the owner of the directory can still create/modify/delete the contents of this directory. For this, I attempt to use the BindFS arguments -p 0775 --create-with-perms=0775.

QUESTION: Why do -p and --create-with-perms cause permission issues when a user is not the owner of a directory, but has group ownership?

Currently, if I try to make a BindFS mount from one point on a host onto another point on that host and then bind mount that into a container, permissions issues seem to occur. In the below example, testowner owns the shared directory, while members of testgroup should have create/modify/delete access to the shared directory contents. This includes user testuser.

Example of Issue

  1. Ensure user and group existence on host
    host # groupadd -g 1003 testgroup
    host # useradd -u 1002 -G testgroup testuser
    host # useradd -u 1004 testowner
  2. Set up directories for BindFS and make a mountpoint
    host # mkdir /root/datadir #This is on an ext4 filesystem
    host # bindfs -d -u testowner -g testgroup --create-for-user=root --create-for-group=root --chown-ignore --chgrp-ignore --chmod-ignore -p 0775 --create-with-perms=0775 /root/datadir /mnt

    The output of BindFS here is:

    FUSE library version: 3.14.1
    nullpath_ok: 0
    unique: 2, opcode: INIT (26), nodeid: 0, insize: 104, pid: 0
    INIT: 7.38
    flags=0x73fffffb
    max_readahead=0x00020000
    INIT: 7.31
    flags=0x4040f039
    max_readahead=0x00020000
    max_write=0x00100000
    max_background=0
    congestion_threshold=0
    time_gran=1
    unique: 2, success, outsize: 80

    And verify directory permissions:

    
    host # ls -al /root/datadir
    total 8
    drwxr-xr-x 2 root root 4096 Apr 11 13:16 .
    drwxr-x--- 8 root root 4096 Apr 11 13:16 ..

host # ls -al /mnt total 8 drwxrwxr-x 2 testowner testgroup 4096 Apr 11 13:16 . drwxr-xr-x 20 root root 4096 Apr 11 00:43 ..

3. Start a container with the bind mount

host # docker run -it --rm --name tester --volume /mnt:/mnt alpine:latest sh

4. Ensure matching users in container

container # addgroup -g 1003 testgroup container # adduser -u 1002 testuser container # addgroup testuser testgroup container # adduser -u 1004 testowner

5. Set up directory in container for `testuser`

container # su testuser -c 'mkdir ~/mydir; echo 'testdata' > ~/mydir/testfile'

6. Try to move created directory as `testuser` into mountpoint

container # su testuser -c 'mv ~/mydir /mnt/'

The output of the above command is:

mv: can't preserve times of '/mnt/mydir/testfile': Operation not permitted mv: can't preserve ownership of '/mnt/mydir/testfile': Operation not permitted mv: can't preserve permissions of '/mnt/mydir/testfile': Operation not permitted mv: can't preserve permissions of '/mnt/mydir': Operation not permitted mv: can't preserve times of '/mnt/mydir': Operation not permitted mv: can't preserve ownership of '/mnt/mydir': Operation not permitted mv: can't preserve permissions of '/mnt/mydir': Operation not permitted

And the corresponding output from BindFS:

unique: 258, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 [137/866] getattr[NULL] / unique: 258, success, outsize: 120 unique: 260, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 260, success, outsize: 120 unique: 262, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir unique: 262, error: -2 (No such file or directory), outsize: 16 unique: 264, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 264, success, outsize: 120 unique: 266, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 266, success, outsize: 120 unique: 268, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir unique: 268, error: -2 (No such file or directory), outsize: 16 unique: 270, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 270, success, outsize: 120 unique: 272, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir unique: 272, error: -2 (No such file or directory), outsize: 16 unique: 274, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 274, success, outsize: 120 unique: 276, opcode: MKDIR (9), nodeid: 1, insize: 54, pid: 28475 mkdir /mydir 0755 umask=0000 getattr[NULL] /mydir NODEID: 6 unique: 276, success, outsize: 144 unique: 278, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 278, success, outsize: 120 unique: 280, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 280, success, outsize: 144 unique: 282, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 282, success, outsize: 120 unique: 284, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 284, success, outsize: 120 unique: 286, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 286, success, outsize: 144 unique: 288, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 288, success, outsize: 120 unique: 290, opcode: LOOKUP (1), nodeid: 6, insize: 49, pid: 28475 LOOKUP /mydir/testfile getattr[NULL] /mydir/testfile unique: 290, error: -2 (No such file or directory), outsize: 16 unique: 292, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 292, success, outsize: 120 unique: 294, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 294, success, outsize: 144 unique: 296, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 296, success, outsize: 120 unique: 298, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 298, success, outsize: 120 unique: 300, opcode: LOOKUP (1), nodeid: 6, insize: 49, pid: 28475 LOOKUP /mydir/testfile getattr[NULL] /mydir/testfile unique: 300, error: -2 (No such file or directory), outsize: 16 unique: 302, opcode: CREATE (35), nodeid: 6, insize: 65, pid: 28475 create flags: 0x80c1 /mydir/testfile 0100644 umask=0022 create[5] flags: 0x80c1 /mydir/testfile getattr[5] /mydir/testfile NODEID: 7 unique: 302, success, outsize: 160 unique: 304, opcode: GETATTR (3), nodeid: 7, insize: 56, pid: 28475 getattr[NULL] /mydir/testfile unique: 304, success, outsize: 120 unique: 306, opcode: GETXATTR (22), nodeid: 7, insize: 68, pid: 28475 getxattr /mydir/testfile security.capability 0 unique: 306, error: -61 (No data available), outsize: 16 unique: 308, opcode: WRITE (16), nodeid: 7, insize: 89, pid: 28475 write[5] 9 bytes to 0 flags: 0x8001 write[5] 9 bytes to 0 [44/866] unique: 308, success, outsize: 24 unique: 310, opcode: RELEASE (18), nodeid: 7, insize: 64, pid: 0 release[5] flags: 0x8001 unique: 310, success, outsize: 16 unique: 312, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 312, success, outsize: 120 unique: 314, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 314, success, outsize: 144 unique: 316, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 316, success, outsize: 120 unique: 318, opcode: LOOKUP (1), nodeid: 6, insize: 49, pid: 28475 LOOKUP /mydir/testfile getattr[NULL] /mydir/testfile NODEID: 7 unique: 318, success, outsize: 144 unique: 320, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 320, success, outsize: 120 unique: 322, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 322, success, outsize: 144 unique: 324, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 324, success, outsize: 120 unique: 326, opcode: LOOKUP (1), nodeid: 6, insize: 49, pid: 28475 LOOKUP /mydir/testfile getattr[NULL] /mydir/testfile NODEID: 7 unique: 326, success, outsize: 144 unique: 328, opcode: GETXATTR (22), nodeid: 7, insize: 68, pid: 28475 getxattr /mydir/testfile security.capability 0 unique: 328, error: -61 (No data available), outsize: 16 unique: 330, opcode: GETATTR (3), nodeid: 7, insize: 56, pid: 28475 getattr[NULL] /mydir/testfile unique: 330, success, outsize: 120 unique: 332, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 332, success, outsize: 120 unique: 334, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 334, success, outsize: 144 unique: 336, opcode: GETATTR (3), nodeid: 6, insize: 56, pid: 28475 getattr[NULL] /mydir unique: 336, success, outsize: 120 unique: 338, opcode: LOOKUP (1), nodeid: 6, insize: 49, pid: 28475 LOOKUP /mydir/testfile getattr[NULL] /mydir/testfile NODEID: 7 unique: 338, success, outsize: 144 unique: 340, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 340, success, outsize: 120 unique: 342, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 342, success, outsize: 144 unique: 344, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 344, success, outsize: 120 unique: 346, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 346, success, outsize: 144 unique: 348, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 348, success, outsize: 120 unique: 350, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 350, success, outsize: 144 unique: 352, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 28475 getattr[NULL] / unique: 352, success, outsize: 120 unique: 354, opcode: LOOKUP (1), nodeid: 1, insize: 46, pid: 28475 LOOKUP /mydir getattr[NULL] /mydir NODEID: 6 unique: 354, success, outsize: 144


## More Information

1. Omitting the BindFS arguments `-p 0775 --create-with-perms=0775` gives a different output for `mv`:

mv: can't create directory '/mnt/mydir': Permission denied


This is probably because, once `/mnt/mydir` is created, `testuser` doesn't have write permissions for it, since the group doesn't have write permissions.

2. This same issue actually also happens *WITHOUT* any use of containers (i.e., the commands in the container exhibit the same behavior if executed on the host), so this is probably not a container issue.
mpartel commented 1 year ago

If my sleepy brain is not mistaken, the following happens:

--chown-ignore doesn't do what one might expect here because it doesn't ignore the permission check. (This may well change when I eventually have time to fix #120 by doing the permission check in bindfs instead of letting the kernel do it.)

Possible solution: use --mirror=@testgroup instead of -u

alder711 commented 1 year ago

Ah, ok, that is a subtle difference that I didn't think about.

The weird thing is, BindFS worked in a previous setup I had for group writable purposes with the command I mentioned above until now, even though I didn't change BindFS versions. Not sure what changed for this to "break" on me. I am now using --mirror=@testgroup as you said, and it is working.

Thanks for all your hard work, @mpartel !