Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package systemd for openSUSE:Factory checked in at 2022-01-12 00:26:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/systemd (Old) and /work/SRC/openSUSE:Factory/.systemd.new.1892 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "systemd" Wed Jan 12 00:26:25 2022 rev:343 rq:945520 version:249.7 Changes: -------- --- /work/SRC/openSUSE:Factory/systemd/systemd.changes 2022-01-07 12:44:58.243786690 +0100 +++ /work/SRC/openSUSE:Factory/.systemd.new.1892/systemd.changes 2022-01-12 00:26:28.183894850 +0100 @@ -1,0 +2,26 @@ +Tue Jan 11 08:06:11 UTC 2022 - Franck Bui <f...@suse.com> + +- Added patches to fix CVE-2021-3997 (bsc#1194178) + + 5000-shared-rm_rf-refactor-rm_rf_children_inner-to-shorte.patch + 5001-shared-rm_rf-refactor-rm_rf-to-shorten-code-a-bit.patch + 5002-shared-rm-rf-loop-over-nested-directories-instead-of.patch + + These patches will be dropped and cherry-picked from upstream once upstream + will commit them in their main branch. + +------------------------------------------------------------------- +Thu Jan 6 14:31:21 UTC 2022 - Franck Bui <f...@suse.com> + +- Import commit a54f80116ccf105dff11aef5d18dd110ebd3e8ee + + 30cbebc56f tmpfiles: 'st' may have been used uninitialized + 5443654ec0 macro: add new helper RET_NERRNO() + 8d90ecc435 rm-rf: optionally fsync() after removing directory tree + 591344010d rm-rf: refactor rm_rf_children(), split out body of directory iteration loop + 8c7762c4f1 Bump the max number of inodes for /dev to a million (bsc#1192858) + dc9476c881 journal: don't remove the flushed flag when journald is stopped + 29efc29efd TEST-10: don't attempt to write a byte to the socket + 773fb785b6 Bump the max number of inodes for /dev to 128k (bsc#1192858) + +------------------------------------------------------------------- Old: ---- systemd-v249.7+suse.57.g523f32df57.tar.xz New: ---- 5000-shared-rm_rf-refactor-rm_rf_children_inner-to-shorte.patch 5001-shared-rm_rf-refactor-rm_rf-to-shorten-code-a-bit.patch 5002-shared-rm-rf-loop-over-nested-directories-instead-of.patch systemd-v249.7+suse.66.ga54f80116c.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ systemd.spec ++++++ --- /var/tmp/diff_new_pack.04IBax/_old 2022-01-12 00:26:29.275895180 +0100 +++ /var/tmp/diff_new_pack.04IBax/_new 2022-01-12 00:26:29.283895184 +0100 @@ -32,7 +32,7 @@ %endif %define min_kernel_version 4.5 -%define suse_version +suse.57.g523f32df57 +%define suse_version +suse.66.ga54f80116c %define _testsuitedir /usr/lib/systemd/tests %if 0%{?bootstrap} @@ -210,6 +210,12 @@ # temporary and should be removed as soon as a fix is merged by # upstream. +# The following patches address CVE-2021-3997. They will be moved to the git +# repo once the issue will become public and upstream will release them. +Patch5000: 5000-shared-rm_rf-refactor-rm_rf_children_inner-to-shorte.patch +Patch5001: 5001-shared-rm_rf-refactor-rm_rf-to-shorten-code-a-bit.patch +Patch5002: 5002-shared-rm-rf-loop-over-nested-directories-instead-of.patch + %description Systemd is a system and service manager, compatible with SysV and LSB init scripts for Linux. systemd provides aggressive parallelization ++++++ 5000-shared-rm_rf-refactor-rm_rf_children_inner-to-shorte.patch ++++++ >From 5bc4f2e271c4907af1d3208c5bb33ce795326abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> Date: Tue, 23 Nov 2021 15:55:45 +0100 Subject: [PATCH 5000/5002] shared/rm_rf: refactor rm_rf_children_inner() to shorten code a bit --- src/shared/rm-rf.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index 19f37e0f19..7362954116 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -124,7 +124,7 @@ static int rm_rf_children_inner( const struct stat *root_dev) { struct stat st; - int r; + int r, q = 0; assert(fd >= 0); assert(fname); @@ -142,7 +142,6 @@ static int rm_rf_children_inner( if (is_dir) { _cleanup_close_ int subdir_fd = -1; - int q; /* if root_dev is set, remove subdirectories only if device is same */ if (root_dev && st.st_dev != root_dev->st_dev) @@ -178,23 +177,15 @@ static int rm_rf_children_inner( * again for each directory */ q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev); - r = unlinkat_harder(fd, fname, AT_REMOVEDIR, flags); - if (r < 0) - return r; - if (q < 0) - return q; - - return 1; - - } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) { - r = unlinkat_harder(fd, fname, 0, flags); - if (r < 0) - return r; - - return 1; - } + } else if (flags & REMOVE_ONLY_DIRECTORIES) + return 0; - return 0; + r = unlinkat_harder(fd, fname, is_dir ? AT_REMOVEDIR : 0, flags); + if (r < 0) + return r; + if (q < 0) + return q; + return 1; } int rm_rf_children( -- 2.31.1 ++++++ 5001-shared-rm_rf-refactor-rm_rf-to-shorten-code-a-bit.patch ++++++ >From 8f608df0305355c9b2ddd7c75926a6bd6247e635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbys...@in.waw.pl> Date: Tue, 23 Nov 2021 16:56:42 +0100 Subject: [PATCH 5001/5002] shared/rm_rf: refactor rm_rf() to shorten code a bit --- src/shared/rm-rf.c | 53 ++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index 7362954116..c7d3b8b7ad 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -250,7 +250,7 @@ int rm_rf_children( } int rm_rf(const char *path, RemoveFlags flags) { - int fd, r; + int fd, r, q = 0; assert(path); @@ -282,49 +282,42 @@ int rm_rf(const char *path, RemoveFlags flags) { } fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); - if (fd < 0) { + if (fd >= 0) { + /* We have a dir */ + r = rm_rf_children(fd, flags, NULL); + + if (FLAGS_SET(flags, REMOVE_ROOT)) + q = RET_NERRNO(rmdir(path)); + } else { if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT) return 0; if (!IN_SET(errno, ENOTDIR, ELOOP)) return -errno; - if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES)) + if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES) || !FLAGS_SET(flags, REMOVE_ROOT)) return 0; - if (FLAGS_SET(flags, REMOVE_ROOT)) { - - if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) { - struct statfs s; - - if (statfs(path, &s) < 0) - return -errno; - if (is_physical_fs(&s)) - return log_error_errno(SYNTHETIC_ERRNO(EPERM), - "Attempted to remove files from a disk file system under \"%s\", refusing.", - path); - } - - if (unlink(path) < 0) { - if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT) - return 0; + if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) { + struct statfs s; + if (statfs(path, &s) < 0) return -errno; - } + if (is_physical_fs(&s)) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), + "Attempted to remove files from a disk file system under \"%s\", refusing.", + path); } - return 0; + r = 0; + q = RET_NERRNO(unlink(path)); } - r = rm_rf_children(fd, flags, NULL); - - if (FLAGS_SET(flags, REMOVE_ROOT) && - rmdir(path) < 0 && - r >= 0 && - (!FLAGS_SET(flags, REMOVE_MISSING_OK) || errno != ENOENT)) - r = -errno; - - return r; + if (r < 0) + return r; + if (q < 0 && (q != -ENOENT || !FLAGS_SET(flags, REMOVE_MISSING_OK))) + return q; + return 0; } int rm_rf_child(int fd, const char *name, RemoveFlags flags) { -- 2.31.1 ++++++ 5002-shared-rm-rf-loop-over-nested-directories-instead-of.patch ++++++ >From c561e2eab3b9b759b7592ea1b8168d4f36ede031 Mon Sep 17 00:00:00 2001 From: Franck Bui <f...@suse.com> Date: Wed, 5 Jan 2022 15:08:07 +0100 Subject: [PATCH 5002/5002] shared/rm-rf: loop over nested directories instead of instead of recursing To remove directory structures, we need to remove the innermost items first, and then recursively remove higher-level directories. We would recursively descend into directories and invoke rm_rf_children and rm_rm_children_inner. This is problematic when too many directories are nested. Instead, let's create a "TODO" queue. In the the queue, for each level we hold the DIR* object we were working on, and the name of the directory. This allows us to leave a partially-processed directory, and restart the removal loop one level down. When done with the inner directory, we use the name to unlinkat() it from the parent, and proceed with the removal of other items. Because the nesting is increased by one level, it is best to view this patch with -b/--ignore-space-change. This fixes CVE-2021-3997, https://bugzilla.redhat.com/show_bug.cgi?id=2024639. The issue was reported and patches reviewed by Qualys Team. Mauro Matteo Cascella and Riccardo Schirone from Red Hat handled the disclosure. [fbui: adjust context] [fbui: fixes CVE-2021-3997] [fbui: fixes bsc#1194178] --- src/shared/rm-rf.c | 159 +++++++++++++++++++++++++++++++-------------- 1 file changed, 112 insertions(+), 47 deletions(-) diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index c7d3b8b7ad..58da213e9f 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -52,7 +52,6 @@ static int patch_dirfd_mode( } int unlinkat_harder(int dfd, const char *filename, int unlink_flags, RemoveFlags remove_flags) { - mode_t old_mode; int r; @@ -116,12 +115,13 @@ int fstatat_harder(int dfd, return 0; } -static int rm_rf_children_inner( +static int rm_rf_inner_child( int fd, const char *fname, int is_dir, RemoveFlags flags, - const struct stat *root_dev) { + const struct stat *root_dev, + bool allow_recursion) { struct stat st; int r, q = 0; @@ -141,9 +141,7 @@ static int rm_rf_children_inner( } if (is_dir) { - _cleanup_close_ int subdir_fd = -1; - - /* if root_dev is set, remove subdirectories only if device is same */ + /* If root_dev is set, remove subdirectories only if device is same */ if (root_dev && st.st_dev != root_dev->st_dev) return 0; @@ -155,7 +153,6 @@ static int rm_rf_children_inner( return 0; if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) { - /* This could be a subvolume, try to remove it */ r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); @@ -169,13 +166,16 @@ static int rm_rf_children_inner( return 1; } - subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (!allow_recursion) + return -EISDIR; + + int subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); if (subdir_fd < 0) return -errno; /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type * again for each directory */ - q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev); + q = rm_rf_children(subdir_fd, flags | REMOVE_PHYSICAL, root_dev); } else if (flags & REMOVE_ONLY_DIRECTORIES) return 0; @@ -188,63 +188,128 @@ static int rm_rf_children_inner( return 1; } +typedef struct TodoEntry { + DIR *dir; /* A directory that we were operating on. */ + char *dirname; /* The filename of that directory itself. */ +} TodoEntry; + +static void free_todo_entries(TodoEntry **todos) { + for (TodoEntry *x = *todos; x && x->dir; x++) { + closedir(x->dir); + free(x->dirname); + } + + freep(todos); +} + int rm_rf_children( int fd, RemoveFlags flags, const struct stat *root_dev) { - _cleanup_closedir_ DIR *d = NULL; + _cleanup_(free_todo_entries) TodoEntry *todos = NULL; struct dirent *de; + size_t n_todo = 0; + _cleanup_free_ char *dirname = NULL; /* Set when we are recursing and want to delete ourselves */ int ret = 0, r; - assert(fd >= 0); + /* Return the first error we run into, but nevertheless try to go on. + * The passed fd is closed in all cases, including on failure. */ + + for (;;) { /* This loop corresponds to the directory nesting level. */ + _cleanup_closedir_ DIR *d = NULL; + + if (n_todo > 0) { + /* We know that we are in recursion here, because n_todo is set. + * We need to remove the inner directory we were operating on. */ + assert(dirname); + r = unlinkat_harder(dirfd(todos[n_todo-1].dir), dirname, AT_REMOVEDIR, flags); + if (r < 0 && r != -ENOENT && ret == 0) + ret = r; + dirname = mfree(dirname); + + /* And now let's back out one level up */ + n_todo --; + d = TAKE_PTR(todos[n_todo].dir); + dirname = TAKE_PTR(todos[n_todo].dirname); + + assert(d); + fd = dirfd(d); /* Retrieve the file descriptor from the DIR object */ + assert(fd >= 0); + } else { + next_fd: + assert(fd >= 0); + d = fdopendir(fd); + if (!d) { + safe_close(fd); + return -errno; + } + fd = dirfd(d); /* We donated the fd to fdopendir(). Let's make sure we sure we have + * the right descriptor even if it were to internally invalidate the + * one we passed. */ + + if (!(flags & REMOVE_PHYSICAL)) { + struct statfs sfs; + + if (fstatfs(fd, &sfs) < 0) + return -errno; + + if (is_physical_fs(&sfs)) { + /* We refuse to clean physical file systems with this call, unless + * explicitly requested. This is extra paranoia just to be sure we + * never ever remove non-state data. */ + + _cleanup_free_ char *path = NULL; + + (void) fd_get_path(fd, &path); + return log_error_errno(SYNTHETIC_ERRNO(EPERM), + "Attempted to remove disk file system under \"%s\", and we can't allow that.", + strna(path)); + } + } + } - /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed - * fd, in all cases, including on failure. */ + FOREACH_DIRENT_ALL(de, d, return -errno) { + int is_dir; - d = fdopendir(fd); - if (!d) { - safe_close(fd); - return -errno; - } + if (dot_or_dot_dot(de->d_name)) + continue; - if (!(flags & REMOVE_PHYSICAL)) { - struct statfs sfs; + is_dir = de->d_type == DT_UNKNOWN ? -1 : de->d_type == DT_DIR; - if (fstatfs(dirfd(d), &sfs) < 0) - return -errno; + r = rm_rf_inner_child(fd, de->d_name, is_dir, flags, root_dev, false); + if (r == -EISDIR) { + /* Push the current working state onto the todo list */ - if (is_physical_fs(&sfs)) { - /* We refuse to clean physical file systems with this call, unless explicitly - * requested. This is extra paranoia just to be sure we never ever remove non-state - * data. */ + if (!GREEDY_REALLOC0(todos, n_todo + 2)) + return log_oom(); - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *newdirname = strdup(de->d_name); + if (!newdirname) + return log_oom(); - (void) fd_get_path(fd, &path); - return log_error_errno(SYNTHETIC_ERRNO(EPERM), - "Attempted to remove disk file system under \"%s\", and we can't allow that.", - strna(path)); - } - } + int newfd = openat(fd, de->d_name, + O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); + if (newfd >= 0) { + todos[n_todo++] = (TodoEntry) { TAKE_PTR(d), TAKE_PTR(dirname) }; + fd = newfd; + dirname = TAKE_PTR(newdirname); - FOREACH_DIRENT_ALL(de, d, return -errno) { - int is_dir; + goto next_fd; - if (dot_or_dot_dot(de->d_name)) - continue; + } else if (errno != -ENOENT && ret == 0) + ret = -errno; - is_dir = - de->d_type == DT_UNKNOWN ? -1 : - de->d_type == DT_DIR; + } else if (r < 0 && r != -ENOENT && ret == 0) + ret = r; + } - r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev); - if (r < 0 && r != -ENOENT && ret == 0) - ret = r; - } + if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(fd) < 0 && ret >= 0) + ret = -errno; - if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(dirfd(d)) < 0 && ret >= 0) - ret = -errno; + if (n_todo == 0) + break; + } return ret; } @@ -336,5 +401,5 @@ int rm_rf_child(int fd, const char *name, RemoveFlags flags) { if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME)) return -EINVAL; - return rm_rf_children_inner(fd, name, -1, flags, NULL); + return rm_rf_inner_child(fd, name, -1, flags, NULL, true); } -- 2.31.1 ++++++ systemd-v249.7+suse.57.g523f32df57.tar.xz -> systemd-v249.7+suse.66.ga54f80116c.tar.xz ++++++ /work/SRC/openSUSE:Factory/systemd/systemd-v249.7+suse.57.g523f32df57.tar.xz /work/SRC/openSUSE:Factory/.systemd.new.1892/systemd-v249.7+suse.66.ga54f80116c.tar.xz differ: char 27, line 1