|
|
446ea3 |
From 25e2006bff1b82c4cee3d3899ed2874815e81e4a Mon Sep 17 00:00:00 2001
|
|
|
31ac43 |
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
|
|
31ac43 |
Date: Wed, 23 Jun 2021 11:46:41 +0200
|
|
|
31ac43 |
Subject: [PATCH] basic/unit-name: do not use strdupa() on a path
|
|
|
31ac43 |
|
|
|
31ac43 |
The path may have unbounded length, for example through a fuse mount.
|
|
|
31ac43 |
|
|
|
31ac43 |
CVE-2021-33910: attacked controlled alloca() leads to crash in systemd and
|
|
|
31ac43 |
ultimately a kernel panic. Systemd parses the content of /proc/self/mountinfo
|
|
|
31ac43 |
and each mountpoint is passed to mount_setup_unit(), which calls
|
|
|
31ac43 |
unit_name_path_escape() underneath. A local attacker who is able to mount a
|
|
|
31ac43 |
filesystem with a very long path can crash systemd and the whole system.
|
|
|
31ac43 |
|
|
|
31ac43 |
https://bugzilla.redhat.com/show_bug.cgi?id=1970887
|
|
|
31ac43 |
|
|
|
31ac43 |
The resulting string length is bounded by UNIT_NAME_MAX, which is 256. But we
|
|
|
31ac43 |
can't easily check the length after simplification before doing the
|
|
|
31ac43 |
simplification, which in turns uses a copy of the string we can write to.
|
|
|
31ac43 |
So we can't reject paths that are too long before doing the duplication.
|
|
|
31ac43 |
Hence the most obvious solution is to switch back to strdup(), as before
|
|
|
31ac43 |
7410616cd9dbbec97cf98d75324da5cda2b2f7a2.
|
|
|
446ea3 |
|
|
|
446ea3 |
(cherry picked from commit 441e0115646d54f080e5c3bb0ba477c892861ab9)
|
|
|
31ac43 |
---
|
|
|
31ac43 |
src/basic/unit-name.c | 13 +++++--------
|
|
|
31ac43 |
1 file changed, 5 insertions(+), 8 deletions(-)
|
|
|
31ac43 |
|
|
|
31ac43 |
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
|
|
|
446ea3 |
index 1b81fe268f..614eb8649b 100644
|
|
|
31ac43 |
--- a/src/basic/unit-name.c
|
|
|
31ac43 |
+++ b/src/basic/unit-name.c
|
|
|
31ac43 |
@@ -369,12 +369,13 @@ int unit_name_unescape(const char *f, char **ret) {
|
|
|
31ac43 |
}
|
|
|
31ac43 |
|
|
|
31ac43 |
int unit_name_path_escape(const char *f, char **ret) {
|
|
|
31ac43 |
- char *p, *s;
|
|
|
31ac43 |
+ _cleanup_free_ char *p = NULL;
|
|
|
31ac43 |
+ char *s;
|
|
|
31ac43 |
|
|
|
31ac43 |
assert(f);
|
|
|
31ac43 |
assert(ret);
|
|
|
31ac43 |
|
|
|
31ac43 |
- p = strdupa(f);
|
|
|
31ac43 |
+ p = strdup(f);
|
|
|
31ac43 |
if (!p)
|
|
|
31ac43 |
return -ENOMEM;
|
|
|
31ac43 |
|
|
|
31ac43 |
@@ -386,13 +387,9 @@ int unit_name_path_escape(const char *f, char **ret) {
|
|
|
31ac43 |
if (!path_is_normalized(p))
|
|
|
31ac43 |
return -EINVAL;
|
|
|
31ac43 |
|
|
|
31ac43 |
- /* Truncate trailing slashes */
|
|
|
31ac43 |
+ /* Truncate trailing slashes and skip leading slashes */
|
|
|
31ac43 |
delete_trailing_chars(p, "/");
|
|
|
31ac43 |
-
|
|
|
31ac43 |
- /* Truncate leading slashes */
|
|
|
31ac43 |
- p = skip_leading_chars(p, "/");
|
|
|
31ac43 |
-
|
|
|
31ac43 |
- s = unit_name_escape(p);
|
|
|
31ac43 |
+ s = unit_name_escape(skip_leading_chars(p, "/"));
|
|
|
31ac43 |
}
|
|
|
31ac43 |
if (!s)
|
|
|
31ac43 |
return -ENOMEM;
|