containers / fuse-overlayfs

FUSE implementation for overlayfs
GNU General Public License v2.0
502 stars 83 forks source link

cp's copy_file_range vs read-only files #399

Open nwf opened 11 months ago

nwf commented 11 months ago

Running the following straightforward sequence on a fuse-overlayfs mount

echo foo > test
chmod -w test
cp test test2

breaks thusly

cp: error copying 'test' to 'test2': Permission denied

and leaves behind a zero-byte file:

-r--r--r-- 1 daemon daemon 4 Aug  1 12:48 test
-r--r--r-- 1 daemon daemon 0 Aug  1 12:48 test2

strace-ing that failing cp shows that copy_file_range is failing:

openat(AT_FDCWD, "test2", O_WRONLY|O_CREAT|O_EXCL, 0444) = 4
ioctl(4, BTRFS_IOC_CLONE or FICLONE, 3) = -1 EOPNOTSUPP (Operation not supported)
newfstatat(4, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
copy_file_range(3, NULL, 4, NULL, 9223372035781033984, 0) = -1 EACCES (Permission denied)

strace-ing fuse-overlayfs itself shows that it attempts to re-open the file rather than using the open handle it already has, resulting in different access semantics:

openat2(4, "./test2", {flags=O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode=0444, resolve=RESOLVE_IN_ROOT}, 24) = 10
[statx and fuse traffic elided]
openat2(4, "test", {flags=O_RDONLY|O_NONBLOCK|O_NOFOLLOW, resolve=RESOLVE_IN_ROOT}, 24) = 11
openat2(4, "test2", {flags=O_WRONLY|O_NONBLOCK|O_NOFOLLOW, resolve=RESOLVE_IN_ROOT}, 24) = -1 EACCES (Permission denied)
writev(6, [{iov_base="\20\0\0\0\363\377\377\377\302\0\0\0\0\0\0\0", iov_len=16}], 1) = 16
close(11)                               = 0
read(6, "@\0\0\0\22\0\0\0\304\0\0\0\0\0\0\0000Q\217?\1\0\0\0\0\0\0\0\0\0\0\0"..., 16781312) = 64
close(10)                               = 0
writev(6, [{iov_base="\20\0\0\0\0\0\0\0\304\0\0\0\0\0\0\0", iov_len=16}], 1) = 16

The system running this is a pretty bog-standard Debian box, save that it's ppc64le, but that shouldn't matter here. fuse-overlayfs is their build of version 1.10.

nwf commented 11 months ago

This is... shockingly fundamental to fuse-overlayfs? Does it just not track open handles? It certainly looks like it doesn't, given the code at https://github.com/containers/fuse-overlayfs/blob/6452d53e83900678f1ead86400332cd7975a1395/main.c#L5409-L5419

aaruni96 commented 10 months ago

I ran into this, and it is a fatal bug for my workflow.

I am on an Ubuntu box, using default repositories

$ fuse-overlayfs --version
fuse-overlayfs: version 1.7.1
FUSE library version 3.10.5
using FUSE kernel interface version 7.31
fusermount3 version: 3.10.5