From: Zbigniew Jędrzejewski-Szmek Date: Mon, 24 May 2021 09:33:50 +0000 (+0200) Subject: basic: allow copy_rights() to work without mounted /proc X-Git-Tag: v249-rc1~160^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0520564dcf3e0adc8eb140f149c93351481c446c;p=thirdparty%2Fsystemd.git basic: allow copy_rights() to work without mounted /proc This will be used in sysusers later on. --- diff --git a/src/basic/copy.c b/src/basic/copy.c index af9ac842a11..ed9f2ba3ff8 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -1243,7 +1243,7 @@ int copy_access(int fdf, int fdt) { return 0; } -int copy_rights(int fdf, int fdt) { +int copy_rights_with_fallback(int fdf, int fdt, const char *patht) { struct stat st; assert(fdf >= 0); @@ -1254,7 +1254,7 @@ int copy_rights(int fdf, int fdt) { if (fstat(fdf, &st) < 0) return -errno; - return fchmod_and_chown(fdt, st.st_mode & 07777, st.st_uid, st.st_gid); + return fchmod_and_chown_with_fallback(fdt, patht, st.st_mode & 07777, st.st_uid, st.st_gid); } int copy_xattr(int fdf, int fdt) { diff --git a/src/basic/copy.h b/src/basic/copy.h index da3ba07ad27..b36ddfcb015 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -64,5 +64,8 @@ static inline int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags cop int copy_times(int fdf, int fdt, CopyFlags flags); int copy_access(int fdf, int fdt); -int copy_rights(int fdf, int fdt); +int copy_rights_with_fallback(int fdf, int fdt, const char *patht); +static inline int copy_rights(int fdf, int fdt) { + return copy_rights_with_fallback(fdf, fdt, NULL); /* no fallback */ +} int copy_xattr(int fdf, int fdt); diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index e8435cab2cc..a4d772777e1 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -227,7 +227,7 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { return fchmod_and_chown(fd, mode, uid, gid); } -int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { +int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t uid, gid_t gid) { bool do_chown, do_chmod; struct stat st; int r; @@ -238,7 +238,11 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { * unaffected if the uid/gid is changed, i.e. it undoes implicit suid/sgid dropping the kernel does * on chown(). * - * This call is happy with O_PATH fds. */ + * This call is happy with O_PATH fds. + * + * If path is given, allow a fallback path which does not use /proc/self/fd/. On any normal system + * /proc will be mounted, but in certain improperly assembled environments it might not be. This is + * less secure (potential TOCTOU), so should only be used after consideration. */ if (fstat(fd, &st) < 0) return -errno; @@ -263,8 +267,14 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { if (((minimal ^ st.st_mode) & 07777) != 0) { r = fchmod_opath(fd, minimal & 07777); - if (r < 0) - return r; + if (r < 0) { + if (!path || r != -ENOSYS) + return r; + + /* Fallback path which doesn't use /proc/self/fd/. */ + if (chmod(path, minimal & 07777) < 0) + return -errno; + } } } @@ -274,8 +284,14 @@ int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { if (do_chmod) { r = fchmod_opath(fd, mode & 07777); - if (r < 0) - return r; + if (r < 0) { + if (!path || r != -ENOSYS) + return r; + + /* Fallback path which doesn't use /proc/self/fd/. */ + if (chmod(path, mode & 07777) < 0) + return -errno; + } } return do_chown || do_chmod; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 027037f7a72..7bac25704ff 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -34,7 +34,10 @@ int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); -int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_chown_with_fallback(int fd, const char *path, mode_t mode, uid_t uid, gid_t gid); +static inline int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) { + return fchmod_and_chown_with_fallback(fd, NULL, mode, uid, gid); /* no fallback */ +} int fchmod_umask(int fd, mode_t mode); int fchmod_opath(int fd, mode_t m);