dryang / rpms / systemd

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