|
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 |
|