Skip to content

Commit

Permalink
alloc-util: introduce MALLOC_SIZEOF_SAFE() helper
Browse files Browse the repository at this point in the history
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: systemd#19203
  • Loading branch information
poettering committed May 19, 2021
1 parent 6db7b53 commit 9349f63
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 5 deletions.
12 changes: 12 additions & 0 deletions src/basic/alloc-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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))
4 changes: 2 additions & 2 deletions src/basic/fileio.c
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ int read_virtual_file(const char *filename, size_t max_size, char **ret_contents
if (!buf)
return -ENOMEM;
/* Use a bigger allocation if we got it anyway, but not more than the limit. */
size = MIN3(malloc_usable_size(buf) - 1, max_size, READ_FULL_BYTES_MAX);
size = MIN3(MALLOC_SIZEOF_SAFE(buf) - 1, max_size, READ_FULL_BYTES_MAX);

for (;;) {
ssize_t k;
Expand Down Expand Up @@ -570,7 +570,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);
Expand Down
2 changes: 1 addition & 1 deletion src/basic/memory-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions src/basic/string-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ int strextendf(char **x, const char *format, ...) {
/* Let's try to use the allocated buffer, if there's room at the end still. Otherwise let's extend by 64 chars. */
if (*x) {
m = strlen(*x);
a = malloc_usable_size(*x);
a = MALLOC_SIZEOF_SAFE(*x);
assert(a >= m + 1);
} else
m = a = 0;
Expand All @@ -821,7 +821,7 @@ int strextendf(char **x, const char *format, ...) {
return -ENOMEM;

*x = n;
a = malloc_usable_size(*x);
a = MALLOC_SIZEOF_SAFE(*x);
}

/* Now, let's try to format the string into it */
Expand Down

0 comments on commit 9349f63

Please sign in to comment.