cp: FIxed permission race when creating files#10204
cp: FIxed permission race when creating files#10204max-amb wants to merge 21 commits intouutils:mainfrom
Conversation
|
GNU testsuite comparison: |
|
I realise this is rather untenable right now, so I have dug up some logs to show the change in action, here is gnu openat(AT_FDCWD, "/tmp/b.txt", O_RDONLY|O_PATH|O_DIRECTORY) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY) = 3
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_EXCL, 0644) = 8
+++ exited with 0 +++and when openat(AT_FDCWD, "/tmp/b.txt", O_RDONLY|O_PATH|O_DIRECTORY) = -1 ENOTDIR (Not a directory)
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY) = 3
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_TRUNC) = 8
+++ exited with 0 +++Here is the implementations strace penat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0600) = 8
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 9
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0100644) = 12
fchmod(12, 0100644) = 0
chmod("/tmp/b.txt", 0644) = 0
+++ exited with 0 +++Note that the first 3 reads of openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0600) = 8instead of openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 8on main. Now when we already have openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 8
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 9
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0100644) = 12
fchmod(12, 0100644) = 0
chmod("/tmp/b.txt", 0100644) = 0
+++ exited with 0 +++which opens openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0600) = -1 EEXIST (File exists)
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_TRUNC|O_CLOEXEC) = 8
fchmod(8, 0600) = 0
openat(AT_FDCWD, "/tmp/a.txt", O_RDONLY|O_CLOEXEC) = 9
openat(AT_FDCWD, "/tmp/b.txt", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0100644) = 12
fchmod(12, 0100644) = 0
chmod("/tmp/b.txt", 0100644) = 0
+++ exited with 0 +++By changing the files permissions we ensure that the file cannot be read while data may be being copied in. This permission is later loosened to the correct permission. @sylvestre I hope that this makes it less hand-wavy :) |
|
and it needs tests :) |
Specific tests are at |
Merging this PR will not alter performance
Comparing Footnotes
|
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
|
ok so how I was handling truncation is the issue. |
|
GNU testsuite comparison: |
|
it regressed a bunch of tests, sorry! |
|
Ah yeah I think I see why now, the rewind as a replacement for truncate would mean sparse files are just layered on with any 0 spaces being filled with the old file. |
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
src/uu/cp/src/platform/linux.rs
Outdated
| let mut desired_permissions = dest_metadata.permissions(); | ||
| // This will be reset to the correct permissions later, this is defensive as it is | ||
| // the most restrictive | ||
| let mut dst = OpenOptions::new().write(true).open(&dest)?; |
There was a problem hiding this comment.
The file is opened with existing permissions before they're tightened to 0o600. The permissions should be set on the file path using std::fs::set_permissions() BEFORE opening the file handle. no ?
There was a problem hiding this comment.
For this, std::fs::set_permissions pre open sets the files permissions to writeable when the file is readonly and then it opens it without issue (because now it is writeable). This isn't the desired behaviour
|
GNU testsuite comparison: |
|
GNU testsuite comparison: |
Fixes #10011.