ryantimwilson / rpms / systemd

Forked from rpms/systemd a month ago
Clone
Zbigniew Jędrzejewski-Szmek a142c8
From 34b9eddfc12936917fab000b780a451d6277c2b4 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek a142c8
From: Siddhesh Poyarekar <siddhesh@gotplt.org>
Zbigniew Jędrzejewski-Szmek a142c8
Date: Tue, 13 Dec 2022 16:54:36 -0500
Zbigniew Jędrzejewski-Szmek a142c8
Subject: [PATCH 4/5] Use dummy allocator to make accesses defined as per
Zbigniew Jędrzejewski-Szmek a142c8
 standard
Zbigniew Jędrzejewski-Szmek a142c8
Zbigniew Jędrzejewski-Szmek a142c8
systemd uses malloc_usable_size() everywhere to use memory blocks
Zbigniew Jędrzejewski-Szmek a142c8
obtained through malloc, but that is abuse since the
Zbigniew Jędrzejewski-Szmek a142c8
malloc_usable_size() interface isn't meant for this kind of use, it is
Zbigniew Jędrzejewski-Szmek a142c8
for diagnostics only.  This is also why systemd behaviour is flaky when
Zbigniew Jędrzejewski-Szmek a142c8
built with _FORTIFY_SOURCE.
Zbigniew Jędrzejewski-Szmek a142c8
Zbigniew Jędrzejewski-Szmek a142c8
One way to make this more standard (and hence safer) is to, at every
Zbigniew Jędrzejewski-Szmek a142c8
malloc_usable_size() call, also 'reallocate' the block so that the
Zbigniew Jędrzejewski-Szmek a142c8
compiler can see the larger size.  This is done through a dummy
Zbigniew Jędrzejewski-Szmek a142c8
reallocator whose only purpose is to tell the compiler about the larger
Zbigniew Jędrzejewski-Szmek a142c8
usable size, it doesn't do any actual reallocation.
Zbigniew Jędrzejewski-Szmek a142c8
Zbigniew Jędrzejewski-Szmek a142c8
Florian Weimer pointed out that this doesn't solve the problem of an
Zbigniew Jędrzejewski-Szmek a142c8
allocator potentially growing usable size at will, which will break the
Zbigniew Jędrzejewski-Szmek a142c8
implicit assumption in systemd use that the value returned remains
Zbigniew Jędrzejewski-Szmek a142c8
constant as long as the object is valid.  The safest way to fix that is
Zbigniew Jędrzejewski-Szmek a142c8
for systemd to step away from using malloc_usable_size() like this.
Zbigniew Jędrzejewski-Szmek a142c8
Zbigniew Jędrzejewski-Szmek a142c8
Resolves #22801.
Zbigniew Jędrzejewski-Szmek a142c8
Zbigniew Jędrzejewski-Szmek a142c8
(cherry picked from commit 7929e180aa47a2692ad4f053afac2857d7198758)
Zbigniew Jędrzejewski-Szmek a142c8
---
Zbigniew Jędrzejewski-Szmek a142c8
 src/basic/alloc-util.c |  4 ++++
Zbigniew Jędrzejewski-Szmek a142c8
 src/basic/alloc-util.h | 38 ++++++++++++++++++++++++++++----------
Zbigniew Jędrzejewski-Szmek a142c8
 2 files changed, 32 insertions(+), 10 deletions(-)
Zbigniew Jędrzejewski-Szmek a142c8
Zbigniew Jędrzejewski-Szmek a142c8
diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c
Zbigniew Jędrzejewski-Szmek a142c8
index b030f454b2..6063943c88 100644
Zbigniew Jędrzejewski-Szmek a142c8
--- a/src/basic/alloc-util.c
Zbigniew Jędrzejewski-Szmek a142c8
+++ b/src/basic/alloc-util.c
Zbigniew Jędrzejewski-Szmek a142c8
@@ -102,3 +102,7 @@ void* greedy_realloc0(
Zbigniew Jędrzejewski-Szmek a142c8
 
Zbigniew Jędrzejewski-Szmek a142c8
         return q;
Zbigniew Jędrzejewski-Szmek a142c8
 }
Zbigniew Jędrzejewski-Szmek a142c8
+
Zbigniew Jędrzejewski-Szmek a142c8
+void *expand_to_usable(void *ptr, size_t newsize _unused_) {
Zbigniew Jędrzejewski-Szmek a142c8
+        return ptr;
Zbigniew Jędrzejewski-Szmek a142c8
+}
Zbigniew Jędrzejewski-Szmek a142c8
diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h
Zbigniew Jędrzejewski-Szmek a142c8
index b38db7d473..eb53aae6f3 100644
Zbigniew Jędrzejewski-Szmek a142c8
--- a/src/basic/alloc-util.h
Zbigniew Jędrzejewski-Szmek a142c8
+++ b/src/basic/alloc-util.h
Zbigniew Jędrzejewski-Szmek a142c8
@@ -2,6 +2,7 @@
Zbigniew Jędrzejewski-Szmek a142c8
 #pragma once
Zbigniew Jędrzejewski-Szmek a142c8
 
Zbigniew Jędrzejewski-Szmek a142c8
 #include <alloca.h>
Zbigniew Jędrzejewski-Szmek a142c8
+#include <malloc.h>
Zbigniew Jędrzejewski-Szmek a142c8
 #include <stddef.h>
Zbigniew Jędrzejewski-Szmek a142c8
 #include <stdlib.h>
Zbigniew Jędrzejewski-Szmek a142c8
 #include <string.h>
Zbigniew Jędrzejewski-Szmek a142c8
@@ -184,17 +185,34 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
Zbigniew Jędrzejewski-Szmek a142c8
 #  define msan_unpoison(r, s)
Zbigniew Jędrzejewski-Szmek a142c8
 #endif
Zbigniew Jędrzejewski-Szmek a142c8
 
Zbigniew Jędrzejewski-Szmek a142c8
-/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), in a way that
Zbigniew Jędrzejewski-Szmek a142c8
- * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
Zbigniew Jędrzejewski-Szmek a142c8
- * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
Zbigniew Jędrzejewski-Szmek a142c8
- * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
Zbigniew Jędrzejewski-Szmek a142c8
- * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
Zbigniew Jędrzejewski-Szmek a142c8
- * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
Zbigniew Jędrzejewski-Szmek a142c8
- * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
Zbigniew Jędrzejewski-Szmek a142c8
- * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
Zbigniew Jędrzejewski-Szmek a142c8
- * case. */
Zbigniew Jędrzejewski-Szmek a142c8
+/* Dummy allocator to tell the compiler that the new size of p is newsize. The implementation returns the
Zbigniew Jędrzejewski-Szmek a142c8
+ * pointer as is; the only reason for its existence is as a conduit for the _alloc_ attribute. This cannot be
Zbigniew Jędrzejewski-Szmek a142c8
+ * a static inline because gcc then loses the attributes on the function.
Zbigniew Jędrzejewski-Szmek a142c8
+ * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503 */
Zbigniew Jędrzejewski-Szmek a142c8
+void *expand_to_usable(void *p, size_t newsize) _alloc_(2) _returns_nonnull_;
Zbigniew Jędrzejewski-Szmek a142c8
+
Zbigniew Jędrzejewski-Szmek a142c8
+static inline size_t malloc_sizeof_safe(void **xp) {
Zbigniew Jędrzejewski-Szmek a142c8
+        if (_unlikely_(!xp || !*xp))
Zbigniew Jędrzejewski-Szmek a142c8
+                return 0;
Zbigniew Jędrzejewski-Szmek a142c8
+
Zbigniew Jędrzejewski-Szmek a142c8
+        size_t sz = malloc_usable_size(*xp);
Zbigniew Jędrzejewski-Szmek a142c8
+        *xp = expand_to_usable(*xp, sz);
Zbigniew Jędrzejewski-Szmek a142c8
+        /* GCC doesn't see the _returns_nonnull_ when built with ubsan, so yet another hint to make it doubly
Zbigniew Jędrzejewski-Szmek a142c8
+         * clear that expand_to_usable won't return NULL.
Zbigniew Jędrzejewski-Szmek a142c8
+         * See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79265 */
Zbigniew Jędrzejewski-Szmek a142c8
+        if (!*xp)
Zbigniew Jędrzejewski-Szmek a142c8
+                assert_not_reached();
Zbigniew Jędrzejewski-Szmek a142c8
+        return sz;
Zbigniew Jędrzejewski-Szmek a142c8
+}
Zbigniew Jędrzejewski-Szmek a142c8
+
Zbigniew Jędrzejewski-Szmek a142c8
+/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), which may
Zbigniew Jędrzejewski-Szmek a142c8
+ * return a value larger than the size that was actually allocated. Access to that additional memory is
Zbigniew Jędrzejewski-Szmek a142c8
+ * discouraged because it violates the C standard; a compiler cannot see that this as valid. To help the
Zbigniew Jędrzejewski-Szmek a142c8
+ * compiler out, the MALLOC_SIZEOF_SAFE macro 'allocates' the usable size using a dummy allocator function
Zbigniew Jędrzejewski-Szmek a142c8
+ * expand_to_usable. There is a possibility of malloc_usable_size() returning different values during the
Zbigniew Jędrzejewski-Szmek a142c8
+ * lifetime of an object, which may cause problems, but the glibc allocator does not do that at the moment. */
Zbigniew Jędrzejewski-Szmek a142c8
 #define MALLOC_SIZEOF_SAFE(x) \
Zbigniew Jędrzejewski-Szmek a142c8
-        MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
Zbigniew Jędrzejewski-Szmek a142c8
+        malloc_sizeof_safe((void**) &__builtin_choose_expr(__builtin_constant_p(x), (void*) { NULL }, (x)))
Zbigniew Jędrzejewski-Szmek a142c8
 
Zbigniew Jędrzejewski-Szmek a142c8
 /* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items
Zbigniew Jędrzejewski-Szmek a142c8
  * that fit into the specified memory block */
Zbigniew Jędrzejewski-Szmek a142c8
-- 
Zbigniew Jędrzejewski-Szmek a142c8
2.39.1
Zbigniew Jędrzejewski-Szmek a142c8