| From 441e0115646d54f080e5c3bb0ba477c892861ab9 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl> |
| Date: Wed, 23 Jun 2021 11:46:41 +0200 |
| Subject: [PATCH] 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 |
| 7410616cd9dbbec97cf98d75324da5cda2b2f7a2. |
| --- |
| src/basic/unit-name.c | 13 +++++-------- |
| 1 file changed, 5 insertions(+), 8 deletions(-) |
| |
| diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c |
| index 284a773483..a22763443f 100644 |
| --- a/src/basic/unit-name.c |
| +++ b/src/basic/unit-name.c |
| @@ -378,12 +378,13 @@ int unit_name_unescape(const char *f, char **ret) { |
| } |
| |
| int unit_name_path_escape(const char *f, char **ret) { |
| - char *p, *s; |
| + _cleanup_free_ char *p = NULL; |
| + char *s; |
| |
| assert(f); |
| assert(ret); |
| |
| - p = strdupa(f); |
| + p = strdup(f); |
| if (!p) |
| return -ENOMEM; |
| |
| @@ -395,13 +396,9 @@ int unit_name_path_escape(const char *f, char **ret) { |
| if (!path_is_normalized(p)) |
| return -EINVAL; |
| |
| - /* Truncate trailing slashes */ |
| + /* Truncate trailing slashes and skip leading slashes */ |
| delete_trailing_chars(p, "/"); |
| - |
| - /* Truncate leading slashes */ |
| - p = skip_leading_chars(p, "/"); |
| - |
| - s = unit_name_escape(p); |
| + s = unit_name_escape(skip_leading_chars(p, "/")); |
| } |
| if (!s) |
| return -ENOMEM; |
| -- |
| 2.32.0.402.g57bb445576-goog |
| |