Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cp's copy_file_range vs read-only files #399

Open
nwf opened this issue Aug 1, 2023 · 2 comments
Open

cp's copy_file_range vs read-only files #399

nwf opened this issue Aug 1, 2023 · 2 comments

Comments

@nwf
Copy link
Contributor

nwf commented Aug 1, 2023

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
Copy link
Contributor Author

nwf commented Aug 1, 2023

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

fuse-overlayfs/main.c

Lines 5409 to 5419 in 6452d53

if (node->hidden)
fd = openat (node->hidden_dirfd, node->path, O_NONBLOCK|O_NOFOLLOW|O_RDONLY, 0755);
else
fd = node->layer->ds->openat (node->layer, node->path, O_NONBLOCK|O_NOFOLLOW|O_RDONLY, 0755);
if (fd < 0)
{
fuse_reply_err (req, errno);
return;
}
fd_dest = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (dnode), dnode->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0));

@aaruni96
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants