File U_13-acct_gather_profile-hdf5-Avoid-TOCTOU-abuse-when-creating-directories.patch of Package slurm.31080
From: Alejandro Sanchez <alex@schedmd.com>
Date: Wed Oct 11 12:45:25 2023 -0600
Subject: [PATCH 13/19]acct_gather_profile/hdf5 - Avoid TOCTOU abuse when creating directories.
Patch-mainline: Upstream
Git-repo: https://github.com/SchedMD/slurm
Git-commit: 82977588c49b94bc8fcef519ea6f41ff4ad37a69
References: bsc#1216207
Signed-off-by: Egbert Eich <eich@suse.de>
Prevent TOCTOU abuse by using the *at family of syscalls (which work on file
descriptors instead of path names) when creating and changing permissions
for ProfileHDF5Dir and its user-specific sub-directories.
---
.../hdf5/acct_gather_profile_hdf5.c | 66 +++++++++++++++++-----
1 file changed, 51 insertions(+), 15 deletions(-)
diff --git a/src/plugins/acct_gather_profile/hdf5/acct_gather_profile_hdf5.c b/src/plugins/acct_gather_profile/hdf5/acct_gather_profile_hdf5.c
index 0baf9b539e..57eeaa907f 100644
--- a/src/plugins/acct_gather_profile/hdf5/acct_gather_profile_hdf5.c
+++ b/src/plugins/acct_gather_profile/hdf5/acct_gather_profile_hdf5.c
@@ -155,30 +155,66 @@ static uint32_t _determine_profile(void)
static void _create_directories(void)
{
- char *user_dir = NULL;
+ char *parent_dir = NULL, *user_dir = NULL, *hdf5_dir_rel = NULL;
+ char *slash = NULL;
+ int parent_dirfd, user_parent_dirfd;
xassert(g_job);
xassert(hdf5_conf.dir);
- xstrfmtcat(user_dir, "%s/%s", hdf5_conf.dir, g_job->user_name);
+ parent_dir = xstrdup(hdf5_conf.dir);
+ /* split into base and new directory name */
+ while ((slash = strrchr(parent_dir, '/'))) {
+ /* fix a path with one or more trailing slashes */
+ if (slash[1] == '\0')
+ slash[0] = '\0';
+ else
+ break;
+ }
+
+ if (!slash)
+ fatal("Invalid ProfileHDF5Dir=\"%s\"", hdf5_conf.dir);
+
+ slash[0] = '\0';
+ hdf5_dir_rel = slash + 1;
+
+ parent_dirfd = open(parent_dir, O_DIRECTORY | O_NOFOLLOW);
/*
- * To avoid race conditions (TOCTOU) with stat() calls, always
- * attempt to create the ProfileHDF5Dir and the user directory within.
+ * Use *at family of syscalls to prevent TOCTOU abuse by working
+ * on file descriptors instead of path names.
*/
- if (((mkdir(hdf5_conf.dir, 0755)) < 0) && (errno != EEXIST))
- fatal("mkdir(%s): %m", hdf5_conf.dir);
- if (chmod(hdf5_conf.dir, 0755) < 0)
- fatal("chmod(%s): %m", hdf5_conf.dir);
-
- if (((mkdir(user_dir, 0700)) < 0) && (errno != EEXIST))
- fatal("mkdir(%s): %m", user_dir);
- if (chmod(user_dir, 0700) < 0)
- fatal("chmod(%s): %m", user_dir);
- if (chown(user_dir, g_job->uid, g_job->gid) < 0)
- fatal("chown(%s): %m", user_dir);
+ if ((mkdirat(parent_dirfd, hdf5_dir_rel, 0755)) < 0) {
+ /* Never chmod on EEXIST */
+ if (errno != EEXIST)
+ fatal("mkdirat(%s): %m", hdf5_conf.dir);
+ } else if (fchmodat(parent_dirfd, hdf5_dir_rel, 0755,
+ AT_SYMLINK_NOFOLLOW) < 0)
+ fatal("fchmodat(%s): %m", hdf5_conf.dir);
+
+ xstrfmtcat(user_dir, "%s/%s", hdf5_conf.dir, g_job->user_name);
+ user_parent_dirfd = openat(parent_dirfd, hdf5_dir_rel,
+ O_DIRECTORY | O_NOFOLLOW);
+ close(parent_dirfd);
+
+ if ((mkdirat(user_parent_dirfd, g_job->user_name, 0700)) < 0) {
+ /* Never chmod on EEXIST */
+ if (errno != EEXIST)
+ fatal("mkdirat(%s): %m", user_dir);
+ } else {
+ /* fchmodat(2) man says AT_SYMLINK_NOFOLLOW not implemented. */
+ if (fchmodat(user_parent_dirfd, g_job->user_name, 0700, 0) < 0)
+ fatal("fchmodat(%s): %m", user_dir);
+
+ if (fchownat(user_parent_dirfd, g_job->user_name, g_job->uid,
+ g_job->gid, AT_SYMLINK_NOFOLLOW) < 0)
+ fatal("fchmodat(%s): %m", user_dir);
+ }
+ close(user_parent_dirfd);
xfree(user_dir);
+ xfree(parent_dir);
+ /* Do not xfree() hdf5_dir_rel (interior pointer to freed data). */
}
/*