summaryrefslogtreecommitdiffstats
path: root/meta
diff options
context:
space:
mode:
authorGeorge McCollister <george.mccollister@gmail.com>2019-02-25 10:37:12 -0600
committerRichard Purdie <richard.purdie@linuxfoundation.org>2019-03-24 16:49:54 +0000
commit4c55db6d5c6f93e5fd851ed2d0c8ebc5ec043cab (patch)
tree42fc8e334fd3ecc0be5a5cbf106677e54870ccb5 /meta
parentd4e0f9252852ebfe5677d2bf0e6d70aacd7a984a (diff)
downloadpoky-4c55db6d5c6f93e5fd851ed2d0c8ebc5ec043cab.tar.gz
systemd: fix CVE-2018-6954
Apply patches to fix CVE-2018-6954 NVD description from https://nvd.nist.gov/vuln/detail/CVE-2018-6954 systemd-tmpfiles in systemd through 237 mishandles symlinks present in non-terminal path components, which allows local users to obtain ownership of arbitrary files via vectors involving creation of a directory and a file under that directory, and later replacing that directory with a symlink. This occurs even if the fs.protected_symlinks sysctl is turned on. Patches from systemd_237-3ubuntu10.13.debian. These patches shouldn't be required on newer OE releases since they use systemd v239 or higher. (From OE-Core rev: 607350d98aa4c65b71fe1f10900e205fad81d1ec) Signed-off-by: George McCollister <george.mccollister@gmail.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r--meta/recipes-core/systemd/systemd/0001-tmpfiles-don-t-resolve-pathnames-when-traversing-rec.patch643
-rw-r--r--meta/recipes-core/systemd/systemd/0002-Make-tmpfiles-safe.patch1828
-rw-r--r--meta/recipes-core/systemd/systemd_237.bb2
3 files changed, 2473 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/0001-tmpfiles-don-t-resolve-pathnames-when-traversing-rec.patch b/meta/recipes-core/systemd/systemd/0001-tmpfiles-don-t-resolve-pathnames-when-traversing-rec.patch
new file mode 100644
index 0000000000..108e4ad8b8
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/0001-tmpfiles-don-t-resolve-pathnames-when-traversing-rec.patch
@@ -0,0 +1,643 @@
1From 33dc9a280f952f503e5493ee29f6815bef29d551 Mon Sep 17 00:00:00 2001
2From: Franck Bui <fbui@suse.com>
3Date: Fri, 2 Mar 2018 17:19:32 +0100
4Subject: [PATCH] tmpfiles: don't resolve pathnames when traversing recursively
5 through directory trees
6
7Otherwise we can be fooled if one path component is replaced underneath us.
8
9The patch achieves that by always operating at file descriptor level (by using
10*at() helpers) and by making sure we do not any path resolution when traversing
11direcotry trees.
12
13However this is not always possible, for instance when listing the content of a
14directory or some operations don't provide the *at() helpers or others (such as
15fchmodat()) don't have the AT_EMPTY_PATH flag. In such cases we operate on
16/proc/self/fd/%i pseudo-symlink instead, which works the same for all kinds of
17objects and requires no checking of type beforehand.
18
19Also O_PATH flag is used when opening file objects in order to prevent
20undesired behaviors: device nodes from reacting, automounts from
21triggering, etc...
22
23Fixes: CVE-2018-6954
24
25Origin: upstream, https://github.com/systemd/systemd/commit/936f6bdb803c432578e2cdcc5f93f3bfff93aff0
26Bug: https://github.com/systemd/systemd/issues/7986
27
28Patch from:
29systemd_237-3ubuntu10.13.debian CVE-2018-6954.patch
30
31https://usn.ubuntu.com/3816-1/ states that CVE-2018-6954 doesn't
32affect Ubuntu 18.10 which uses the same version of systemd as thud
33(239).
34
35CVE: CVE-2018-6954
36Upstream-Status: Backport
37
38Signed-off-by: George McCollister <george.mccollister@gmail.com>
39---
40 src/tmpfiles/tmpfiles.c | 363 +++++++++++++++++++++++++++++++-----------------
41 1 file changed, 239 insertions(+), 124 deletions(-)
42
43diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
44index 88cc543f09..613d418eb3 100644
45--- a/src/tmpfiles/tmpfiles.c
46+++ b/src/tmpfiles/tmpfiles.c
47@@ -792,94 +792,105 @@ static bool hardlink_vulnerable(struct stat *st) {
48 return !S_ISDIR(st->st_mode) && st->st_nlink > 1 && dangerous_hardlinks();
49 }
50
51-static int path_set_perms(Item *i, const char *path) {
52- char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
53- _cleanup_close_ int fd = -1;
54- struct stat st;
55+static int fd_set_perms(Item *i, int fd, const struct stat *st) {
56+ _cleanup_free_ char *path = NULL;
57+ int r;
58
59 assert(i);
60- assert(path);
61-
62- if (!i->mode_set && !i->uid_set && !i->gid_set)
63- goto shortcut;
64-
65- /* We open the file with O_PATH here, to make the operation
66- * somewhat atomic. Also there's unfortunately no fchmodat()
67- * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
68- * O_PATH. */
69-
70- fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
71- if (fd < 0) {
72- int level = LOG_ERR, r = -errno;
73+ assert(fd);
74
75- /* Option "e" operates only on existing objects. Do not
76- * print errors about non-existent files or directories */
77- if (i->type == EMPTY_DIRECTORY && errno == ENOENT) {
78- level = LOG_DEBUG;
79- r = 0;
80- }
81-
82- log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
83+ r = fd_get_path(fd, &path);
84+ if (r < 0)
85 return r;
86- }
87
88- if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
89- return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
90+ if (!i->mode_set && !i->uid_set && !i->gid_set)
91+ goto shortcut;
92
93- if (hardlink_vulnerable(&st)) {
94+ if (hardlink_vulnerable(st)) {
95 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
96 return -EPERM;
97 }
98
99- xsprintf(fn, "/proc/self/fd/%i", fd);
100-
101 if (i->mode_set) {
102- if (S_ISLNK(st.st_mode))
103+ if (S_ISLNK(st->st_mode))
104 log_debug("Skipping mode fix for symlink %s.", path);
105 else {
106 mode_t m = i->mode;
107
108 if (i->mask_perms) {
109- if (!(st.st_mode & 0111))
110+ if (!(st->st_mode & 0111))
111 m &= ~0111;
112- if (!(st.st_mode & 0222))
113+ if (!(st->st_mode & 0222))
114 m &= ~0222;
115- if (!(st.st_mode & 0444))
116+ if (!(st->st_mode & 0444))
117 m &= ~0444;
118- if (!S_ISDIR(st.st_mode))
119+ if (!S_ISDIR(st->st_mode))
120 m &= ~07000; /* remove sticky/sgid/suid bit, unless directory */
121 }
122
123- if (m == (st.st_mode & 07777))
124- log_debug("\"%s\" has correct mode %o already.", path, st.st_mode);
125+ if (m == (st->st_mode & 07777))
126+ log_debug("\"%s\" has correct mode %o already.", path, st->st_mode);
127 else {
128+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
129+
130 log_debug("Changing \"%s\" to mode %o.", path, m);
131
132- if (chmod(fn, m) < 0)
133- return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, fn);
134+ /* fchmodat() still doesn't have AT_EMPTY_PATH flag. */
135+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
136+
137+ if (chmod(procfs_path, m) < 0)
138+ return log_error_errno(errno, "chmod() of %s via %s failed: %m", path, procfs_path);
139 }
140 }
141 }
142
143- if ((i->uid_set && i->uid != st.st_uid) ||
144- (i->gid_set && i->gid != st.st_gid)) {
145+ if ((i->uid_set && i->uid != st->st_uid) ||
146+ (i->gid_set && i->gid != st->st_gid)) {
147 log_debug("Changing \"%s\" to owner "UID_FMT":"GID_FMT,
148 path,
149 i->uid_set ? i->uid : UID_INVALID,
150 i->gid_set ? i->gid : GID_INVALID);
151
152- if (chown(fn,
153- i->uid_set ? i->uid : UID_INVALID,
154- i->gid_set ? i->gid : GID_INVALID) < 0)
155- return log_error_errno(errno, "chown() of %s via %s failed: %m", path, fn);
156+ if (fchownat(fd,
157+ "",
158+ i->uid_set ? i->uid : UID_INVALID,
159+ i->gid_set ? i->gid : GID_INVALID,
160+ AT_EMPTY_PATH) < 0)
161+ return log_error_errno(errno, "fchownat() of %s failed: %m", path);
162 }
163
164- fd = safe_close(fd);
165-
166 shortcut:
167 return label_fix(path, false, false);
168 }
169
170+static int path_set_perms(Item *i, const char *path) {
171+ _cleanup_close_ int fd = -1;
172+ struct stat st;
173+
174+ assert(i);
175+ assert(path);
176+
177+ fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
178+ if (fd < 0) {
179+ int level = LOG_ERR, r = -errno;
180+
181+ /* Option "e" operates only on existing objects. Do not
182+ * print errors about non-existent files or directories */
183+ if (i->type == EMPTY_DIRECTORY && errno == ENOENT) {
184+ level = LOG_DEBUG;
185+ r = 0;
186+ }
187+
188+ log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
189+ return r;
190+ }
191+
192+ if (fstat(fd, &st) < 0)
193+ return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
194+
195+ return fd_set_perms(i, fd, &st);
196+}
197+
198 static int parse_xattrs_from_arg(Item *i) {
199 const char *p;
200 int r;
201@@ -918,21 +929,43 @@ static int parse_xattrs_from_arg(Item *i) {
202 return 0;
203 }
204
205-static int path_set_xattrs(Item *i, const char *path) {
206+static int fd_set_xattrs(Item *i, int fd, const struct stat *st) {
207+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
208+ _cleanup_free_ char *path = NULL;
209 char **name, **value;
210+ int r;
211
212 assert(i);
213- assert(path);
214+ assert(fd);
215+
216+ r = fd_get_path(fd, &path);
217+ if (r < 0)
218+ return r;
219+
220+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
221
222 STRV_FOREACH_PAIR(name, value, i->xattrs) {
223 log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
224- if (lsetxattr(path, *name, *value, strlen(*value), 0) < 0)
225+ if (setxattr(procfs_path, *name, *value, strlen(*value), 0) < 0)
226 return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
227 *name, *value, path);
228 }
229 return 0;
230 }
231
232+static int path_set_xattrs(Item *i, const char *path) {
233+ _cleanup_close_ int fd = -1;
234+
235+ assert(i);
236+ assert(path);
237+
238+ fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH);
239+ if (fd < 0)
240+ return log_error_errno(errno, "Cannot open '%s': %m", path);
241+
242+ return fd_set_xattrs(i, fd, NULL);
243+}
244+
245 static int parse_acls_from_arg(Item *item) {
246 #if HAVE_ACL
247 int r;
248@@ -998,52 +1031,71 @@ static int path_set_acl(const char *path, const char *pretty, acl_type_t type, a
249 }
250 #endif
251
252-static int path_set_acls(Item *item, const char *path) {
253+static int fd_set_acls(Item *item, int fd, const struct stat *st) {
254 int r = 0;
255 #if HAVE_ACL
256- char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
257- _cleanup_close_ int fd = -1;
258- struct stat st;
259+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
260+ _cleanup_free_ char *path = NULL;
261
262 assert(item);
263- assert(path);
264-
265- fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
266- if (fd < 0)
267- return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
268+ assert(fd);
269+ assert(st);
270
271- if (fstatat(fd, "", &st, AT_EMPTY_PATH) < 0)
272- return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
273+ r = fd_get_path(fd, &path);
274+ if (r < 0)
275+ return r;
276
277- if (hardlink_vulnerable(&st)) {
278+ if (hardlink_vulnerable(st)) {
279 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
280 return -EPERM;
281 }
282
283- if (S_ISLNK(st.st_mode)) {
284+ if (S_ISLNK(st->st_mode)) {
285 log_debug("Skipping ACL fix for symlink %s.", path);
286 return 0;
287 }
288
289- xsprintf(fn, "/proc/self/fd/%i", fd);
290+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
291
292 if (item->acl_access)
293- r = path_set_acl(fn, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
294+ r = path_set_acl(procfs_path, path, ACL_TYPE_ACCESS, item->acl_access, item->force);
295
296 if (r == 0 && item->acl_default)
297- r = path_set_acl(fn, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
298+ r = path_set_acl(procfs_path, path, ACL_TYPE_DEFAULT, item->acl_default, item->force);
299
300 if (r > 0)
301 return -r; /* already warned */
302- else if (r == -EOPNOTSUPP) {
303+ if (r == -EOPNOTSUPP) {
304 log_debug_errno(r, "ACLs not supported by file system at %s", path);
305 return 0;
306- } else if (r < 0)
307- log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
308+ }
309+ if (r < 0)
310+ return log_error_errno(r, "ACL operation on \"%s\" failed: %m", path);
311 #endif
312 return r;
313 }
314
315+static int path_set_acls(Item *item, const char *path) {
316+ int r = 0;
317+#ifdef HAVE_ACL
318+ _cleanup_close_ int fd = -1;
319+ struct stat st;
320+
321+ assert(item);
322+ assert(path);
323+
324+ fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
325+ if (fd < 0)
326+ return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
327+
328+ if (fstat(fd, &st) < 0)
329+ return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
330+
331+ r = fd_set_acls(item, fd, &st);
332+ #endif
333+ return r;
334+ }
335+
336 #define ATTRIBUTES_ALL \
337 (FS_NOATIME_FL | \
338 FS_SYNC_FL | \
339@@ -1143,30 +1195,24 @@ static int parse_attribute_from_arg(Item *item) {
340 return 0;
341 }
342
343-static int path_set_attribute(Item *item, const char *path) {
344- _cleanup_close_ int fd = -1;
345- struct stat st;
346+static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
347+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
348+ _cleanup_close_ int procfs_fd = -1;
349+ _cleanup_free_ char *path = NULL;
350 unsigned f;
351 int r;
352
353 if (!item->attribute_set || item->attribute_mask == 0)
354 return 0;
355
356- fd = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOATIME|O_NOFOLLOW);
357- if (fd < 0) {
358- if (errno == ELOOP)
359- return log_error_errno(errno, "Skipping file attributes adjustment on symlink %s.", path);
360-
361- return log_error_errno(errno, "Cannot open '%s': %m", path);
362- }
363-
364- if (fstat(fd, &st) < 0)
365- return log_error_errno(errno, "Cannot stat '%s': %m", path);
366+ r = fd_get_path(fd, &path);
367+ if (r < 0)
368+ return r;
369
370 /* Issuing the file attribute ioctls on device nodes is not
371 * safe, as that will be delivered to the drivers, not the
372 * file system containing the device node. */
373- if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
374+ if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) {
375 log_error("Setting file flags is only supported on regular files and directories, cannot set on '%s'.", path);
376 return -EINVAL;
377 }
378@@ -1174,10 +1220,16 @@ static int path_set_attribute(Item *item, const char *path) {
379 f = item->attribute_value & item->attribute_mask;
380
381 /* Mask away directory-specific flags */
382- if (!S_ISDIR(st.st_mode))
383+ if (!S_ISDIR(st->st_mode))
384 f &= ~FS_DIRSYNC_FL;
385
386- r = chattr_fd(fd, f, item->attribute_mask);
387+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
388+
389+ procfs_fd = open(procfs_path, O_RDONLY|O_CLOEXEC|O_NOATIME);
390+ if (procfs_fd < 0)
391+ return -errno;
392+
393+ r = chattr_fd(procfs_fd, f, item->attribute_mask);
394 if (r < 0)
395 log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING,
396 r,
397@@ -1187,6 +1239,23 @@ static int path_set_attribute(Item *item, const char *path) {
398 return 0;
399 }
400
401+static int path_set_attribute(Item *item, const char *path) {
402+ _cleanup_close_ int fd = -1;
403+ struct stat st;
404+
405+ if (!item->attribute_set || item->attribute_mask == 0)
406+ return 0;
407+
408+ fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH);
409+ if (fd < 0)
410+ return log_error_errno(errno, "Cannot open '%s': %m", path);
411+
412+ if (fstat(fd, &st) < 0)
413+ return log_error_errno(errno, "Cannot stat '%s': %m", path);
414+
415+ return fd_set_attribute(item, fd, &st);
416+}
417+
418 static int write_one_file(Item *i, const char *path) {
419 _cleanup_close_ int fd = -1;
420 int flags, r = 0;
421@@ -1251,48 +1320,58 @@ done:
422 }
423
424 typedef int (*action_t)(Item *, const char *);
425+typedef int (*fdaction_t)(Item *, int fd, const struct stat *st);
426
427-static int item_do_children(Item *i, const char *path, action_t action) {
428- _cleanup_closedir_ DIR *d;
429- struct dirent *de;
430- int r = 0;
431+static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) {
432+ int r = 0, q;
433
434 assert(i);
435- assert(path);
436+ assert(fd >= 0);
437+ assert(st);
438
439 /* This returns the first error we run into, but nevertheless
440 * tries to go on */
441+ r = action(i, fd, st);
442
443- d = opendir_nomod(path);
444- if (!d)
445- return IN_SET(errno, ENOENT, ENOTDIR, ELOOP) ? 0 : -errno;
446+ if (S_ISDIR(st->st_mode)) {
447+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
448+ _cleanup_closedir_ DIR *d = NULL;
449+ struct dirent *de;
450
451- FOREACH_DIRENT_ALL(de, d, r = -errno) {
452- _cleanup_free_ char *p = NULL;
453- int q;
454+ /* The passed 'fd' was opened with O_PATH. We need to convert
455+ * it into a 'regular' fd before reading the directory content. */
456+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
457
458- if (dot_or_dot_dot(de->d_name))
459- continue;
460+ d = opendir(procfs_path);
461+ if (!d) {
462+ r = r ?: -errno;
463+ goto finish;
464+ }
465
466- p = strjoin(path, "/", de->d_name);
467- if (!p)
468- return -ENOMEM;
469+ FOREACH_DIRENT_ALL(de, d, q = -errno; goto finish) {
470+ struct stat de_st;
471+ int de_fd;
472+
473+ if (dot_or_dot_dot(de->d_name))
474+ continue;
475
476- q = action(i, p);
477- if (q < 0 && q != -ENOENT && r == 0)
478- r = q;
479+ de_fd = openat(fd, de->d_name, O_NOFOLLOW|O_CLOEXEC|O_PATH);
480+ if (de_fd >= 0 && fstat(de_fd, &de_st) >= 0)
481+ /* pass ownership of dirent fd over */
482+ q = item_do(i, de_fd, &de_st, action);
483+ else
484+ q = -errno;
485
486- if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
487- q = item_do_children(i, p, action);
488 if (q < 0 && r == 0)
489 r = q;
490 }
491 }
492-
493+finish:
494+ safe_close(fd);
495 return r;
496 }
497
498-static int glob_item(Item *i, action_t action, bool recursive) {
499+static int glob_item(Item *i, action_t action) {
500 _cleanup_globfree_ glob_t g = {
501 #ifdef GLOB_ALTDIRFUNC
502 .gl_opendir = (void *(*)(const char *)) opendir_nomod,
503@@ -1309,12 +1388,48 @@ static int glob_item(Item *i, action_t action, bool recursive) {
504 k = action(i, *fn);
505 if (k < 0 && r == 0)
506 r = k;
507+ }
508
509- if (recursive) {
510- k = item_do_children(i, *fn, action);
511- if (k < 0 && r == 0)
512- r = k;
513+ return r;
514+}
515+
516+static int glob_item_recursively(Item *i, fdaction_t action) {
517+ _cleanup_globfree_ glob_t g = {
518+ .gl_opendir = (void *(*)(const char *)) opendir_nomod,
519+ };
520+ int r = 0, k;
521+ char **fn;
522+
523+ k = safe_glob(i->path, GLOB_NOSORT|GLOB_BRACE, &g);
524+ if (k < 0 && k != -ENOENT)
525+ return log_error_errno(k, "glob(%s) failed: %m", i->path);
526+
527+ STRV_FOREACH(fn, g.gl_pathv) {
528+ _cleanup_close_ int fd = -1;
529+ struct stat st;
530+
531+ /* Make sure we won't trigger/follow file object (such as
532+ * device nodes, automounts, ...) pointed out by 'fn' with
533+ * O_PATH. Note, when O_PATH is used, flags other than
534+ * O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored. */
535+
536+ fd = open(*fn, O_CLOEXEC|O_NOFOLLOW|O_PATH);
537+ if (fd < 0) {
538+ r = r ?: -errno;
539+ continue;
540+ }
541+
542+ if (fstat(fd, &st) < 0) {
543+ r = r ?: -errno;
544+ continue;
545 }
546+
547+ k = item_do(i, fd, &st, action);
548+ if (k < 0 && r == 0)
549+ r = k;
550+
551+ /* we passed fd ownership to the previous call */
552+ fd = -1;
553 }
554
555 return r;
556@@ -1403,7 +1518,7 @@ static int create_item(Item *i) {
557 break;
558
559 case WRITE_FILE:
560- r = glob_item(i, write_one_file, false);
561+ r = glob_item(i, write_one_file);
562 if (r < 0)
563 return r;
564
565@@ -1662,49 +1777,49 @@ static int create_item(Item *i) {
566
567 case ADJUST_MODE:
568 case RELABEL_PATH:
569- r = glob_item(i, path_set_perms, false);
570+ r = glob_item(i, path_set_perms);
571 if (r < 0)
572 return r;
573 break;
574
575 case RECURSIVE_RELABEL_PATH:
576- r = glob_item(i, path_set_perms, true);
577+ r = glob_item_recursively(i, fd_set_perms);
578 if (r < 0)
579 return r;
580 break;
581
582 case SET_XATTR:
583- r = glob_item(i, path_set_xattrs, false);
584+ r = glob_item(i, path_set_xattrs);
585 if (r < 0)
586 return r;
587 break;
588
589 case RECURSIVE_SET_XATTR:
590- r = glob_item(i, path_set_xattrs, true);
591+ r = glob_item_recursively(i, fd_set_xattrs);
592 if (r < 0)
593 return r;
594 break;
595
596 case SET_ACL:
597- r = glob_item(i, path_set_acls, false);
598+ r = glob_item(i, path_set_acls);
599 if (r < 0)
600 return r;
601 break;
602
603 case RECURSIVE_SET_ACL:
604- r = glob_item(i, path_set_acls, true);
605+ r = glob_item_recursively(i, fd_set_acls);
606 if (r < 0)
607 return r;
608 break;
609
610 case SET_ATTRIBUTE:
611- r = glob_item(i, path_set_attribute, false);
612+ r = glob_item(i, path_set_attribute);
613 if (r < 0)
614 return r;
615 break;
616
617 case RECURSIVE_SET_ATTRIBUTE:
618- r = glob_item(i, path_set_attribute, true);
619+ r = glob_item_recursively(i, fd_set_attribute);
620 if (r < 0)
621 return r;
622 break;
623@@ -1754,7 +1869,7 @@ static int remove_item(Item *i) {
624 case REMOVE_PATH:
625 case TRUNCATE_DIRECTORY:
626 case RECURSIVE_REMOVE_PATH:
627- return glob_item(i, remove_item_instance, false);
628+ return glob_item(i, remove_item_instance);
629
630 default:
631 return 0;
632@@ -1828,7 +1943,7 @@ static int clean_item(Item *i) {
633 return 0;
634 case EMPTY_DIRECTORY:
635 case IGNORE_DIRECTORY_PATH:
636- return glob_item(i, clean_item_instance, false);
637+ return glob_item(i, clean_item_instance);
638 default:
639 return 0;
640 }
641--
6422.11.0
643
diff --git a/meta/recipes-core/systemd/systemd/0002-Make-tmpfiles-safe.patch b/meta/recipes-core/systemd/systemd/0002-Make-tmpfiles-safe.patch
new file mode 100644
index 0000000000..80d27c141b
--- /dev/null
+++ b/meta/recipes-core/systemd/systemd/0002-Make-tmpfiles-safe.patch
@@ -0,0 +1,1828 @@
1From fb95c890cf5116e698347c6a7bb3daeeb2d28cf9 Mon Sep 17 00:00:00 2001
2From: George McCollister <george.mccollister@gmail.com>
3Date: Thu, 21 Feb 2019 18:04:37 -0600
4Subject: [PATCH] Make tmpfiles safe
5
6In addition to backporting the changesets in #8822, this also backports
7e04fc13 (test: add tests for systemd-tmpfiles), as well as empty_to_root()
8from v239.
9
10Origin: upstream, https://github.com/systemd/systemd/pull/8822/commits
11Bug: https://github.com/systemd/systemd/issues/7986
12
13Patch from:
14systemd_237-3ubuntu10.13.debian CVE-2018-6954_2.patch
15
16https://usn.ubuntu.com/3816-1/ states that CVE-2018-6954 doesn't
17affect Ubuntu 18.10 which uses the same version of systemd as thud
18(239).
19
20CVE: CVE-2018-6954
21Upstream-Status: Backport
22
23Signed-off-by: George McCollister <george.mccollister@gmail.com>
24---
25 src/basic/btrfs-util.c | 26 +-
26 src/basic/btrfs-util.h | 1 +
27 src/basic/fileio.c | 5 +-
28 src/basic/fs-util.c | 27 +-
29 src/basic/fs-util.h | 2 +
30 src/basic/label.h | 1 +
31 src/basic/mkdir-label.c | 17 +
32 src/basic/mkdir.c | 6 +
33 src/basic/mkdir.h | 1 +
34 src/basic/path-util.c | 5 +-
35 src/basic/path-util.h | 4 +
36 src/basic/selinux-util.c | 84 +++--
37 src/basic/selinux-util.h | 1 +
38 src/basic/smack-util.c | 119 +++++--
39 src/basic/smack-util.h | 1 +
40 src/basic/stat-util.c | 11 +
41 src/basic/stat-util.h | 1 +
42 src/test/test-fs-util.c | 25 ++
43 src/tmpfiles/tmpfiles.c | 902 ++++++++++++++++++++++++++++++++---------------
44 19 files changed, 882 insertions(+), 357 deletions(-)
45
46diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
47index 19d385ab7c..26b088f52b 100644
48--- a/src/basic/btrfs-util.c
49+++ b/src/basic/btrfs-util.c
50@@ -150,8 +150,25 @@ int btrfs_is_subvol(const char *path) {
51 return btrfs_is_subvol_fd(fd);
52 }
53
54-int btrfs_subvol_make(const char *path) {
55+int btrfs_subvol_make_fd(int fd, const char *subvolume) {
56 struct btrfs_ioctl_vol_args args = {};
57+ int r;
58+
59+ assert(subvolume);
60+
61+ r = validate_subvolume_name(subvolume);
62+ if (r < 0)
63+ return r;
64+
65+ strncpy(args.name, subvolume, sizeof(args.name)-1);
66+
67+ if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
68+ return -errno;
69+
70+ return 0;
71+}
72+
73+int btrfs_subvol_make(const char *path) {
74 _cleanup_close_ int fd = -1;
75 const char *subvolume;
76 int r;
77@@ -166,12 +183,7 @@ int btrfs_subvol_make(const char *path) {
78 if (fd < 0)
79 return fd;
80
81- strncpy(args.name, subvolume, sizeof(args.name)-1);
82-
83- if (ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args) < 0)
84- return -errno;
85-
86- return 0;
87+ return btrfs_subvol_make_fd(fd, subvolume);
88 }
89
90 int btrfs_subvol_set_read_only_fd(int fd, bool b) {
91diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
92index 952b3c26da..e92687bc57 100644
93--- a/src/basic/btrfs-util.h
94+++ b/src/basic/btrfs-util.h
95@@ -84,6 +84,7 @@ int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
96 int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
97
98 int btrfs_subvol_make(const char *path);
99+int btrfs_subvol_make_fd(int fd, const char *subvolume);
100
101 int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
102 int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
103diff --git a/src/basic/fileio.c b/src/basic/fileio.c
104index 26d6174664..1c7e23332f 100644
105--- a/src/basic/fileio.c
106+++ b/src/basic/fileio.c
107@@ -1304,7 +1304,10 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
108 if (!t)
109 return -ENOMEM;
110
111- x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
112+ if (isempty(p))
113+ x = stpcpy(stpcpy(t, ".#"), extra);
114+ else
115+ x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
116
117 u = random_u64();
118 for (i = 0; i < 16; i++) {
119diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
120index a8e50d4c78..c96a8813ea 100644
121--- a/src/basic/fs-util.c
122+++ b/src/basic/fs-util.c
123@@ -465,6 +465,31 @@ int mkfifo_atomic(const char *path, mode_t mode) {
124 return 0;
125 }
126
127+int mkfifoat_atomic(int dirfd, const char *path, mode_t mode) {
128+ _cleanup_free_ char *t = NULL;
129+ int r;
130+
131+ assert(path);
132+
133+ if (path_is_absolute(path))
134+ return mkfifo_atomic(path, mode);
135+
136+ /* We're only interested in the (random) filename. */
137+ r = tempfn_random_child("", NULL, &t);
138+ if (r < 0)
139+ return r;
140+
141+ if (mkfifoat(dirfd, t, mode) < 0)
142+ return -errno;
143+
144+ if (renameat(dirfd, t, dirfd, path) < 0) {
145+ unlink_noerrno(t);
146+ return -errno;
147+ }
148+
149+ return 0;
150+}
151+
152 int get_files_in_directory(const char *path, char ***list) {
153 _cleanup_closedir_ DIR *d = NULL;
154 struct dirent *de;
155@@ -808,7 +833,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
156 fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0)
157 return -EREMOTE;
158
159- if (S_ISLNK(st.st_mode)) {
160+ if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
161 char *joined;
162
163 _cleanup_free_ char *destination = NULL;
164diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
165index 9c4b02eccd..121345e74d 100644
166--- a/src/basic/fs-util.h
167+++ b/src/basic/fs-util.h
168@@ -80,6 +80,7 @@ int symlink_idempotent(const char *from, const char *to);
169 int symlink_atomic(const char *from, const char *to);
170 int mknod_atomic(const char *path, mode_t mode, dev_t dev);
171 int mkfifo_atomic(const char *path, mode_t mode);
172+int mkfifoat_atomic(int dir_fd, const char *path, mode_t mode);
173
174 int get_files_in_directory(const char *path, char ***list);
175
176@@ -106,6 +107,7 @@ enum {
177 CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */
178 CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */
179 CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */
180+ CHASE_NOFOLLOW = 1U << 7, /* Only valid with CHASE_OPEN: when the path's right-most component refers to symlink return O_PATH fd of the symlink, rather than following it. */
181 };
182
183 int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
184diff --git a/src/basic/label.h b/src/basic/label.h
185index d73dacec4f..3ecfed72c6 100644
186--- a/src/basic/label.h
187+++ b/src/basic/label.h
188@@ -26,6 +26,7 @@
189 int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs);
190
191 int mkdir_label(const char *path, mode_t mode);
192+int mkdirat_label(int dirfd, const char *path, mode_t mode);
193 int symlink_label(const char *old_path, const char *new_path);
194
195 int btrfs_subvol_make_label(const char *path);
196diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c
197index 6f3a46f467..3c1a227bfa 100644
198--- a/src/basic/mkdir-label.c
199+++ b/src/basic/mkdir-label.c
200@@ -47,6 +47,23 @@ int mkdir_label(const char *path, mode_t mode) {
201 return mac_smack_fix(path, false, false);
202 }
203
204+int mkdirat_label(int dirfd, const char *path, mode_t mode) {
205+ int r;
206+
207+ assert(path);
208+
209+ r = mac_selinux_create_file_prepare_at(dirfd, path, S_IFDIR);
210+ if (r < 0)
211+ return r;
212+
213+ r = mkdirat_errno_wrapper(dirfd, path, mode);
214+ mac_selinux_create_file_clear();
215+ if (r < 0)
216+ return r;
217+
218+ return mac_smack_fix_at(dirfd, path, false, false);
219+}
220+
221 int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) {
222 return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir_label);
223 }
224diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
225index d51518a5a7..418945ad4a 100644
226--- a/src/basic/mkdir.c
227+++ b/src/basic/mkdir.c
228@@ -77,6 +77,12 @@ int mkdir_errno_wrapper(const char *pathname, mode_t mode) {
229 return 0;
230 }
231
232+int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) {
233+ if (mkdirat(dirfd, pathname, mode) < 0)
234+ return -errno;
235+ return 0;
236+}
237+
238 int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) {
239 return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir_errno_wrapper);
240 }
241diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h
242index d6c2d579a3..3ec6f3ed2d 100644
243--- a/src/basic/mkdir.h
244+++ b/src/basic/mkdir.h
245@@ -24,6 +24,7 @@
246 #include <sys/types.h>
247
248 int mkdir_errno_wrapper(const char *pathname, mode_t mode);
249+int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode);
250 int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink);
251 int mkdir_parents(const char *path, mode_t mode);
252 int mkdir_p(const char *path, mode_t mode);
253diff --git a/src/basic/path-util.c b/src/basic/path-util.c
254index df94629385..84404f7ee1 100644
255--- a/src/basic/path-util.c
256+++ b/src/basic/path-util.c
257@@ -127,10 +127,7 @@ int path_make_absolute_cwd(const char *p, char **ret) {
258 if (r < 0)
259 return r;
260
261- if (endswith(cwd, "/"))
262- c = strjoin(cwd, p);
263- else
264- c = strjoin(cwd, "/", p);
265+ c = path_join(NULL, cwd, p);
266 }
267 if (!c)
268 return -ENOMEM;
269diff --git a/src/basic/path-util.h b/src/basic/path-util.h
270index 89c285e076..1094baca12 100644
271--- a/src/basic/path-util.h
272+++ b/src/basic/path-util.h
273@@ -156,3 +156,7 @@ static inline const char *skip_dev_prefix(const char *p) {
274
275 return e ?: p;
276 }
277+static inline const char *empty_to_root(const char *path) {
278+ return isempty(path) ? "/" : path;
279+}
280+
281diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
282index 0c6e99b1d7..bdef7d148b 100644
283--- a/src/basic/selinux-util.c
284+++ b/src/basic/selinux-util.c
285@@ -34,6 +34,7 @@
286 #endif
287
288 #include "alloc-util.h"
289+#include "fd-util.h"
290 #include "log.h"
291 #include "macro.h"
292 #include "path-util.h"
293@@ -311,48 +312,89 @@ char* mac_selinux_free(char *label) {
294 return NULL;
295 }
296
297-int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
298-
299 #if HAVE_SELINUX
300+static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) {
301 _cleanup_freecon_ char *filecon = NULL;
302+ _cleanup_free_ char *path = NULL;
303 int r;
304
305- assert(path);
306-
307- if (!label_hnd)
308- return 0;
309-
310- if (path_is_absolute(path))
311- r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
312- else {
313- _cleanup_free_ char *newpath = NULL;
314-
315- r = path_make_absolute_cwd(path, &newpath);
316- if (r < 0)
317- return r;
318-
319- r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
320- }
321+ assert(abspath);
322+ assert(path_is_absolute(abspath));
323
324+ r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
325 if (r < 0) {
326 /* No context specified by the policy? Proceed without setting it. */
327 if (errno == ENOENT)
328 return 0;
329
330- log_enforcing("Failed to determine SELinux security context for %s: %m", path);
331+ log_enforcing("Failed to determine SELinux security context for %s: %m", abspath);
332 } else {
333 if (setfscreatecon_raw(filecon) >= 0)
334 return 0; /* Success! */
335
336- log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
337+ log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, abspath);
338 }
339
340 if (security_getenforce() > 0)
341 return -errno;
342
343-#endif
344 return 0;
345 }
346+#endif
347+
348+int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
349+ int r = 0;
350+
351+#if HAVE_SELINUX
352+ _cleanup_free_ char *abspath = NULL;
353+ _cleanup_close_ int fd = -1;
354+
355+ assert(path);
356+
357+ if (!label_hnd)
358+ return 0;
359+
360+ if (!path_is_absolute(path)) {
361+ _cleanup_free_ char *p = NULL;
362+
363+ if (dirfd == AT_FDCWD)
364+ r = safe_getcwd(&p);
365+ else
366+ r = fd_get_path(dirfd, &p);
367+ if (r < 0)
368+ return r;
369+
370+ abspath = path_join(NULL, p, path);
371+ if (!abspath)
372+ return -ENOMEM;
373+
374+ path = abspath;
375+ }
376+
377+ r = selinux_create_file_prepare_abspath(path, mode);
378+#endif
379+ return r;
380+}
381+
382+int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
383+ int r = 0;
384+
385+#if HAVE_SELINUX
386+ _cleanup_free_ char *abspath = NULL;
387+
388+ assert(path);
389+
390+ if (!label_hnd)
391+ return 0;
392+
393+ r = path_make_absolute_cwd(path, &abspath);
394+ if (r < 0)
395+ return r;
396+
397+ r = selinux_create_file_prepare_abspath(abspath, mode);
398+#endif
399+ return r;
400+}
401
402 void mac_selinux_create_file_clear(void) {
403
404diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
405index 9780dca81e..84a8bf9729 100644
406--- a/src/basic/selinux-util.h
407+++ b/src/basic/selinux-util.h
408@@ -41,6 +41,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
409 char* mac_selinux_free(char *label);
410
411 int mac_selinux_create_file_prepare(const char *path, mode_t mode);
412+int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode);
413 void mac_selinux_create_file_clear(void);
414
415 int mac_selinux_create_socket_prepare(const char *label);
416diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c
417index f0018f013f..ea0af3e45f 100644
418--- a/src/basic/smack-util.c
419+++ b/src/basic/smack-util.c
420@@ -21,18 +21,21 @@
421 ***/
422
423 #include <errno.h>
424+#include <fcntl.h>
425 #include <string.h>
426 #include <sys/stat.h>
427 #include <sys/xattr.h>
428 #include <unistd.h>
429
430 #include "alloc-util.h"
431+#include "fd-util.h"
432 #include "fileio.h"
433 #include "log.h"
434 #include "macro.h"
435 #include "path-util.h"
436 #include "process-util.h"
437 #include "smack-util.h"
438+#include "stdio-util.h"
439 #include "string-table.h"
440 #include "xattr-util.h"
441
442@@ -134,59 +137,111 @@ int mac_smack_apply_pid(pid_t pid, const char *label) {
443 return r;
444 }
445
446-int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
447+static int smack_fix_fd(int fd , const char *abspath, bool ignore_erofs) {
448+ char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
449+ const char *label;
450 struct stat st;
451 int r;
452
453- assert(path);
454+ /* The caller should have done the sanity checks. */
455+ assert(abspath);
456+ assert(path_is_absolute(abspath));
457
458- if (!mac_smack_use())
459+ /* Path must be in /dev. */
460+ if (!path_startswith(abspath, "/dev"))
461 return 0;
462
463+ if (fstat(fd, &st) < 0)
464+ return -errno;
465+
466 /*
467- * Path must be in /dev and must exist
468+ * Label directories and character devices "*".
469+ * Label symlinks "_".
470+ * Don't change anything else.
471 */
472- if (!path_startswith(path, "/dev"))
473+
474+ if (S_ISDIR(st.st_mode))
475+ label = SMACK_STAR_LABEL;
476+ else if (S_ISLNK(st.st_mode))
477+ label = SMACK_FLOOR_LABEL;
478+ else if (S_ISCHR(st.st_mode))
479+ label = SMACK_STAR_LABEL;
480+ else
481 return 0;
482
483- r = lstat(path, &st);
484- if (r >= 0) {
485- const char *label;
486-
487- /*
488- * Label directories and character devices "*".
489- * Label symlinks "_".
490- * Don't change anything else.
491- */
492-
493- if (S_ISDIR(st.st_mode))
494- label = SMACK_STAR_LABEL;
495- else if (S_ISLNK(st.st_mode))
496- label = SMACK_FLOOR_LABEL;
497- else if (S_ISCHR(st.st_mode))
498- label = SMACK_STAR_LABEL;
499- else
500- return 0;
501+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
502+ if (setxattr(procfs_path, "security.SMACK64", label, strlen(label), 0) < 0) {
503+ _cleanup_free_ char *old_label = NULL;
504
505- r = lsetxattr(path, "security.SMACK64", label, strlen(label), 0);
506+ r = -errno;
507
508 /* If the FS doesn't support labels, then exit without warning */
509- if (r < 0 && errno == EOPNOTSUPP)
510+ if (r == -EOPNOTSUPP)
511+ return 0;
512+
513+ /* It the FS is read-only and we were told to ignore failures caused by that, suppress error */
514+ if (r == -EROFS && ignore_erofs)
515+ return 0;
516+
517+ /* If the old label is identical to the new one, suppress any kind of error */
518+ if (getxattr_malloc(procfs_path, "security.SMACK64", &old_label, false) >= 0 &&
519+ streq(old_label, label))
520 return 0;
521+
522+ return log_debug_errno(r, "Unable to fix SMACK label of %s: %m", abspath);
523 }
524
525- if (r < 0) {
526- /* Ignore ENOENT in some cases */
527+ return r;
528+}
529+
530+int mac_smack_fix_at(int dirfd, const char *path, bool ignore_enoent, bool ignore_erofs) {
531+ _cleanup_free_ char *p = NULL;
532+ _cleanup_close_ int fd = -1;
533+ int r;
534+
535+ assert(path);
536+
537+ if (!mac_smack_use())
538+ return 0;
539+
540+ fd = openat(dirfd, path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
541+ if (fd < 0) {
542 if (ignore_enoent && errno == ENOENT)
543 return 0;
544
545- if (ignore_erofs && errno == EROFS)
546+ return -errno;
547+ }
548+
549+ r = fd_get_path(fd, &p);
550+ if (r < 0)
551+ return r;
552+
553+ return smack_fix_fd(fd, p, ignore_erofs);
554+}
555+
556+int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
557+ _cleanup_free_ char *abspath = NULL;
558+ _cleanup_close_ int fd = -1;
559+ int r;
560+
561+ assert(path);
562+
563+ if (!mac_smack_use())
564+ return 0;
565+
566+ r = path_make_absolute_cwd(path, &abspath);
567+ if (r < 0)
568+ return r;
569+
570+ fd = open(abspath, O_NOFOLLOW|O_CLOEXEC|O_PATH);
571+ if (fd < 0) {
572+ if (ignore_enoent && errno == ENOENT)
573 return 0;
574
575- r = log_debug_errno(errno, "Unable to fix SMACK label of %s: %m", path);
576+ return -errno;
577 }
578
579- return r;
580+ return smack_fix_fd(fd, abspath, ignore_erofs);
581 }
582
583 int mac_smack_copy(const char *dest, const char *src) {
584@@ -236,6 +291,10 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
585 return 0;
586 }
587
588+int mac_smack_fix_at(int dirfd, const char *path, bool ignore_enoent, bool ignore_erofs) {
589+ return 0;
590+}
591+
592 int mac_smack_copy(const char *dest, const char *src) {
593 return 0;
594 }
595diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h
596index e4d46d7736..0c214bbbc0 100644
597--- a/src/basic/smack-util.h
598+++ b/src/basic/smack-util.h
599@@ -44,6 +44,7 @@ typedef enum SmackAttr {
600 bool mac_smack_use(void);
601
602 int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs);
603+int mac_smack_fix_at(int dirfd, const char *path, bool ignore_enoent, bool ignore_erofs);
604
605 const char* smack_attr_to_string(SmackAttr i) _const_;
606 SmackAttr smack_attr_from_string(const char *s) _pure_;
607diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
608index 3a54103f1b..801889ae5b 100644
609--- a/src/basic/stat-util.c
610+++ b/src/basic/stat-util.c
611@@ -63,6 +63,17 @@ int is_dir(const char* path, bool follow) {
612 return !!S_ISDIR(st.st_mode);
613 }
614
615+int is_dir_fd(int fd) {
616+ struct stat st;
617+ int r;
618+
619+ r = fstat(fd, &st);
620+ if (r < 0)
621+ return -errno;
622+
623+ return !!S_ISDIR(st.st_mode);
624+}
625+
626 int is_device_node(const char *path) {
627 struct stat info;
628
629diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
630index d8d3c20496..7ea68abfa3 100644
631--- a/src/basic/stat-util.h
632+++ b/src/basic/stat-util.h
633@@ -31,6 +31,7 @@
634
635 int is_symlink(const char *path);
636 int is_dir(const char *path, bool follow);
637+int is_dir_fd(int fd);
638 int is_device_node(const char *path);
639
640 int dir_is_empty(const char *path);
641diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
642index 9f3a500080..a76d6d0f8b 100644
643--- a/src/test/test-fs-util.c
644+++ b/src/test/test-fs-util.c
645@@ -40,6 +40,7 @@ static void test_chase_symlinks(void) {
646 _cleanup_free_ char *result = NULL;
647 char temp[] = "/tmp/test-chase.XXXXXX";
648 const char *top, *p, *pslash, *q, *qslash;
649+ struct stat st;
650 int r, pfd;
651
652 assert_se(mkdtemp(temp));
653@@ -288,6 +289,30 @@ static void test_chase_symlinks(void) {
654 assert_se(sd_id128_equal(a, b));
655 }
656
657+ /* Test CHASE_NOFOLLOW */
658+
659+ p = strjoina(temp, "/target");
660+ q = strjoina(temp, "/symlink");
661+ assert_se(symlink(p, q) >= 0);
662+ pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
663+ assert_se(pfd > 0);
664+ assert_se(path_equal(result, q));
665+ assert_se(fstat(pfd, &st) >= 0);
666+ assert_se(S_ISLNK(st.st_mode));
667+ result = mfree(result);
668+
669+ /* s1 -> s2 -> nonexistent */
670+ q = strjoina(temp, "/s1");
671+ assert_se(symlink("s2", q) >= 0);
672+ p = strjoina(temp, "/s2");
673+ assert_se(symlink("nonexistent", p) >= 0);
674+ pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
675+ assert_se(pfd > 0);
676+ assert_se(path_equal(result, q));
677+ assert_se(fstat(pfd, &st) >= 0);
678+ assert_se(S_ISLNK(st.st_mode));
679+ result = mfree(result);
680+
681 assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
682 }
683
684diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
685index 613d418eb3..d59ccbaa39 100644
686--- a/src/tmpfiles/tmpfiles.c
687+++ b/src/tmpfiles/tmpfiles.c
688@@ -794,6 +794,7 @@ static bool hardlink_vulnerable(struct stat *st) {
689
690 static int fd_set_perms(Item *i, int fd, const struct stat *st) {
691 _cleanup_free_ char *path = NULL;
692+ struct stat stbuf;
693 int r;
694
695 assert(i);
696@@ -806,6 +807,12 @@ static int fd_set_perms(Item *i, int fd, const struct stat *st) {
697 if (!i->mode_set && !i->uid_set && !i->gid_set)
698 goto shortcut;
699
700+ if (!st) {
701+ if (fstat(fd, &stbuf) < 0)
702+ return log_error_errno(errno, "fstat(%s) failed: %m", path);
703+ st = &stbuf;
704+ }
705+
706 if (hardlink_vulnerable(st)) {
707 log_error("Refusing to set permissions on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
708 return -EPERM;
709@@ -863,32 +870,62 @@ shortcut:
710 return label_fix(path, false, false);
711 }
712
713-static int path_set_perms(Item *i, const char *path) {
714- _cleanup_close_ int fd = -1;
715- struct stat st;
716+static int path_open_parent_safe(const char *path) {
717+ _cleanup_free_ char *dn = NULL;
718+ int fd;
719
720- assert(i);
721- assert(path);
722+ if (path_equal(path, "/") || !path_is_normalized(path)) {
723+ log_error("Failed to open parent of '%s': invalid path.", path);
724+ return -EINVAL;
725+ }
726
727- fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
728- if (fd < 0) {
729- int level = LOG_ERR, r = -errno;
730+ dn = dirname_malloc(path);
731+ if (!dn)
732+ return log_oom();
733
734- /* Option "e" operates only on existing objects. Do not
735- * print errors about non-existent files or directories */
736- if (i->type == EMPTY_DIRECTORY && errno == ENOENT) {
737- level = LOG_DEBUG;
738- r = 0;
739- }
740+ fd = chase_symlinks(dn, NULL, CHASE_OPEN|CHASE_SAFE, NULL);
741+ if (fd == -EPERM)
742+ return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
743+ if (fd < 0)
744+ return log_error_errno(fd, "Failed to validate path %s: %m", path);
745
746- log_full_errno(level, errno, "Adjusting owner and mode for %s failed: %m", path);
747- return r;
748+ return fd;
749+}
750+
751+static int path_open_safe(const char *path) {
752+ int fd;
753+
754+ /* path_open_safe() returns a file descriptor opened with O_PATH after
755+ * verifying that the path doesn't contain unsafe transitions, except
756+ * for its final component as the function does not follow symlink. */
757+
758+ assert(path);
759+
760+ if (!path_is_normalized(path)) {
761+ log_error("Failed to open invalid path '%s'.", path);
762+ return -EINVAL;
763 }
764
765- if (fstat(fd, &st) < 0)
766- return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
767+ fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_NOFOLLOW, NULL);
768+ if (fd == -EPERM)
769+ return log_error_errno(fd, "Unsafe symlinks encountered in %s, refusing.", path);
770+ if (fd < 0)
771+ return log_error_errno(fd, "Failed to validate path %s: %m", path);
772+
773+ return fd;
774+}
775+
776+static int path_set_perms(Item *i, const char *path) {
777+ _cleanup_close_ int fd = -1;
778+
779+ assert(i);
780+ assert(path);
781
782- return fd_set_perms(i, fd, &st);
783+ fd = path_open_safe(path);
784+ if (fd < 0)
785+ return fd;
786+
787+ return fd_set_perms(i, fd, NULL);
788 }
789
790 static int parse_xattrs_from_arg(Item *i) {
791@@ -959,9 +996,9 @@ static int path_set_xattrs(Item *i, const char *path) {
792 assert(i);
793 assert(path);
794
795- fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH);
796+ fd = path_open_safe(path);
797 if (fd < 0)
798- return log_error_errno(errno, "Cannot open '%s': %m", path);
799+ return fd;
800
801 return fd_set_xattrs(i, fd, NULL);
802 }
803@@ -1036,15 +1073,21 @@ static int fd_set_acls(Item *item, int fd, const struct stat *st) {
804 #if HAVE_ACL
805 char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
806 _cleanup_free_ char *path = NULL;
807+ struct stat stbuf;
808
809 assert(item);
810 assert(fd);
811- assert(st);
812
813 r = fd_get_path(fd, &path);
814 if (r < 0)
815 return r;
816
817+ if (!st) {
818+ if (fstat(fd, &stbuf) < 0)
819+ return log_error_errno(errno, "fstat(%s) failed: %m", path);
820+ st = &stbuf;
821+ }
822+
823 if (hardlink_vulnerable(st)) {
824 log_error("Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.", path);
825 return -EPERM;
826@@ -1079,19 +1122,15 @@ static int path_set_acls(Item *item, const char *path) {
827 int r = 0;
828 #ifdef HAVE_ACL
829 _cleanup_close_ int fd = -1;
830- struct stat st;
831
832 assert(item);
833 assert(path);
834
835- fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
836+ fd = path_open_safe(path);
837 if (fd < 0)
838- return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
839+ return fd;
840
841- if (fstat(fd, &st) < 0)
842- return log_error_errno(errno, "Failed to fstat() file %s: %m", path);
843-
844- r = fd_set_acls(item, fd, &st);
845+ r = fd_set_acls(item, fd, NULL);
846 #endif
847 return r;
848 }
849@@ -1199,6 +1238,7 @@ static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
850 char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
851 _cleanup_close_ int procfs_fd = -1;
852 _cleanup_free_ char *path = NULL;
853+ struct stat stbuf;
854 unsigned f;
855 int r;
856
857@@ -1209,6 +1249,12 @@ static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
858 if (r < 0)
859 return r;
860
861+ if (!st) {
862+ if (fstat(fd, &stbuf) < 0)
863+ return log_error_errno(errno, "fstat(%s) failed: %m", path);
864+ st = &stbuf;
865+ }
866+
867 /* Issuing the file attribute ioctls on device nodes is not
868 * safe, as that will be delivered to the drivers, not the
869 * file system containing the device node. */
870@@ -1241,99 +1287,558 @@ static int fd_set_attribute(Item *item, int fd, const struct stat *st) {
871
872 static int path_set_attribute(Item *item, const char *path) {
873 _cleanup_close_ int fd = -1;
874- struct stat st;
875
876 if (!item->attribute_set || item->attribute_mask == 0)
877 return 0;
878
879- fd = open(path, O_CLOEXEC|O_NOFOLLOW|O_PATH);
880+ fd = path_open_safe(path);
881 if (fd < 0)
882- return log_error_errno(errno, "Cannot open '%s': %m", path);
883-
884- if (fstat(fd, &st) < 0)
885- return log_error_errno(errno, "Cannot stat '%s': %m", path);
886+ return fd;
887
888- return fd_set_attribute(item, fd, &st);
889+ return fd_set_attribute(item, fd, NULL);
890 }
891
892 static int write_one_file(Item *i, const char *path) {
893- _cleanup_close_ int fd = -1;
894- int flags, r = 0;
895- struct stat st;
896+ _cleanup_close_ int fd = -1, dir_fd = -1;
897+ char *bn;
898+ int r;
899+
900+ assert(i);
901+ assert(path);
902+ assert(i->argument);
903+ assert(i->type == WRITE_FILE);
904+
905+ /* Validate the path and keep the fd on the directory for opening the
906+ * file so we're sure that it can't be changed behind our back. */
907+ dir_fd = path_open_parent_safe(path);
908+ if (dir_fd < 0)
909+ return dir_fd;
910+
911+ bn = basename(path);
912+
913+ /* Follows symlinks */
914+ fd = openat(dir_fd, bn, O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
915+ if (fd < 0) {
916+ if (errno == ENOENT) {
917+ log_debug_errno(errno, "Not writing missing file \"%s\": %m", path);
918+ return 0;
919+ }
920+ return log_error_errno(errno, "Failed to open file \"%s\": %m", path);
921+ }
922+
923+ /* 'w' is allowed to write into any kind of files. */
924+ log_debug("Writing to \"%s\".", path);
925+
926+ r = loop_write(fd, i->argument, strlen(i->argument), false);
927+ if (r < 0)
928+ return log_error_errno(r, "Failed to write file \"%s\": %m", path);
929+
930+ return fd_set_perms(i, fd, NULL);
931+}
932+
933+static int create_file(Item *i, const char *path) {
934+ _cleanup_close_ int fd = -1, dir_fd = -1;
935+ struct stat stbuf, *st = NULL;
936+ int r = 0;
937+ char *bn;
938
939 assert(i);
940 assert(path);
941+ assert(i->type == CREATE_FILE);
942+
943+ /* 'f' operates on regular files exclusively. */
944
945- flags = i->type == CREATE_FILE ? O_CREAT|O_EXCL|O_NOFOLLOW :
946- i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC|O_NOFOLLOW : 0;
947+ /* Validate the path and keep the fd on the directory for opening the
948+ * file so we're sure that it can't be changed behind our back. */
949+ dir_fd = path_open_parent_safe(path);
950+ if (dir_fd < 0)
951+ return dir_fd;
952+
953+ bn = basename(path);
954
955 RUN_WITH_UMASK(0000) {
956 mac_selinux_create_file_prepare(path, S_IFREG);
957- fd = open(path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
958+ fd = openat(dir_fd, bn, O_CREAT|O_EXCL|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
959 mac_selinux_create_file_clear();
960 }
961
962 if (fd < 0) {
963- if (i->type == WRITE_FILE && errno == ENOENT) {
964- log_debug_errno(errno, "Not writing missing file \"%s\": %m", path);
965- return 0;
966+ /* Even on a read-only filesystem, open(2) returns EEXIST if the
967+ * file already exists. It returns EROFS only if it needs to
968+ * create the file. */
969+ if (errno != EEXIST)
970+ return log_error_errno(errno, "Failed to create file %s: %m", path);
971+
972+ /* Re-open the file. At that point it must exist since open(2)
973+ * failed with EEXIST. We still need to check if the perms/mode
974+ * need to be changed. For read-only filesystems, we let
975+ * fd_set_perms() report the error if the perms need to be
976+ * modified. */
977+ fd = openat(dir_fd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode);
978+ if (fd < 0)
979+ return log_error_errno(errno, "Failed to re-open file %s: %m", path);
980+
981+ if (fstat(fd, &stbuf) < 0)
982+ return log_error_errno(errno, "stat(%s) failed: %m", path);
983+
984+ if (!S_ISREG(stbuf.st_mode)) {
985+ log_error("%s exists and is not a regular file.", path);
986+ return -EEXIST;
987 }
988- if (i->type == CREATE_FILE && errno == EEXIST) {
989- log_debug_errno(errno, "Not writing to pre-existing file \"%s\": %m", path);
990- goto done;
991+
992+ st = &stbuf;
993+ } else {
994+
995+ log_debug("\"%s\" has been created.", path);
996+
997+ if (i->argument) {
998+ log_debug("Writing to \"%s\".", path);
999+
1000+ r = loop_write(fd, i->argument, strlen(i->argument), false);
1001+ if (r < 0)
1002+ return log_error_errno(r, "Failed to write file \"%s\": %m", path);
1003 }
1004+ }
1005
1006- r = -errno;
1007- if (!i->argument && errno == EROFS && stat(path, &st) == 0 &&
1008- (i->type == CREATE_FILE || st.st_size == 0))
1009- goto check_mode;
1010+ return fd_set_perms(i, fd, st);
1011+}
1012
1013- return log_error_errno(r, "Failed to create file %s: %m", path);
1014+static int truncate_file(Item *i, const char *path) {
1015+ _cleanup_close_ int fd = -1, dir_fd = -1;
1016+ struct stat stbuf, *st = NULL;
1017+ bool erofs = false;
1018+ int r = 0;
1019+ char *bn;
1020+
1021+ assert(i);
1022+ assert(path);
1023+ assert(i->type == TRUNCATE_FILE);
1024+
1025+ /* We want to operate on regular file exclusively especially since
1026+ * O_TRUNC is unspecified if the file is neither a regular file nor a
1027+ * fifo nor a terminal device. Therefore we first open the file and make
1028+ * sure it's a regular one before truncating it. */
1029+
1030+ /* Validate the path and keep the fd on the directory for opening the
1031+ * file so we're sure that it can't be changed behind our back. */
1032+ dir_fd = path_open_parent_safe(path);
1033+ if (dir_fd < 0)
1034+ return dir_fd;
1035+
1036+ bn = basename(path);
1037+
1038+ RUN_WITH_UMASK(0000) {
1039+ mac_selinux_create_file_prepare(path, S_IFREG);
1040+ fd = openat(dir_fd, bn, O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_CLOEXEC|O_WRONLY|O_NOCTTY, i->mode);
1041+ mac_selinux_create_file_clear();
1042 }
1043
1044- if (i->argument) {
1045- log_debug("%s to \"%s\".", i->type == CREATE_FILE ? "Appending" : "Writing", path);
1046+ if (fd < 0) {
1047+ if (errno != EROFS)
1048+ return log_error_errno(errno, "Failed to open/create file %s: %m", path);
1049
1050- r = loop_write(fd, i->argument, strlen(i->argument), false);
1051- if (r < 0)
1052- return log_error_errno(r, "Failed to write file \"%s\": %m", path);
1053- } else
1054- log_debug("\"%s\" has been created.", path);
1055+ /* On a read-only filesystem, we don't want to fail if the
1056+ * target is already empty and the perms are set. So we still
1057+ * proceed with the sanity checks and let the remaining
1058+ * operations fail with EROFS if they try to modify the target
1059+ * file. */
1060+
1061+ fd = openat(dir_fd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH, i->mode);
1062+ if (fd < 0) {
1063+ if (errno == ENOENT) {
1064+ log_error("Cannot create file %s on a read-only file system.", path);
1065+ return -EROFS;
1066+ }
1067
1068- fd = safe_close(fd);
1069+ return log_error_errno(errno, "Failed to re-open file %s: %m", path);
1070+ }
1071
1072-done:
1073- if (stat(path, &st) < 0)
1074+ erofs = true;
1075+ }
1076+
1077+ if (fstat(fd, &stbuf) < 0)
1078 return log_error_errno(errno, "stat(%s) failed: %m", path);
1079
1080- check_mode:
1081- if (!S_ISREG(st.st_mode)) {
1082- log_error("%s is not a file.", path);
1083+ if (!S_ISREG(stbuf.st_mode)) {
1084+ log_error("%s exists and is not a regular file.", path);
1085 return -EEXIST;
1086 }
1087
1088- r = path_set_perms(i, path);
1089+ if (stbuf.st_size > 0) {
1090+ if (ftruncate(fd, 0) < 0) {
1091+ r = erofs ? -EROFS : -errno;
1092+ return log_error_errno(r, "Failed to truncate file %s: %m", path);
1093+ }
1094+ } else
1095+ st = &stbuf;
1096+
1097+ log_debug("\"%s\" has been created.", path);
1098+
1099+ if (i->argument) {
1100+ log_debug("Writing to \"%s\".", path);
1101+
1102+ r = loop_write(fd, i->argument, strlen(i->argument), false);
1103+ if (r < 0) {
1104+ r = erofs ? -EROFS : r;
1105+ return log_error_errno(r, "Failed to write file %s: %m", path);
1106+ }
1107+ }
1108+
1109+ return fd_set_perms(i, fd, st);
1110+}
1111+
1112+static int copy_files(Item *i) {
1113+ _cleanup_close_ int dfd = -1, fd = -1;
1114+ char *bn;
1115+ int r;
1116+
1117+ log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
1118+
1119+ bn = basename(i->path);
1120+
1121+ /* Validate the path and use the returned directory fd for copying the
1122+ * target so we're sure that the path can't be changed behind our
1123+ * back. */
1124+ dfd = path_open_parent_safe(i->path);
1125+ if (dfd < 0)
1126+ return dfd;
1127+
1128+ r = copy_tree_at(AT_FDCWD, i->argument,
1129+ dfd, bn,
1130+ i->uid_set ? i->uid : UID_INVALID,
1131+ i->gid_set ? i->gid : GID_INVALID,
1132+ COPY_REFLINK);
1133+ if (r < 0) {
1134+ struct stat a, b;
1135+
1136+ /* If the target already exists on read-only filesystems, trying
1137+ * to create the target will not fail with EEXIST but with
1138+ * EROFS. */
1139+ if (r == -EROFS && faccessat(dfd, bn, F_OK, AT_SYMLINK_NOFOLLOW) == 0)
1140+ r = -EEXIST;
1141+
1142+ if (r != -EEXIST)
1143+ return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
1144+
1145+ if (stat(i->argument, &a) < 0)
1146+ return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
1147+
1148+ if (fstatat(dfd, bn, &b, AT_SYMLINK_NOFOLLOW) < 0)
1149+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1150+
1151+ if ((a.st_mode ^ b.st_mode) & S_IFMT) {
1152+ log_debug("Can't copy to %s, file exists already and is of different type", i->path);
1153+ return 0;
1154+ }
1155+ }
1156+
1157+ fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1158+ if (fd < 0)
1159+ return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
1160+
1161+ return fd_set_perms(i, fd, NULL);
1162+}
1163+
1164+typedef enum {
1165+ CREATION_NORMAL,
1166+ CREATION_EXISTING,
1167+ CREATION_FORCE,
1168+ _CREATION_MODE_MAX,
1169+ _CREATION_MODE_INVALID = -1
1170+} CreationMode;
1171+
1172+static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
1173+ [CREATION_NORMAL] = "Created",
1174+ [CREATION_EXISTING] = "Found existing",
1175+ [CREATION_FORCE] = "Created replacement",
1176+};
1177+
1178+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
1179+
1180+static int create_directory_or_subvolume(const char *path, mode_t mode, bool subvol) {
1181+ _cleanup_close_ int pfd = -1;
1182+ CreationMode creation;
1183+ int r;
1184+
1185+ assert(path);
1186+
1187+ pfd = path_open_parent_safe(path);
1188+ if (pfd < 0)
1189+ return pfd;
1190+
1191+ if (subvol) {
1192+ if (btrfs_is_subvol(empty_to_root(arg_root)) <= 0)
1193+
1194+ /* Don't create a subvolume unless the root directory is
1195+ * one, too. We do this under the assumption that if the
1196+ * root directory is just a plain directory (i.e. very
1197+ * light-weight), we shouldn't try to split it up into
1198+ * subvolumes (i.e. more heavy-weight). Thus, chroot()
1199+ * environments and suchlike will get a full brtfs
1200+ * subvolume set up below their tree only if they
1201+ * specifically set up a btrfs subvolume for the root
1202+ * dir too. */
1203+
1204+ subvol = false;
1205+ else {
1206+ RUN_WITH_UMASK((~mode) & 0777)
1207+ r = btrfs_subvol_make_fd(pfd, basename(path));
1208+ }
1209+ } else
1210+ r = 0;
1211+
1212+ if (!subvol || r == -ENOTTY)
1213+ RUN_WITH_UMASK(0000)
1214+ r = mkdirat_label(pfd, basename(path), mode);
1215+
1216+ if (r < 0) {
1217+ int k;
1218+
1219+ if (!IN_SET(r, -EEXIST, -EROFS))
1220+ return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", path);
1221+
1222+ k = is_dir_fd(pfd);
1223+ if (k == -ENOENT && r == -EROFS)
1224+ return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", path);
1225+ if (k < 0)
1226+ return log_error_errno(k, "Failed to check if %s exists: %m", path);
1227+ if (!k) {
1228+ log_warning("\"%s\" already exists and is not a directory.", path);
1229+ return -EEXIST;
1230+ }
1231+
1232+ creation = CREATION_EXISTING;
1233+ } else
1234+ creation = CREATION_NORMAL;
1235+
1236+ log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), path);
1237+
1238+ r = openat(pfd, basename(path), O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
1239 if (r < 0)
1240- return r;
1241+ return -errno;
1242+ return r;
1243+}
1244
1245- return 0;
1246+static int create_directory(Item *i, const char *path) {
1247+ _cleanup_close_ int fd = -1;
1248+
1249+ assert(i);
1250+ assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
1251+
1252+ fd = create_directory_or_subvolume(path, i->mode, false);
1253+ if (fd == -EEXIST)
1254+ return 0;
1255+ if (fd < 0)
1256+ return fd;
1257+
1258+ return fd_set_perms(i, fd, NULL);
1259+}
1260+
1261+static int create_subvolume(Item *i, const char *path) {
1262+ _cleanup_close_ int fd = -1;
1263+ int r, q = 0;
1264+
1265+ assert(i);
1266+ assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
1267+
1268+ fd = create_directory_or_subvolume(path, i->mode, true);
1269+ if (fd == -EEXIST)
1270+ return 0;
1271+ if (fd < 0)
1272+ return fd;
1273+
1274+ if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
1275+ r = btrfs_subvol_auto_qgroup_fd(fd, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
1276+ if (r == -ENOTTY)
1277+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
1278+ else if (r == -EROFS)
1279+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
1280+ else if (r == -ENOPROTOOPT)
1281+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
1282+ else if (r < 0)
1283+ q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
1284+ else if (r > 0)
1285+ log_debug("Adjusted quota for subvolume \"%s\".", i->path);
1286+ else if (r == 0)
1287+ log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
1288+ }
1289+
1290+ r = fd_set_perms(i, fd, NULL);
1291+ if (q < 0)
1292+ return q;
1293+
1294+ return r;
1295+}
1296+
1297+static int empty_directory(Item *i, const char *path) {
1298+ int r;
1299+
1300+ assert(i);
1301+ assert(i->type == EMPTY_DIRECTORY);
1302+
1303+ r = is_dir(path, false);
1304+ if (r == -ENOENT) {
1305+ /* Option "e" operates only on existing objects. Do not
1306+ * print errors about non-existent files or directories */
1307+ log_debug("Skipping missing directory: %s", path);
1308+ return 0;
1309+ }
1310+ if (r < 0)
1311+ return log_error_errno(r, "is_dir() failed on path %s: %m", path);
1312+
1313+ return path_set_perms(i, path);
1314+}
1315+
1316+static int create_device(Item *i, mode_t file_type) {
1317+ _cleanup_close_ int dfd = -1, fd = -1;
1318+ CreationMode creation;
1319+ char *bn;
1320+ int r;
1321+
1322+ assert(i);
1323+ assert(IN_SET(file_type, S_IFBLK, S_IFCHR));
1324+
1325+ bn = basename(i->path);
1326+
1327+ /* Validate the path and use the returned directory fd for copying the
1328+ * target so we're sure that the path can't be changed behind our
1329+ * back. */
1330+ dfd = path_open_parent_safe(i->path);
1331+ if (dfd < 0)
1332+ return dfd;
1333+
1334+ RUN_WITH_UMASK(0000) {
1335+ mac_selinux_create_file_prepare(i->path, file_type);
1336+ r = mknodat(dfd, bn, i->mode | file_type, i->major_minor);
1337+ mac_selinux_create_file_clear();
1338+ }
1339+
1340+ if (r < 0) {
1341+ struct stat st;
1342+
1343+ if (errno == EPERM) {
1344+ log_debug("We lack permissions, possibly because of cgroup configuration; "
1345+ "skipping creation of device node %s.", i->path);
1346+ return 0;
1347+ }
1348+
1349+ if (errno != EEXIST)
1350+ return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1351+
1352+ if (fstatat(dfd, bn, &st, 0) < 0)
1353+ return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1354+
1355+ if ((st.st_mode & S_IFMT) != file_type) {
1356+
1357+ if (i->force) {
1358+
1359+ RUN_WITH_UMASK(0000) {
1360+ mac_selinux_create_file_prepare(i->path, file_type);
1361+ /* FIXME: need to introduce mknodat_atomic() */
1362+ r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1363+ mac_selinux_create_file_clear();
1364+ }
1365+
1366+ if (r < 0)
1367+ return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1368+ creation = CREATION_FORCE;
1369+ } else {
1370+ log_debug("%s is not a device node.", i->path);
1371+ return 0;
1372+ }
1373+ } else
1374+ creation = CREATION_EXISTING;
1375+ } else
1376+ creation = CREATION_NORMAL;
1377+
1378+ log_debug("%s %s device node \"%s\" %u:%u.",
1379+ creation_mode_verb_to_string(creation),
1380+ i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1381+ i->path, major(i->mode), minor(i->mode));
1382+
1383+ fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1384+ if (fd < 0)
1385+ return log_error_errno(errno, "Failed to openat(%s): %m", i->path);
1386+
1387+ return fd_set_perms(i, fd, NULL);
1388+}
1389+
1390+static int create_fifo(Item *i, const char *path) {
1391+ _cleanup_close_ int pfd = -1, fd = -1;
1392+ CreationMode creation;
1393+ struct stat st;
1394+ char *bn;
1395+ int r;
1396+
1397+ pfd = path_open_parent_safe(path);
1398+ if (pfd < 0)
1399+ return pfd;
1400+
1401+ bn = basename(path);
1402+
1403+ RUN_WITH_UMASK(0000) {
1404+ mac_selinux_create_file_prepare(path, S_IFIFO);
1405+ r = mkfifoat(pfd, bn, i->mode);
1406+ mac_selinux_create_file_clear();
1407+ }
1408+
1409+ if (r < 0) {
1410+ if (errno != EEXIST)
1411+ return log_error_errno(errno, "Failed to create fifo %s: %m", path);
1412+
1413+ if (fstatat(pfd, bn, &st, AT_SYMLINK_NOFOLLOW) < 0)
1414+ return log_error_errno(errno, "stat(%s) failed: %m", path);
1415+
1416+ if (!S_ISFIFO(st.st_mode)) {
1417+
1418+ if (i->force) {
1419+ RUN_WITH_UMASK(0000) {
1420+ mac_selinux_create_file_prepare(path, S_IFIFO);
1421+ r = mkfifoat_atomic(pfd, bn, i->mode);
1422+ mac_selinux_create_file_clear();
1423+ }
1424+
1425+ if (r < 0)
1426+ return log_error_errno(r, "Failed to create fifo %s: %m", path);
1427+ creation = CREATION_FORCE;
1428+ } else {
1429+ log_warning("\"%s\" already exists and is not a fifo.", path);
1430+ return 0;
1431+ }
1432+ } else
1433+ creation = CREATION_EXISTING;
1434+ } else
1435+ creation = CREATION_NORMAL;
1436+
1437+ log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), path);
1438+
1439+ fd = openat(pfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1440+ if (fd < 0)
1441+ return log_error_errno(fd, "Failed to openat(%s): %m", path);
1442+
1443+ return fd_set_perms(i, fd, NULL);
1444 }
1445
1446 typedef int (*action_t)(Item *, const char *);
1447 typedef int (*fdaction_t)(Item *, int fd, const struct stat *st);
1448
1449-static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) {
1450+static int item_do(Item *i, int fd, fdaction_t action) {
1451+ struct stat st;
1452 int r = 0, q;
1453
1454 assert(i);
1455 assert(fd >= 0);
1456- assert(st);
1457+
1458+ if (fstat(fd, &st) < 0) {
1459+ r = -errno;
1460+ goto finish;
1461+ }
1462
1463 /* This returns the first error we run into, but nevertheless
1464 * tries to go on */
1465- r = action(i, fd, st);
1466+ r = action(i, fd, &st);
1467
1468- if (S_ISDIR(st->st_mode)) {
1469+ if (S_ISDIR(st.st_mode)) {
1470 char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
1471 _cleanup_closedir_ DIR *d = NULL;
1472 struct dirent *de;
1473@@ -1349,16 +1854,15 @@ static int item_do(Item *i, int fd, const struct stat *st, fdaction_t action) {
1474 }
1475
1476 FOREACH_DIRENT_ALL(de, d, q = -errno; goto finish) {
1477- struct stat de_st;
1478 int de_fd;
1479
1480 if (dot_or_dot_dot(de->d_name))
1481 continue;
1482
1483 de_fd = openat(fd, de->d_name, O_NOFOLLOW|O_CLOEXEC|O_PATH);
1484- if (de_fd >= 0 && fstat(de_fd, &de_st) >= 0)
1485+ if (de_fd >= 0)
1486 /* pass ownership of dirent fd over */
1487- q = item_do(i, de_fd, &de_st, action);
1488+ q = item_do(i, de_fd, action);
1489 else
1490 q = -errno;
1491
1492@@ -1406,7 +1910,6 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
1493
1494 STRV_FOREACH(fn, g.gl_pathv) {
1495 _cleanup_close_ int fd = -1;
1496- struct stat st;
1497
1498 /* Make sure we won't trigger/follow file object (such as
1499 * device nodes, automounts, ...) pointed out by 'fn' with
1500@@ -1419,12 +1922,7 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
1501 continue;
1502 }
1503
1504- if (fstat(fd, &st) < 0) {
1505- r = r ?: -errno;
1506- continue;
1507- }
1508-
1509- k = item_do(i, fd, &st, action);
1510+ k = item_do(i, fd, action);
1511 if (k < 0 && r == 0)
1512 r = k;
1513
1514@@ -1435,27 +1933,9 @@ static int glob_item_recursively(Item *i, fdaction_t action) {
1515 return r;
1516 }
1517
1518-typedef enum {
1519- CREATION_NORMAL,
1520- CREATION_EXISTING,
1521- CREATION_FORCE,
1522- _CREATION_MODE_MAX,
1523- _CREATION_MODE_INVALID = -1
1524-} CreationMode;
1525-
1526-static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
1527- [CREATION_NORMAL] = "Created",
1528- [CREATION_EXISTING] = "Found existing",
1529- [CREATION_FORCE] = "Created replacement",
1530-};
1531-
1532-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
1533-
1534 static int create_item(Item *i) {
1535- struct stat st;
1536- int r = 0;
1537- int q = 0;
1538 CreationMode creation;
1539+ int r = 0;
1540
1541 assert(i);
1542
1543@@ -1470,51 +1950,31 @@ static int create_item(Item *i) {
1544 return 0;
1545
1546 case CREATE_FILE:
1547- case TRUNCATE_FILE:
1548 RUN_WITH_UMASK(0000)
1549 (void) mkdir_parents_label(i->path, 0755);
1550
1551- r = write_one_file(i, i->path);
1552+ r = create_file(i, i->path);
1553 if (r < 0)
1554 return r;
1555 break;
1556
1557- case COPY_FILES: {
1558-
1559+ case TRUNCATE_FILE:
1560 RUN_WITH_UMASK(0000)
1561 (void) mkdir_parents_label(i->path, 0755);
1562
1563- log_debug("Copying tree \"%s\" to \"%s\".", i->argument, i->path);
1564- r = copy_tree(i->argument, i->path,
1565- i->uid_set ? i->uid : UID_INVALID,
1566- i->gid_set ? i->gid : GID_INVALID,
1567- COPY_REFLINK);
1568-
1569- if (r == -EROFS && stat(i->path, &st) == 0)
1570- r = -EEXIST;
1571-
1572- if (r < 0) {
1573- struct stat a, b;
1574-
1575- if (r != -EEXIST)
1576- return log_error_errno(r, "Failed to copy files to %s: %m", i->path);
1577-
1578- if (stat(i->argument, &a) < 0)
1579- return log_error_errno(errno, "stat(%s) failed: %m", i->argument);
1580+ r = truncate_file(i, i->path);
1581+ if (r < 0)
1582+ return r;
1583+ break;
1584
1585- if (stat(i->path, &b) < 0)
1586- return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1587+ case COPY_FILES: {
1588
1589- if ((a.st_mode ^ b.st_mode) & S_IFMT) {
1590- log_debug("Can't copy to %s, file exists already and is of different type", i->path);
1591- return 0;
1592- }
1593- }
1594+ RUN_WITH_UMASK(0000)
1595+ (void) mkdir_parents_label(i->path, 0755);
1596
1597- r = path_set_perms(i, i->path);
1598+ r = copy_files(i);
1599 if (r < 0)
1600 return r;
1601-
1602 break;
1603
1604 case WRITE_FILE:
1605@@ -1526,132 +1986,39 @@ static int create_item(Item *i) {
1606
1607 case CREATE_DIRECTORY:
1608 case TRUNCATE_DIRECTORY:
1609+ RUN_WITH_UMASK(0000)
1610+ (void) mkdir_parents_label(i->path, 0755);
1611+
1612+ r = create_directory(i, i->path);
1613+ if (r < 0)
1614+ return r;
1615+ break;
1616+
1617 case CREATE_SUBVOLUME:
1618 case CREATE_SUBVOLUME_INHERIT_QUOTA:
1619 case CREATE_SUBVOLUME_NEW_QUOTA:
1620 RUN_WITH_UMASK(0000)
1621 (void) mkdir_parents_label(i->path, 0755);
1622
1623- if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
1624-
1625- if (btrfs_is_subvol(isempty(arg_root) ? "/" : arg_root) <= 0)
1626-
1627- /* Don't create a subvolume unless the
1628- * root directory is one, too. We do
1629- * this under the assumption that if
1630- * the root directory is just a plain
1631- * directory (i.e. very light-weight),
1632- * we shouldn't try to split it up
1633- * into subvolumes (i.e. more
1634- * heavy-weight). Thus, chroot()
1635- * environments and suchlike will get
1636- * a full brtfs subvolume set up below
1637- * their tree only if they
1638- * specifically set up a btrfs
1639- * subvolume for the root dir too. */
1640-
1641- r = -ENOTTY;
1642- else {
1643- RUN_WITH_UMASK((~i->mode) & 0777)
1644- r = btrfs_subvol_make(i->path);
1645- }
1646- } else
1647- r = 0;
1648-
1649- if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
1650- RUN_WITH_UMASK(0000)
1651- r = mkdir_label(i->path, i->mode);
1652-
1653- if (r < 0) {
1654- int k;
1655-
1656- if (!IN_SET(r, -EEXIST, -EROFS))
1657- return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", i->path);
1658-
1659- k = is_dir(i->path, false);
1660- if (k == -ENOENT && r == -EROFS)
1661- return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", i->path);
1662- if (k < 0)
1663- return log_error_errno(k, "Failed to check if %s exists: %m", i->path);
1664- if (!k) {
1665- log_warning("\"%s\" already exists and is not a directory.", i->path);
1666- return 0;
1667- }
1668-
1669- creation = CREATION_EXISTING;
1670- } else
1671- creation = CREATION_NORMAL;
1672-
1673- log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
1674-
1675- if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
1676- r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
1677- if (r == -ENOTTY)
1678- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
1679- else if (r == -EROFS)
1680- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
1681- else if (r == -ENOPROTOOPT)
1682- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
1683- else if (r < 0)
1684- q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
1685- else if (r > 0)
1686- log_debug("Adjusted quota for subvolume \"%s\".", i->path);
1687- else if (r == 0)
1688- log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
1689- }
1690+ r = create_subvolume(i, i->path);
1691+ if (r < 0)
1692+ return r;
1693+ break;
1694
1695- _fallthrough_;
1696 case EMPTY_DIRECTORY:
1697- r = path_set_perms(i, i->path);
1698- if (q < 0)
1699- return q;
1700+ r = empty_directory(i, i->path);
1701 if (r < 0)
1702 return r;
1703
1704 break;
1705
1706 case CREATE_FIFO:
1707- RUN_WITH_UMASK(0000) {
1708+ RUN_WITH_UMASK(0000)
1709 (void) mkdir_parents_label(i->path, 0755);
1710
1711- mac_selinux_create_file_prepare(i->path, S_IFIFO);
1712- r = mkfifo(i->path, i->mode);
1713- mac_selinux_create_file_clear();
1714- }
1715-
1716- if (r < 0) {
1717- if (errno != EEXIST)
1718- return log_error_errno(errno, "Failed to create fifo %s: %m", i->path);
1719-
1720- if (lstat(i->path, &st) < 0)
1721- return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1722-
1723- if (!S_ISFIFO(st.st_mode)) {
1724-
1725- if (i->force) {
1726- RUN_WITH_UMASK(0000) {
1727- mac_selinux_create_file_prepare(i->path, S_IFIFO);
1728- r = mkfifo_atomic(i->path, i->mode);
1729- mac_selinux_create_file_clear();
1730- }
1731-
1732- if (r < 0)
1733- return log_error_errno(r, "Failed to create fifo %s: %m", i->path);
1734- creation = CREATION_FORCE;
1735- } else {
1736- log_warning("\"%s\" already exists and is not a fifo.", i->path);
1737- return 0;
1738- }
1739- } else
1740- creation = CREATION_EXISTING;
1741- } else
1742- creation = CREATION_NORMAL;
1743- log_debug("%s fifo \"%s\".", creation_mode_verb_to_string(creation), i->path);
1744-
1745- r = path_set_perms(i, i->path);
1746+ r = create_fifo(i, i->path);
1747 if (r < 0)
1748 return r;
1749-
1750 break;
1751 }
1752
1753@@ -1704,9 +2071,7 @@ static int create_item(Item *i) {
1754 }
1755
1756 case CREATE_BLOCK_DEVICE:
1757- case CREATE_CHAR_DEVICE: {
1758- mode_t file_type;
1759-
1760+ case CREATE_CHAR_DEVICE:
1761 if (have_effective_cap(CAP_MKNOD) == 0) {
1762 /* In a container we lack CAP_MKNOD. We
1763 shouldn't attempt to create the device node in
1764@@ -1720,60 +2085,11 @@ static int create_item(Item *i) {
1765 RUN_WITH_UMASK(0000)
1766 (void) mkdir_parents_label(i->path, 0755);
1767
1768- file_type = i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR;
1769-
1770- RUN_WITH_UMASK(0000) {
1771- mac_selinux_create_file_prepare(i->path, file_type);
1772- r = mknod(i->path, i->mode | file_type, i->major_minor);
1773- mac_selinux_create_file_clear();
1774- }
1775-
1776- if (r < 0) {
1777- if (errno == EPERM) {
1778- log_debug("We lack permissions, possibly because of cgroup configuration; "
1779- "skipping creation of device node %s.", i->path);
1780- return 0;
1781- }
1782-
1783- if (errno != EEXIST)
1784- return log_error_errno(errno, "Failed to create device node %s: %m", i->path);
1785-
1786- if (lstat(i->path, &st) < 0)
1787- return log_error_errno(errno, "stat(%s) failed: %m", i->path);
1788-
1789- if ((st.st_mode & S_IFMT) != file_type) {
1790-
1791- if (i->force) {
1792-
1793- RUN_WITH_UMASK(0000) {
1794- mac_selinux_create_file_prepare(i->path, file_type);
1795- r = mknod_atomic(i->path, i->mode | file_type, i->major_minor);
1796- mac_selinux_create_file_clear();
1797- }
1798-
1799- if (r < 0)
1800- return log_error_errno(r, "Failed to create device node \"%s\": %m", i->path);
1801- creation = CREATION_FORCE;
1802- } else {
1803- log_debug("%s is not a device node.", i->path);
1804- return 0;
1805- }
1806- } else
1807- creation = CREATION_EXISTING;
1808- } else
1809- creation = CREATION_NORMAL;
1810-
1811- log_debug("%s %s device node \"%s\" %u:%u.",
1812- creation_mode_verb_to_string(creation),
1813- i->type == CREATE_BLOCK_DEVICE ? "block" : "char",
1814- i->path, major(i->mode), minor(i->mode));
1815-
1816- r = path_set_perms(i, i->path);
1817+ r = create_device(i, i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);
1818 if (r < 0)
1819 return r;
1820
1821 break;
1822- }
1823
1824 case ADJUST_MODE:
1825 case RELABEL_PATH:
1826--
18272.11.0
1828
diff --git a/meta/recipes-core/systemd/systemd_237.bb b/meta/recipes-core/systemd/systemd_237.bb
index 96f419a7f9..bc33fbebdc 100644
--- a/meta/recipes-core/systemd/systemd_237.bb
+++ b/meta/recipes-core/systemd/systemd_237.bb
@@ -61,6 +61,8 @@ SRC_URI += "file://touchscreen.rules \
61 file://0025-journald-set-a-limit-on-the-number-of-fields-1k.patch \ 61 file://0025-journald-set-a-limit-on-the-number-of-fields-1k.patch \
62 file://0026-journal-remote-set-a-limit-on-the-number-of-fields-i.patch \ 62 file://0026-journal-remote-set-a-limit-on-the-number-of-fields-i.patch \
63 file://0027-journal-fix-out-of-bounds-read-CVE-2018-16866.patch \ 63 file://0027-journal-fix-out-of-bounds-read-CVE-2018-16866.patch \
64 file://0001-tmpfiles-don-t-resolve-pathnames-when-traversing-rec.patch \
65 file://0002-Make-tmpfiles-safe.patch \
64 " 66 "
65SRC_URI_append_qemuall = " file://0001-core-device.c-Change-the-default-device-timeout-to-2.patch" 67SRC_URI_append_qemuall = " file://0001-core-device.c-Change-the-default-device-timeout-to-2.patch"
66 68