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