summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorPurushottam Choudhary <purushottamchoudhary29@gmail.com>2022-01-21 18:37:33 +0530
committerRichard Purdie <richard.purdie@linuxfoundation.org>2022-02-16 09:48:51 +0000
commit40d6918639ce8227215e716551495b90f2197dd7 (patch)
tree059ca24a7ed0d0241123874f1e269c970823957e /meta
parentbbd2561fe9a7b005295183e5ecc74d692203dee4 (diff)
downloadpoky-40d6918639ce8227215e716551495b90f2197dd7.tar.gz
systemd: Fix CVE-2021-3997
Add patches to fix CVE-2021-3997. Add additional below mentioned patches which are required to fix CVE: 1. rm-rf-optionally-fsync-after-removing-directory-tree.patch 2. rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch Link: http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz (From OE-Core rev: b7f79fbf23488b954987dfc4aa867e42bdce7fee) Signed-off-by: Purushottam Choudhary <purushottam.choudhary@kpit.com> Signed-off-by: Purushottam Choudhary <purushottamchoudhary29@gmail.com> Signed-off-by: Steve Sakoman <steve@sakoman.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r--meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch65
-rw-r--r--meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch101
-rw-r--r--meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch266
-rw-r--r--meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch35
-rw-r--r--meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch318
-rw-r--r--meta/recipes-core/systemd/systemd_244.5.bb5
6 files changed, 790 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch b/meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch
new file mode 100644
index 0000000000..341976822b
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/CVE-2021-3997-1.patch
@@ -0,0 +1,65 @@
1Backport of the following upstream commit:
2From fbb77e1e55866633c9f064e2b3bcf2b6402d962d Mon Sep 17 00:00:00 2001
3From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
4Date: Tue, 23 Nov 2021 15:55:45 +0100
5Subject: [PATCH 1/3] shared/rm_rf: refactor rm_rf_children_inner() to shorten
6 code a bit
7
8CVE: CVE-2021-3997
9Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz]
10Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com>
11---
12 src/basic/rm-rf.c | 27 +++++++++------------------
13 1 file changed, 9 insertions(+), 18 deletions(-)
14
15--- a/src/basic/rm-rf.c
16+++ b/src/basic/rm-rf.c
17@@ -34,7 +34,7 @@
18 const struct stat *root_dev) {
19
20 struct stat st;
21- int r;
22+ int r, q = 0;
23
24 assert(fd >= 0);
25 assert(fname);
26@@ -50,7 +50,6 @@
27
28 if (is_dir) {
29 _cleanup_close_ int subdir_fd = -1;
30- int q;
31
32 /* if root_dev is set, remove subdirectories only if device is same */
33 if (root_dev && st.st_dev != root_dev->st_dev)
34@@ -86,23 +85,15 @@
35 * again for each directory */
36 q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
37
38- r = unlinkat(fd, fname, AT_REMOVEDIR);
39- if (r < 0)
40- return r;
41- if (q < 0)
42- return q;
43-
44- return 1;
45-
46- } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
47- r = unlinkat(fd, fname, 0);
48- if (r < 0)
49- return r;
50-
51- return 1;
52- }
53+ } else if (flags & REMOVE_ONLY_DIRECTORIES)
54+ return 0;
55
56- return 0;
57+ r = unlinkat(fd, fname, is_dir ? AT_REMOVEDIR : 0);
58+ if (r < 0)
59+ return r;
60+ if (q < 0)
61+ return q;
62+ return 1;
63 }
64
65 int rm_rf_children(
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch b/meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch
new file mode 100644
index 0000000000..066e10fbbc
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/CVE-2021-3997-2.patch
@@ -0,0 +1,101 @@
1Backport of the following upstream commit:
2From bd0127daaaae009ade053718f7d2f297aee4acaf Mon Sep 17 00:00:00 2001
3From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
4Date: Tue, 23 Nov 2021 16:56:42 +0100
5Subject: [PATCH 2/3] shared/rm_rf: refactor rm_rf() to shorten code a bit
6
7CVE: CVE-2021-3997
8Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz]
9Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com>
10---
11 src/basic/rm-rf.c | 53 ++++++++++++++++++++--------------------------
12 1 file changed, 23 insertions(+), 30 deletions(-)
13
14--- a/src/basic/rm-rf.c
15+++ b/src/basic/rm-rf.c
16@@ -159,7 +159,7 @@
17 }
18
19 int rm_rf(const char *path, RemoveFlags flags) {
20- int fd, r;
21+ int fd, r, q = 0;
22
23 assert(path);
24
25@@ -191,49 +191,47 @@
26 }
27
28 fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
29- if (fd < 0) {
30+ if (fd >= 0) {
31+ /* We have a dir */
32+ r = rm_rf_children(fd, flags, NULL);
33+
34+ if (FLAGS_SET(flags, REMOVE_ROOT)) {
35+ q = rmdir(path);
36+ if (q < 0)
37+ q = -errno;
38+ }
39+ } else {
40 if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT)
41 return 0;
42
43 if (!IN_SET(errno, ENOTDIR, ELOOP))
44 return -errno;
45
46- if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES))
47+ if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES) || !FLAGS_SET(flags, REMOVE_ROOT))
48 return 0;
49
50- if (FLAGS_SET(flags, REMOVE_ROOT)) {
51-
52- if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
53- struct statfs s;
54-
55- if (statfs(path, &s) < 0)
56- return -errno;
57- if (is_physical_fs(&s))
58- return log_error_errno(SYNTHETIC_ERRNO(EPERM),
59- "Attempted to remove files from a disk file system under \"%s\", refusing.",
60- path);
61- }
62-
63- if (unlink(path) < 0) {
64- if (FLAGS_SET(flags, REMOVE_MISSING_OK) && errno == ENOENT)
65- return 0;
66+ if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
67+ struct statfs s;
68
69+ if (statfs(path, &s) < 0)
70 return -errno;
71- }
72+ if (is_physical_fs(&s))
73+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
74+ "Attempted to remove files from a disk file system under \"%s\", refusing.",
75+ path);
76 }
77
78- return 0;
79+ r = 0;
80+ q = unlink(path);
81+ if (q < 0)
82+ q = -errno;
83 }
84
85- r = rm_rf_children(fd, flags, NULL);
86-
87- if (FLAGS_SET(flags, REMOVE_ROOT) &&
88- rmdir(path) < 0 &&
89- r >= 0 &&
90- (!FLAGS_SET(flags, REMOVE_MISSING_OK) || errno != ENOENT))
91- r = -errno;
92-
93- return r;
94+ if (r < 0)
95+ return r;
96+ if (q < 0 && (q != -ENOENT || !FLAGS_SET(flags, REMOVE_MISSING_OK)))
97+ return q;
98+ return 0;
99 }
100
101 int rm_rf_child(int fd, const char *name, RemoveFlags flags) {
diff --git a/meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch b/meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch
new file mode 100644
index 0000000000..c96b8d9a6e
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/CVE-2021-3997-3.patch
@@ -0,0 +1,266 @@
1Backport of the following upstream commit:
2From bef8e8e577368697b2e6f85183b1dbc99e0e520f Mon Sep 17 00:00:00 2001
3From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
4Date: Tue, 30 Nov 2021 22:29:05 +0100
5Subject: [PATCH 3/3] shared/rm-rf: loop over nested directories instead of
6 instead of recursing
7
8To remove directory structures, we need to remove the innermost items first,
9and then recursively remove higher-level directories. We would recursively
10descend into directories and invoke rm_rf_children and rm_rm_children_inner.
11This is problematic when too many directories are nested.
12
13Instead, let's create a "TODO" queue. In the the queue, for each level we
14hold the DIR* object we were working on, and the name of the directory. This
15allows us to leave a partially-processed directory, and restart the removal
16loop one level down. When done with the inner directory, we use the name to
17unlinkat() it from the parent, and proceed with the removal of other items.
18
19Because the nesting is increased by one level, it is best to view this patch
20with -b/--ignore-space-change.
21
22This fixes CVE-2021-3997, https://bugzilla.redhat.com/show_bug.cgi?id=2024639.
23The issue was reported and patches reviewed by Qualys Team.
24Mauro Matteo Cascella and Riccardo Schirone from Red Hat handled the disclosure.
25
26CVE: CVE-2021-3997
27Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz]
28Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com>
29---
30 src/basic/rm-rf.c | 161 +++++++++++++++++++++++++++++++--------------
31 1 file changed, 113 insertions(+), 48 deletions(-)
32
33--- a/src/basic/rm-rf.c
34+++ b/src/basic/rm-rf.c
35@@ -26,12 +26,13 @@
36 return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
37 }
38
39-static int rm_rf_children_inner(
40+static int rm_rf_inner_child(
41 int fd,
42 const char *fname,
43 int is_dir,
44 RemoveFlags flags,
45- const struct stat *root_dev) {
46+ const struct stat *root_dev,
47+ bool allow_recursion) {
48
49 struct stat st;
50 int r, q = 0;
51@@ -49,9 +50,7 @@
52 }
53
54 if (is_dir) {
55- _cleanup_close_ int subdir_fd = -1;
56-
57- /* if root_dev is set, remove subdirectories only if device is same */
58+ /* If root_dev is set, remove subdirectories only if device is same */
59 if (root_dev && st.st_dev != root_dev->st_dev)
60 return 0;
61
62@@ -63,7 +62,6 @@
63 return 0;
64
65 if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
66-
67 /* This could be a subvolume, try to remove it */
68
69 r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
70@@ -77,13 +75,16 @@
71 return 1;
72 }
73
74- subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
75+ if (!allow_recursion)
76+ return -EISDIR;
77+
78+ int subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
79 if (subdir_fd < 0)
80 return -errno;
81
82 /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type
83 * again for each directory */
84- q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
85+ q = rm_rf_children(subdir_fd, flags | REMOVE_PHYSICAL, root_dev);
86
87 } else if (flags & REMOVE_ONLY_DIRECTORIES)
88 return 0;
89@@ -96,64 +97,128 @@
90 return 1;
91 }
92
93+typedef struct TodoEntry {
94+ DIR *dir; /* A directory that we were operating on. */
95+ char *dirname; /* The filename of that directory itself. */
96+} TodoEntry;
97+
98+static void free_todo_entries(TodoEntry **todos) {
99+ for (TodoEntry *x = *todos; x && x->dir; x++) {
100+ closedir(x->dir);
101+ free(x->dirname);
102+ }
103+
104+ freep(todos);
105+}
106+
107 int rm_rf_children(
108 int fd,
109 RemoveFlags flags,
110 const struct stat *root_dev) {
111
112- _cleanup_closedir_ DIR *d = NULL;
113- struct dirent *de;
114+ _cleanup_(free_todo_entries) TodoEntry *todos = NULL;
115+ size_t n_todo = 0, allocated = 0;
116+ _cleanup_free_ char *dirname = NULL; /* Set when we are recursing and want to delete ourselves */
117 int ret = 0, r;
118
119- assert(fd >= 0);
120+ /* Return the first error we run into, but nevertheless try to go on.
121+ * The passed fd is closed in all cases, including on failure. */
122
123- /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed
124- * fd, in all cases, including on failure. */
125+ for (;;) { /* This loop corresponds to the directory nesting level. */
126+ _cleanup_closedir_ DIR *d = NULL;
127+ struct dirent *de;
128+
129+ if (n_todo > 0) {
130+ /* We know that we are in recursion here, because n_todo is set.
131+ * We need to remove the inner directory we were operating on. */
132+ assert(dirname);
133+ r = unlinkat(dirfd(todos[n_todo-1].dir), dirname, AT_REMOVEDIR);
134+ if (r < 0 && r != -ENOENT && ret == 0)
135+ ret = r;
136+ dirname = mfree(dirname);
137+
138+ /* And now let's back out one level up */
139+ n_todo --;
140+ d = TAKE_PTR(todos[n_todo].dir);
141+ dirname = TAKE_PTR(todos[n_todo].dirname);
142+
143+ assert(d);
144+ fd = dirfd(d); /* Retrieve the file descriptor from the DIR object */
145+ assert(fd >= 0);
146+ } else {
147+ next_fd:
148+ assert(fd >= 0);
149+ d = fdopendir(fd);
150+ if (!d) {
151+ safe_close(fd);
152+ return -errno;
153+ }
154+ fd = dirfd(d); /* We donated the fd to fdopendir(). Let's make sure we sure we have
155+ * the right descriptor even if it were to internally invalidate the
156+ * one we passed. */
157+
158+ if (!(flags & REMOVE_PHYSICAL)) {
159+ struct statfs sfs;
160+
161+ if (fstatfs(fd, &sfs) < 0)
162+ return -errno;
163+
164+ if (is_physical_fs(&sfs)) {
165+ /* We refuse to clean physical file systems with this call, unless
166+ * explicitly requested. This is extra paranoia just to be sure we
167+ * never ever remove non-state data. */
168+
169+ _cleanup_free_ char *path = NULL;
170+
171+ (void) fd_get_path(fd, &path);
172+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
173+ "Attempted to remove disk file system under \"%s\", and we can't allow that.",
174+ strna(path));
175+ }
176+ }
177+ }
178
179- d = fdopendir(fd);
180- if (!d) {
181- safe_close(fd);
182- return -errno;
183- }
184+ FOREACH_DIRENT_ALL(de, d, return -errno) {
185+ int is_dir;
186
187- if (!(flags & REMOVE_PHYSICAL)) {
188- struct statfs sfs;
189+ if (dot_or_dot_dot(de->d_name))
190+ continue;
191
192- if (fstatfs(dirfd(d), &sfs) < 0)
193- return -errno;
194- }
195+ is_dir = de->d_type == DT_UNKNOWN ? -1 : de->d_type == DT_DIR;
196
197- if (is_physical_fs(&sfs)) {
198- /* We refuse to clean physical file systems with this call, unless explicitly
199- * requested. This is extra paranoia just to be sure we never ever remove non-state
200- * data. */
201-
202- _cleanup_free_ char *path = NULL;
203-
204- (void) fd_get_path(fd, &path);
205- return log_error_errno(SYNTHETIC_ERRNO(EPERM),
206- "Attempted to remove disk file system under \"%s\", and we can't allow that.",
207- strna(path));
208- }
209- }
210+ r = rm_rf_inner_child(fd, de->d_name, is_dir, flags, root_dev, false);
211+ if (r == -EISDIR) {
212+ /* Push the current working state onto the todo list */
213
214- FOREACH_DIRENT_ALL(de, d, return -errno) {
215- int is_dir;
216+ if (!GREEDY_REALLOC0(todos, allocated, n_todo + 2))
217+ return log_oom();
218
219- if (dot_or_dot_dot(de->d_name))
220- continue;
221+ _cleanup_free_ char *newdirname = strdup(de->d_name);
222+ if (!newdirname)
223+ return log_oom();
224
225- is_dir =
226- de->d_type == DT_UNKNOWN ? -1 :
227- de->d_type == DT_DIR;
228-
229- r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev);
230- if (r < 0 && r != -ENOENT && ret == 0)
231- ret = r;
232- }
233+ int newfd = openat(fd, de->d_name,
234+ O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
235+ if (newfd >= 0) {
236+ todos[n_todo++] = (TodoEntry) { TAKE_PTR(d), TAKE_PTR(dirname) };
237+ fd = newfd;
238+ dirname = TAKE_PTR(newdirname);
239+
240+ goto next_fd;
241
242- if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(dirfd(d)) < 0 && ret >= 0)
243- ret = -errno;
244+ } else if (errno != -ENOENT && ret == 0)
245+ ret = -errno;
246+
247+ } else if (r < 0 && r != -ENOENT && ret == 0)
248+ ret = r;
249+ }
250+
251+ if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(fd) < 0 && ret >= 0)
252+ ret = -errno;
253+
254+ if (n_todo == 0)
255+ break;
256+ }
257
258 return ret;
259 }
260@@ -250,5 +315,5 @@
261 if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
262 return -EINVAL;
263
264- return rm_rf_children_inner(fd, name, -1, flags, NULL);
265+ return rm_rf_inner_child(fd, name, -1, flags, NULL, true);
266 }
diff --git a/meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch b/meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch
new file mode 100644
index 0000000000..b860da008c
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/rm-rf-optionally-fsync-after-removing-directory-tree.patch
@@ -0,0 +1,35 @@
1Backport of the following upstream commit:
2From bdfe7ada0d4d66e6d6e65f2822acbb1ec230f9c2 Mon Sep 17 00:00:00 2001
3From: Lennart Poettering <lennart@poettering.net>
4Date: Tue, 5 Oct 2021 10:32:56 +0200
5Subject: [PATCH] rm-rf: optionally fsync() after removing directory tree
6
7Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz]
8Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com>
9---
10 src/basic/rm-rf.c | 3 +++
11 src/basic/rm-rf.h | 1 +
12 2 files changed, 4 insertions(+)
13
14--- a/src/basic/rm-rf.c
15+++ b/src/basic/rm-rf.c
16@@ -161,6 +161,9 @@
17 ret = r;
18 }
19
20+ if (FLAGS_SET(flags, REMOVE_SYNCFS) && syncfs(dirfd(d)) < 0 && ret >= 0)
21+ ret = -errno;
22+
23 return ret;
24 }
25
26--- a/src/basic/rm-rf.h
27+++ b/src/basic/rm-rf.h
28@@ -11,6 +11,7 @@
29 REMOVE_PHYSICAL = 1 << 2, /* If not set, only removes files on tmpfs, never physical file systems */
30 REMOVE_SUBVOLUME = 1 << 3, /* Drop btrfs subvolumes in the tree too */
31 REMOVE_MISSING_OK = 1 << 4, /* If the top-level directory is missing, ignore the ENOENT for it */
32+ REMOVE_SYNCFS = 1 << 7, /* syncfs() the root of the specified directory after removing everything in it */
33 } RemoveFlags;
34
35 int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
diff --git a/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch b/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch
new file mode 100644
index 0000000000..f80e6433c6
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch
@@ -0,0 +1,318 @@
1Backport of the following upstream commit:
2From 96906b22417c65d70933976e0ee920c70c9113a4 Mon Sep 17 00:00:00 2001
3From: Lennart Poettering <lennart@poettering.net>
4Date: Tue, 26 Jan 2021 16:30:06 +0100
5Subject: [PATCH] rm-rf: refactor rm_rf_children(), split out body of directory
6 iteration loop
7
8This splits out rm_rf_children_inner() as body of the loop. We can use
9that to implement rm_rf_child() for deleting one specific entry in a
10directory.
11
12Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/s/systemd/systemd_245.4-4ubuntu3.15.debian.tar.xz]
13Signed-off-by: Purushottam Choudhary <Purushottam.Choudhary@kpit.com>
14---
15 src/basic/rm-rf.c | 223 ++++++++++++++++++++++++++-------------------
16 src/basic/rm-rf.h | 3 +-
17 2 files changed, 131 insertions(+), 95 deletions(-)
18
19--- a/src/basic/rm-rf.c
20+++ b/src/basic/rm-rf.c
21@@ -19,138 +19,153 @@
22 #include "stat-util.h"
23 #include "string-util.h"
24
25+/* We treat tmpfs/ramfs + cgroupfs as non-physical file sytems. cgroupfs is similar to tmpfs in a way after
26+ * all: we can create arbitrary directory hierarchies in it, and hence can also use rm_rf() on it to remove
27+ * those again. */
28 static bool is_physical_fs(const struct statfs *sfs) {
29 return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
30 }
31
32-int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
33+static int rm_rf_children_inner(
34+ int fd,
35+ const char *fname,
36+ int is_dir,
37+ RemoveFlags flags,
38+ const struct stat *root_dev) {
39+
40+ struct stat st;
41+ int r;
42+
43+ assert(fd >= 0);
44+ assert(fname);
45+
46+ if (is_dir < 0 || (is_dir > 0 && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
47+
48+ r = fstatat(fd, fname, &st, AT_SYMLINK_NOFOLLOW);
49+ if (r < 0)
50+ return r;
51+
52+ is_dir = S_ISDIR(st.st_mode);
53+ }
54+
55+ if (is_dir) {
56+ _cleanup_close_ int subdir_fd = -1;
57+ int q;
58+
59+ /* if root_dev is set, remove subdirectories only if device is same */
60+ if (root_dev && st.st_dev != root_dev->st_dev)
61+ return 0;
62+
63+ /* Stop at mount points */
64+ r = fd_is_mount_point(fd, fname, 0);
65+ if (r < 0)
66+ return r;
67+ if (r > 0)
68+ return 0;
69+
70+ if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
71+
72+ /* This could be a subvolume, try to remove it */
73+
74+ r = btrfs_subvol_remove_fd(fd, fname, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
75+ if (r < 0) {
76+ if (!IN_SET(r, -ENOTTY, -EINVAL))
77+ return r;
78+
79+ /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
80+ } else
81+ /* It was a subvolume, done. */
82+ return 1;
83+ }
84+
85+ subdir_fd = openat(fd, fname, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
86+ if (subdir_fd < 0)
87+ return -errno;
88+
89+ /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file system type
90+ * again for each directory */
91+ q = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
92+
93+ r = unlinkat(fd, fname, AT_REMOVEDIR);
94+ if (r < 0)
95+ return r;
96+ if (q < 0)
97+ return q;
98+
99+ return 1;
100+
101+ } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
102+ r = unlinkat(fd, fname, 0);
103+ if (r < 0)
104+ return r;
105+
106+ return 1;
107+ }
108+
109+ return 0;
110+}
111+
112+int rm_rf_children(
113+ int fd,
114+ RemoveFlags flags,
115+ const struct stat *root_dev) {
116+
117 _cleanup_closedir_ DIR *d = NULL;
118 struct dirent *de;
119 int ret = 0, r;
120- struct statfs sfs;
121
122 assert(fd >= 0);
123
124 /* This returns the first error we run into, but nevertheless tries to go on. This closes the passed
125- * fd, in all cases, including on failure.. */
126+ * fd, in all cases, including on failure. */
127+
128+ d = fdopendir(fd);
129+ if (!d) {
130+ safe_close(fd);
131+ return -errno;
132+ }
133
134 if (!(flags & REMOVE_PHYSICAL)) {
135+ struct statfs sfs;
136
137- r = fstatfs(fd, &sfs);
138- if (r < 0) {
139- safe_close(fd);
140+ if (fstatfs(dirfd(d), &sfs) < 0)
141 return -errno;
142 }
143
144 if (is_physical_fs(&sfs)) {
145- /* We refuse to clean physical file systems with this call,
146- * unless explicitly requested. This is extra paranoia just
147- * to be sure we never ever remove non-state data. */
148+ /* We refuse to clean physical file systems with this call, unless explicitly
149+ * requested. This is extra paranoia just to be sure we never ever remove non-state
150+ * data. */
151+
152 _cleanup_free_ char *path = NULL;
153
154 (void) fd_get_path(fd, &path);
155- log_error("Attempted to remove disk file system under \"%s\", and we can't allow that.",
156- strna(path));
157-
158- safe_close(fd);
159- return -EPERM;
160+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
161+ "Attempted to remove disk file system under \"%s\", and we can't allow that.",
162+ strna(path));
163 }
164 }
165
166- d = fdopendir(fd);
167- if (!d) {
168- safe_close(fd);
169- return errno == ENOENT ? 0 : -errno;
170- }
171-
172 FOREACH_DIRENT_ALL(de, d, return -errno) {
173- bool is_dir;
174- struct stat st;
175+ int is_dir;
176
177 if (dot_or_dot_dot(de->d_name))
178 continue;
179
180- if (de->d_type == DT_UNKNOWN ||
181- (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) {
182- if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
183- if (ret == 0 && errno != ENOENT)
184- ret = -errno;
185- continue;
186- }
187-
188- is_dir = S_ISDIR(st.st_mode);
189- } else
190- is_dir = de->d_type == DT_DIR;
191-
192- if (is_dir) {
193- _cleanup_close_ int subdir_fd = -1;
194-
195- /* if root_dev is set, remove subdirectories only if device is same */
196- if (root_dev && st.st_dev != root_dev->st_dev)
197- continue;
198-
199- subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
200- if (subdir_fd < 0) {
201- if (ret == 0 && errno != ENOENT)
202- ret = -errno;
203- continue;
204- }
205-
206- /* Stop at mount points */
207- r = fd_is_mount_point(fd, de->d_name, 0);
208- if (r < 0) {
209- if (ret == 0 && r != -ENOENT)
210- ret = r;
211-
212- continue;
213- }
214- if (r > 0)
215- continue;
216-
217- if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) {
218-
219- /* This could be a subvolume, try to remove it */
220-
221- r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
222- if (r < 0) {
223- if (!IN_SET(r, -ENOTTY, -EINVAL)) {
224- if (ret == 0)
225- ret = r;
226-
227- continue;
228- }
229-
230- /* ENOTTY, then it wasn't a btrfs subvolume, continue below. */
231- } else
232- /* It was a subvolume, continue. */
233- continue;
234- }
235-
236- /* We pass REMOVE_PHYSICAL here, to avoid doing the fstatfs() to check the file
237- * system type again for each directory */
238- r = rm_rf_children(TAKE_FD(subdir_fd), flags | REMOVE_PHYSICAL, root_dev);
239- if (r < 0 && ret == 0)
240- ret = r;
241-
242- if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
243- if (ret == 0 && errno != ENOENT)
244- ret = -errno;
245- }
246-
247- } else if (!(flags & REMOVE_ONLY_DIRECTORIES)) {
248-
249- if (unlinkat(fd, de->d_name, 0) < 0) {
250- if (ret == 0 && errno != ENOENT)
251- ret = -errno;
252- }
253- }
254+ is_dir =
255+ de->d_type == DT_UNKNOWN ? -1 :
256+ de->d_type == DT_DIR;
257+
258+ r = rm_rf_children_inner(dirfd(d), de->d_name, is_dir, flags, root_dev);
259+ if (r < 0 && r != -ENOENT && ret == 0)
260+ ret = r;
261 }
262+
263 return ret;
264 }
265
266 int rm_rf(const char *path, RemoveFlags flags) {
267 int fd, r;
268- struct statfs s;
269
270 assert(path);
271
272@@ -195,9 +210,10 @@
273 if (FLAGS_SET(flags, REMOVE_ROOT)) {
274
275 if (!FLAGS_SET(flags, REMOVE_PHYSICAL)) {
276+ struct statfs s;
277+
278 if (statfs(path, &s) < 0)
279 return -errno;
280-
281 if (is_physical_fs(&s))
282 return log_error_errno(SYNTHETIC_ERRNO(EPERM),
283 "Attempted to remove files from a disk file system under \"%s\", refusing.",
284@@ -225,3 +241,22 @@
285
286 return r;
287 }
288+
289+int rm_rf_child(int fd, const char *name, RemoveFlags flags) {
290+
291+ /* Removes one specific child of the specified directory */
292+
293+ if (fd < 0)
294+ return -EBADF;
295+
296+ if (!filename_is_valid(name))
297+ return -EINVAL;
298+
299+ if ((flags & (REMOVE_ROOT|REMOVE_MISSING_OK)) != 0) /* Doesn't really make sense here, we are not supposed to remove 'fd' anyway */
300+ return -EINVAL;
301+
302+ if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
303+ return -EINVAL;
304+
305+ return rm_rf_children_inner(fd, name, -1, flags, NULL);
306+}
307--- a/src/basic/rm-rf.h
308+++ b/src/basic/rm-rf.h
309@@ -13,7 +13,8 @@
310 REMOVE_MISSING_OK = 1 << 4, /* If the top-level directory is missing, ignore the ENOENT for it */
311 } RemoveFlags;
312
313-int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
314+int rm_rf_children(int fd, RemoveFlags flags, const struct stat *root_dev);
315+int rm_rf_child(int fd, const char *name, RemoveFlags flags);
316 int rm_rf(const char *path, RemoveFlags flags);
317
318 /* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
diff --git a/meta/recipes-core/systemd/systemd_244.5.bb b/meta/recipes-core/systemd/systemd_244.5.bb
index b6f5a47d63..66446e2a7c 100644
--- a/meta/recipes-core/systemd/systemd_244.5.bb
+++ b/meta/recipes-core/systemd/systemd_244.5.bb
@@ -28,6 +28,11 @@ SRC_URI += "file://touchscreen.rules \
28 file://network-merge-link_drop-and-link_detach_from_manager.patch \ 28 file://network-merge-link_drop-and-link_detach_from_manager.patch \
29 file://network-also-drop-requests-when-link-enters-linger-state.patch \ 29 file://network-also-drop-requests-when-link-enters-linger-state.patch \
30 file://network-fix-Link-reference-counter-issue.patch \ 30 file://network-fix-Link-reference-counter-issue.patch \
31 file://rm-rf-refactor-rm-rf-children-split-out-body-of-directory.patch \
32 file://rm-rf-optionally-fsync-after-removing-directory-tree.patch \
33 file://CVE-2021-3997-1.patch \
34 file://CVE-2021-3997-2.patch \
35 file://CVE-2021-3997-3.patch \
31 " 36 "
32 37
33# patches needed by musl 38# patches needed by musl