Skip to content

Commit cfd14c6

Browse files
committed
basic/unit-name: do not use strdupa() on a path
The path may have unbounded length, for example through a fuse mount. CVE-2021-33910: attacked controlled alloca() leads to crash in systemd and ultimately a kernel panic. Systemd parses the content of /proc/self/mountinfo and each mountpoint is passed to mount_setup_unit(), which calls unit_name_path_escape() underneath. A local attacker who is able to mount a filesystem with a very long path can crash systemd and the whole system. https://bugzilla.redhat.com/show_bug.cgi?id=1970887 The resulting string length is bounded by UNIT_NAME_MAX, which is 256. But we can't easily check the length after simplification before doing the simplification, which in turns uses a copy of the string we can write to. So we can't reject paths that are too long before doing the duplication. Hence the most obvious solution is to switch back to strdup(), as before 7410616. (cherry picked from commit 441e011) (cherry picked from commit 764b741) (cherry picked from commit 4a1c5f3) (cherry picked from commit b006743)
1 parent aa29dcc commit cfd14c6

File tree

1 file changed

+5
-8
lines changed

1 file changed

+5
-8
lines changed

Diff for: src/basic/unit-name.c

+5-8
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,13 @@ int unit_name_unescape(const char *f, char **ret) {
378378
}
379379

380380
int unit_name_path_escape(const char *f, char **ret) {
381-
char *p, *s;
381+
_cleanup_free_ char *p = NULL;
382+
char *s;
382383

383384
assert(f);
384385
assert(ret);
385386

386-
p = strdupa(f);
387+
p = strdup(f);
387388
if (!p)
388389
return -ENOMEM;
389390

@@ -395,13 +396,9 @@ int unit_name_path_escape(const char *f, char **ret) {
395396
if (!path_is_normalized(p))
396397
return -EINVAL;
397398

398-
/* Truncate trailing slashes */
399+
/* Truncate trailing slashes and skip leading slashes */
399400
delete_trailing_chars(p, "/");
400-
401-
/* Truncate leading slashes */
402-
p = skip_leading_chars(p, "/");
403-
404-
s = unit_name_escape(p);
401+
s = unit_name_escape(skip_leading_chars(p, "/"));
405402
}
406403
if (!s)
407404
return -ENOMEM;

0 commit comments

Comments
 (0)