From 7cd20415cfaa808791f7a650c7799802f6cb825a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 24 May 2021 11:33:50 +0200 Subject: [PATCH] basic: allow copy_rights() to work without mounted /proc This will be used in sysusers later on. (cherry picked from commit 0520564dcf3e0adc8eb140f149c93351481c446c) --- src/basic/copy.c | 4 ++-- src/basic/copy.h | 5 ++++- src/basic/fs-util.c | 28 ++++++++++++++++++++++------ src/basic/fs-util.h | 5 ++++- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/basic/copy.c b/src/basic/copy.c index d25777cc4b..142805a529 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 da3ba07ad2..b36ddfcb01 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 46d6f7780e..18fdaae9df 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 027037f7a7..7bac25704f 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); -- 2.25.1