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