summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-05-18 22:27:24 +0200
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-07-22 13:34:39 +0200
commit849c984fce3e9ad017f3d6e36ba773fe73811471 (patch)
tree6db15d46970f4f5e7ba52cc88f0ffc6719ecbb36
parentab8d88de3a49506ba854743aada8e4559e76b4e1 (diff)
downloadsystemd-849c984fce3e9ad017f3d6e36ba773fe73811471.tar.gz
alloc-util: introduce MALLOC_SIZEOF_SAFE() helper
It's a wrapper around malloc_usable_size() that is supposed to be compatible with _FORTIFY_SOURCES=1, by taking the __builtin_object_size() data into account, the same way as the _FORTIFY_SOURCES=1 logic does. Fixes: #19203 (cherry picked from commit 6df28e1f847d68ad37ffe3f4ff47745b55233861) Fixes https://bugzilla.redhat.com/show_bug.cgi?id=1975564
-rw-r--r--src/basic/alloc-util.h12
-rw-r--r--src/basic/fileio.c4
-rw-r--r--src/basic/memory-util.h2
3 files changed, 15 insertions, 3 deletions
diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h
index 698a6583c5..66bee6cb87 100644
--- a/src/basic/alloc-util.h
+++ b/src/basic/alloc-util.h
@@ -163,3 +163,15 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
#else
# define msan_unpoison(r, s)
#endif
+
+/* This returns the number of usable bytes in a malloc()ed region as per malloc_usable_size(), in a way that
+ * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the
+ * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of
+ * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by
+ * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the
+ * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory,
+ * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and
+ * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner
+ * case. */
+#define MALLOC_SIZEOF_SAFE(x) \
+ MIN(malloc_usable_size(x), __builtin_object_size(x, 0))
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 08b46ef6f3..b2ffcd3287 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -421,7 +421,7 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
if (!buf)
return -ENOMEM;
/* Use a bigger allocation if we got it anyway, but not more than the limit. */
- size = MIN(malloc_usable_size(buf) - 1, READ_VIRTUAL_BYTES_MAX);
+ size = MIN(MALLOC_SIZEOF_SAFE(buf) - 1, READ_VIRTUAL_BYTES_MAX);
for (;;) {
ssize_t k;
@@ -560,7 +560,7 @@ int read_full_stream_full(
buf = t;
/* Unless a size has been explicitly specified, try to read as much as fits into the memory
* we allocated (minus 1, to leave one byte for the safety NUL byte) */
- n = size == SIZE_MAX ? malloc_usable_size(buf) - 1 : n_next;
+ n = size == SIZE_MAX ? MALLOC_SIZEOF_SAFE(buf) - 1 : n_next;
errno = 0;
k = fread(buf + l, 1, n - l, f);
diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h
index 179edd247b..e3f7980d12 100644
--- a/src/basic/memory-util.h
+++ b/src/basic/memory-util.h
@@ -88,7 +88,7 @@ static inline void* erase_and_free(void *p) {
if (!p)
return NULL;
- l = malloc_usable_size(p);
+ l = MALLOC_SIZEOF_SAFE(p);
explicit_bzero_safe(p, l);
return mfree(p);
}