From f77ee4f2bb6a3ef536e4226d46e7171f9a0c5916 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Fri, 9 Dec 2022 14:23:50 +0200 Subject: [PATCH] Fixes to mkhomedir behavior - Provide a switch to restore pre-CVE-2020-10737 behavior - Always set the home directory permissions according to HOME_MODE Signed-off-by: Alexander Bokovoy --- oddjob-override-mask-fix.patch | 246 +++++++++++++++++++++++++++++++++ oddjob.spec | 8 +- 2 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 oddjob-override-mask-fix.patch diff --git a/oddjob-override-mask-fix.patch b/oddjob-override-mask-fix.patch new file mode 100644 index 0000000..2c98a59 --- /dev/null +++ b/oddjob-override-mask-fix.patch @@ -0,0 +1,246 @@ +From 71b0389fbb31833d827f5f0fec18880c2f602753 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Thu, 19 May 2022 13:52:22 +0300 +Subject: [PATCH 1/2] mkhomedir: add support for pre-CVE-2020-10737 behavior + +Pre-CVE-2020-10737 behavior was used to allow creating home directories +on NFS mounts when non-Kerberos authentication method is in use. This is +exactly the case where a race condition addressed by the CVE-2020-10737 +fix could have happened. However, there are legit use cases where this +setup is needed. + +Add '-f' option to mkhomedir helper to activate previous behavior. In +order to enable it, a change to oddjobd-mkhomedir.conf configuration +file is needed by explicitly adding '-f' option to the executable file +definition. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2050079 + +Signed-off-by: Alexander Bokovoy +--- + src/mkhomedir.c | 16 +++++++++++++--- + src/oddjobd-mkhomedir.conf.5.in | 9 +++++++++ + 2 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/src/mkhomedir.c b/src/mkhomedir.c +index be85959..ac813a9 100644 +--- a/src/mkhomedir.c ++++ b/src/mkhomedir.c +@@ -53,9 +53,11 @@ static const char *skel; + static const char *skel_dir; + static struct passwd *pwd; + static mode_t override_umask; ++static int owner_mkdir_first = 0; + + #define FLAG_POPULATE (1 << 0) + #define FLAG_QUIET (1 << 1) ++#define FLAG_OWNER_MKDIR_FIRST (1 << 2) + + /* Given the path of an item somewhere in the skeleton directory, create as + * identical as possible a copy in the destination tree. */ +@@ -158,7 +160,7 @@ copy_single_item(const char *source, const struct stat *sb, + * target user just yet to avoid potential race conditions + * involving symlink attacks when we copy over the skeleton + * tree. */ +- if (status->level == 0) { ++ if (status->level == 0 && !owner_mkdir_first) { + uid = 0; + gid = 0; + } +@@ -222,6 +224,9 @@ mkhomedir(const char *user, int flags) + pwd->pw_dir); + return HANDLER_INVALID_INVOCATION; + } ++ if (flags & FLAG_OWNER_MKDIR_FIRST) { ++ owner_mkdir_first = 1; ++ } + if ((lstat(pwd->pw_dir, &st) == -1) && (errno == ENOENT)) { + /* Figure out which location we're using as a + * template. */ +@@ -237,7 +242,7 @@ mkhomedir(const char *user, int flags) + int res = nftw(get_skel_dir(), copy_single_item, 5, + FTW_PHYS); + /* only now give ownership to the target user */ +- if (res == 0) { ++ if (res == 0 && !owner_mkdir_first) { + res = chown(pwd->pw_dir, pwd->pw_uid, pwd->pw_gid); + } + +@@ -317,8 +322,11 @@ main(int argc, char **argv) + umask(override_umask); + skel_dir = "/etc/skel"; + +- while ((i = getopt(argc, argv, "nqs:u:")) != -1) { ++ while ((i = getopt(argc, argv, "nqfs:u:")) != -1) { + switch (i) { ++ case 'f': ++ flags |= FLAG_OWNER_MKDIR_FIRST; ++ break; + case 'n': + flags &= ~FLAG_POPULATE; + break; +@@ -339,6 +347,8 @@ main(int argc, char **argv) + break; + default: + fprintf(stderr, "Valid options:\n" ++ "-f\tCreate home directory initially owned by user, " ++ "not root. See man page for security issues.\n" + "-n\tDo not populate home directories, " + "just create them.\n" + "-q\tDo not print messages when creating " +diff --git a/src/oddjobd-mkhomedir.conf.5.in b/src/oddjobd-mkhomedir.conf.5.in +index d7a2429..6e35ad5 100644 +--- a/src/oddjobd-mkhomedir.conf.5.in ++++ b/src/oddjobd-mkhomedir.conf.5.in +@@ -10,6 +10,15 @@ directory. + + The mkhomedir helper itself accepts these options: + .TP ++-f ++Restore behavior before CVE-2020-10737 was fixed: create the home directory ++with user's ownership directly rather than create it as a root and only after ++populating it change to the user's ownership. The former behavior is insecure ++but may be used to allow creation of NFS-mounted home directories when ++non-Kerberos authentication is in use. It is prone for a race condition that ++could be exploited in the NFS-mounted home directories use case. To avoid ++CVE-2020-10737, do not use \fB-f\fR option in production environments. ++.TP + -q + Refrain from outputting the usual "Creating home directory..." message when it + creates a home directory. +-- +2.38.1 + + +From b800e25258353dbb1a88506123c21ac3298fd2d0 Mon Sep 17 00:00:00 2001 +From: Carlos Santos +Date: Tue, 18 Oct 2022 08:59:16 -0300 +Subject: [PATCH 2/2] Always set the home directory permissions according to + HOME_MODE + +Currently the home directory permissions are set by taking the /etc/skel +mode and masking it with HOME_MODE: + + override_umask = 0777 & ~get_umask(&configured_umask, "HOME_MODE"); + stat(skel, &sb); /* performed by nftw() */ + oddjob_selinux_mkdir(newpath, sb->st_mode & ~override_umask, uid, gid); + +The problem is that when HOME_MODE is more permissive than /etc/skel, +the masking will not produce the desired result, e.g. + + skel_mode = 0755 + HOME_MODE = 0775 + override_umask = 0777 & ~HOME_MODE /* 0002 */ + mode = skel_mode & ~override_umask /* 0755 & 0775 = 0755 */ + +In order to fix the problem, always use 0777 & ~override_umask for the +top home directory. + +Signed-off-by: Carlos Santos +Fixes: https://pagure.io/oddjob/issue/17 +--- + src/mkhomedir.c | 45 +++++++++++++++++++++------------------------ + 1 file changed, 21 insertions(+), 24 deletions(-) + +diff --git a/src/mkhomedir.c b/src/mkhomedir.c +index ac813a9..932918f 100644 +--- a/src/mkhomedir.c ++++ b/src/mkhomedir.c +@@ -67,6 +67,7 @@ copy_single_item(const char *source, const struct stat *sb, + { + uid_t uid = pwd->pw_uid; + gid_t gid = pwd->pw_gid; ++ mode_t mode = sb->st_mode & ~override_umask; + int sfd, dfd, i, res; + char target[PATH_MAX + 1], newpath[PATH_MAX + 1]; + unsigned char buf[BUFSIZ]; +@@ -112,8 +113,7 @@ copy_single_item(const char *source, const struct stat *sb, + oddjob_set_selinux_file_creation_context(newpath, + sb->st_mode | + S_IFREG); +- dfd = open(newpath, O_WRONLY | O_CREAT | O_EXCL, +- sb->st_mode & ~override_umask); ++ dfd = open(newpath, O_WRONLY | O_CREAT | O_EXCL, mode); + if (dfd != -1) { + while ((i = read(sfd, buf, sizeof(buf))) > 0) { + retry_write(dfd, buf, i); +@@ -156,20 +156,22 @@ copy_single_item(const char *source, const struct stat *sb, + } + return 0; + case FTW_D: +- /* It's the home directory itself. Don't give it to the +- * target user just yet to avoid potential race conditions +- * involving symlink attacks when we copy over the skeleton +- * tree. */ +- if (status->level == 0 && !owner_mkdir_first) { +- uid = 0; +- gid = 0; +- } +- + /* It's a directory. Make one with the same name and + * permissions, but owned by the target user. */ +- res = oddjob_selinux_mkdir(newpath, +- sb->st_mode & ~override_umask, +- uid, gid); ++ if (status->level == 0) { ++ /* It's the home directory itself. Use the configured ++ * (or overriden) mode, not the source mode & umask. */ ++ mode = 0777 & ~override_umask; ++ ++ /* Don't give it to the target user just yet to avoid ++ * potential race conditions involving symlink attacks ++ * when we copy over the skeleton tree. */ ++ if (!owner_mkdir_first) { ++ uid = 0; ++ gid = 0; ++ } ++ } ++ res = oddjob_selinux_mkdir(newpath, mode, uid, gid); + + /* on unexpected errors, or if the home directory itself + * suddenly already exists, abort the copy operation. */ +@@ -248,12 +250,8 @@ mkhomedir(const char *user, int flags) + + return res; + } else { +- if (stat(skel, &st) != 0) { +- st.st_mode = S_IRWXU; +- } + if ((oddjob_selinux_mkdir(pwd->pw_dir, +- st.st_mode & +- ~override_umask, ++ 0777 & ~override_umask, + pwd->pw_uid, + pwd->pw_gid) != 0) && + (errno != EEXIST)) { +@@ -269,11 +267,11 @@ mkhomedir(const char *user, int flags) + } + + static mode_t +-get_umask(int *configured, const char *variable) ++get_umask(int *configured, const char *variable, mode_t default_value) + { + FILE *fp; + char buf[BUFSIZ], *p, *end; +- mode_t mask = umask(0777); ++ mode_t mask = default_value; + long tmp; + size_t vlen = strlen(variable); + +@@ -315,11 +313,10 @@ main(int argc, char **argv) + + openlog(PACKAGE "-mkhomedir", LOG_PID, LOG_DAEMON); + /* Unlike UMASK, HOME_MODE is the file mode, so needs to be reverted */ +- override_umask = 0777 & ~get_umask(&configured_umask, "HOME_MODE"); ++ override_umask = 0777 & ~get_umask(&configured_umask, "HOME_MODE", 0); + if (configured_umask == 0) { +- override_umask = get_umask(&configured_umask, "UMASK"); ++ override_umask = get_umask(&configured_umask, "UMASK", 022); + } +- umask(override_umask); + skel_dir = "/etc/skel"; + + while ((i = getopt(argc, argv, "nqfs:u:")) != -1) { +-- +2.38.1 + diff --git a/oddjob.spec b/oddjob.spec index fbdb28f..07267e8 100644 --- a/oddjob.spec +++ b/oddjob.spec @@ -22,9 +22,10 @@ Name: oddjob Version: 0.34.7 -Release: 6%{?dist} +Release: 7%{?dist} Source0: https://releases.pagure.org/oddjob/oddjob-%{version}.tar.gz Source1: https://releases.pagure.org/oddjob/oddjob-%{version}.tar.gz.asc +Patch1: oddjob-override-mask-fix.patch Summary: A D-Bus service which runs odd jobs on behalf of client applications License: BSD BuildRequires: make @@ -88,6 +89,7 @@ This package contains a trivial sample oddjob service. %prep %setup -q +%patch1 -p1 %build sample_flag= @@ -247,6 +249,10 @@ fi exit 0 %changelog +* Fri Dec 09 2022 Alexander Bokovoy - 0.34.7-7 +- Provide a switch to restore pre-CVE-2020-10737 behavior +- Always set the home directory permissions according to HOME_MODE + * Fri Jul 22 2022 Fedora Release Engineering - 0.34.7-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild