fs-util: prefer linkat(AT_EMPTY_PATH) over /proc/self/fd/ shenanigans
The permission check got relaxed in kernel v6.10, so let's
switch the fallback order around.
This also effectively reverts 94d94f0c0a,
as I just realized that link_fd() involves multiple paths and
we can't tell which one tripped ENOENT...
This commit is contained in:
+13
-14
@@ -1343,26 +1343,25 @@ int xopenat_lock_full(
|
||||
}
|
||||
|
||||
int link_fd(int fd, int newdirfd, const char *newpath) {
|
||||
int r, k;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(newdirfd >= 0 || newdirfd == AT_FDCWD);
|
||||
assert(newpath);
|
||||
|
||||
/* Try linking via /proc/self/fd/ first. */
|
||||
r = RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), newdirfd, newpath, AT_SYMLINK_FOLLOW));
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
/* Try to link via AT_EMPTY_PATH first. This fails with ENOENT if we don't have CAP_DAC_READ_SEARCH
|
||||
* on kernels < 6.10, in which case we'd then resort to /proc/self/fd/ dance.
|
||||
*
|
||||
* See also: https://github.com/torvalds/linux/commit/42bd2af5950456d46fdaa91c3a8fb02e680f19f5 */
|
||||
r = RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
|
||||
if (r == -ENOENT) {
|
||||
r = RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), newdirfd, newpath, AT_SYMLINK_FOLLOW));
|
||||
if (r == -ENOENT && proc_mounted() == 0) /* No proc_fd_enoent_errno() here because we don't
|
||||
know if it's the target path that's missing. */
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/* Fall back to symlinking via AT_EMPTY_PATH as fallback (this requires CAP_DAC_READ_SEARCH and a
|
||||
* more recent kernel, but does not require /proc/ mounted) */
|
||||
k = proc_mounted();
|
||||
if (k < 0)
|
||||
return r;
|
||||
if (k > 0)
|
||||
return -EBADF;
|
||||
|
||||
return RET_NERRNO(linkat(fd, "", newdirfd, newpath, AT_EMPTY_PATH));
|
||||
return r;
|
||||
}
|
||||
|
||||
int linkat_replace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) {
|
||||
|
||||
Reference in New Issue
Block a user