]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn-patch-uid: try fchmodat2() to restore mode of symlink 29817/head
authorArseny Maslennikov <arseny@altlinux.org>
Sat, 21 Oct 2023 08:00:00 +0000 (11:00 +0300)
committerMike Yuan <me@yhndnzj.com>
Wed, 1 Nov 2023 16:29:09 +0000 (00:29 +0800)
Prior to this commit, if the target had been a symlink, we did nothing
with it. Let's try with fchmodat2() and skip gracefully if not supported.

Co-authored-by: Mike Yuan <me@yhndnzj.com>
src/nspawn/nspawn-patch-uid.c

index 66663adc2b9078c2119f2522bae561c8a22dc66a..063995dd6b8efa7dfbfa51aa15ba27a62e2f6091 100644 (file)
@@ -11,6 +11,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "missing_magic.h"
+#include "missing_syscall.h"
 #include "nspawn-def.h"
 #include "nspawn-patch-uid.h"
 #include "stat-util.h"
@@ -239,14 +240,18 @@ static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift
 
                 /* The Linux kernel alters the mode in some cases of chown(). Let's undo this. */
                 if (name) {
+                        /* It looks like older glibc (before 2016) did not support AT_SYMLINK_NOFOLLOW. */
                         if (!S_ISLNK(st->st_mode))
-                                r = fchmodat(fd, name, st->st_mode, 0);
-                        else /* AT_SYMLINK_NOFOLLOW is not available for fchmodat() */
-                                r = 0;
+                                r = RET_NERRNO(fchmodat(fd, name, st->st_mode, 0));
+                        else {
+                                r = RET_NERRNO(fchmodat2(fd, name, st->st_mode, AT_SYMLINK_NOFOLLOW));
+                                if (IN_SET(r, -ENOSYS, -EPERM))
+                                        r = 0;
+                        }
                 } else
-                        r = fchmod(fd, st->st_mode);
+                        r = RET_NERRNO(fchmod(fd, st->st_mode));
                 if (r < 0)
-                        return -errno;
+                        return r;
 
                 changed = true;
         }