alloc-util: add strdupa_safe() + strndupa_safe() and use it everywhere

Let's define two helpers strdupa_safe() + strndupa_safe() which do the
same as their non-safe counterparts, except that they abort if called
with allocations larger than ALLOCA_MAX.

This should ensure that all our alloca() based allocations are subject
to this limit.

afaics glibc offers three alloca() based APIs: alloca() itself,
strndupa() + strdupa(). With this we have now replacements for all of
them, that take the limit into account.
This commit is contained in:
Lennart Poettering
2021-10-14 15:57:52 +02:00
parent 5222651ecc
commit 2f82562bad
60 changed files with 164 additions and 131 deletions
+16
View File
@@ -194,3 +194,19 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \
VOID_0))
/* These are like strdupa()/strndupa(), but honour ALLOCA_MAX */
#define strdupa_safe(s) \
({ \
const char *_t = (s); \
(char*) memdupa_suffix0(_t, strlen(_t)); \
})
#define strndupa_safe(s, n) \
({ \
const char *_t = (s); \
(char*) memdupa_suffix0(_t, strnlen(_t, (n))); \
})
#include "memory-util.h"
+1 -1
View File
@@ -1131,7 +1131,7 @@ int cg_path_decode_unit(const char *cgroup, char **unit) {
if (n < 3)
return -ENXIO;
c = strndupa(cgroup, n);
c = strndupa_safe(cgroup, n);
c = cg_unescape(c);
if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
+3 -3
View File
@@ -394,7 +394,7 @@ int strv_env_replace_consume(char ***l, char *p) {
return -EINVAL;
}
name = strndupa(p, t - p);
name = strndupa_safe(p, t - p);
STRV_FOREACH(f, *l)
if (env_entry_has_name(*f, name)) {
@@ -481,7 +481,7 @@ char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
const char *t;
t = strndupa(name, k);
t = strndupa_safe(name, k);
return getenv(t);
};
@@ -804,7 +804,7 @@ int putenv_dup(const char *assignment, bool override) {
if (!e)
return -EINVAL;
n = strndupa(assignment, e - assignment);
n = strndupa_safe(assignment, e - assignment);
/* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
if (setenv(n, e + 1, override) < 0)
+1 -1
View File
@@ -56,7 +56,7 @@ int rmdir_parents(const char *path, const char *stop) {
if (!path_is_safe(stop))
return -EINVAL;
p = strdupa(path);
p = strdupa_safe(path);
for (;;) {
char *slash = NULL;
+4 -2
View File
@@ -1073,8 +1073,10 @@ int log_struct_iovec_internal(
for (size_t i = 0; i < n_input_iovec; i++)
if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE=")) {
char *m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="),
input_iovec[i].iov_len - STRLEN("MESSAGE="));
char *m;
m = strndupa_safe((char*) input_iovec[i].iov_base + STRLEN("MESSAGE="),
input_iovec[i].iov_len - STRLEN("MESSAGE="));
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
}
+1 -1
View File
@@ -126,7 +126,7 @@ int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, ui
assert(*e == '/');
/* drop the last component */
path = strndupa(path, e - path);
path = strndupa_safe(path, e - path);
r = is_dir(path, true);
if (r > 0)
return 0;
+1 -1
View File
@@ -156,7 +156,7 @@ static bool filename_possibly_with_slash_suffix(const char *s) {
if (slash[strspn(slash, "/")] != 0) /* Check that the suffix consist only of one or more slashes */
return false;
copied = strndupa(s, slash - s);
copied = strndupa_safe(s, slash - s);
return filename_is_valid(copied);
}
+2 -2
View File
@@ -704,7 +704,7 @@ int parse_dev(const char *s, dev_t *ret) {
if (s[n] != ':')
return -EINVAL;
major = strndupa(s, n);
major = strndupa_safe(s, n);
r = safe_atou(major, &x);
if (r < 0)
return r;
@@ -765,7 +765,7 @@ int parse_loadavg_fixed_point(const char *s, loadavg_t *ret) {
if (!d)
return -EINVAL;
i_str = strndupa(s, d - s);
i_str = strndupa_safe(s, d - s);
f_str = d + 1;
r = safe_atolu_full(i_str, 10, &i);
+1 -1
View File
@@ -489,7 +489,7 @@ static int get_paths_from_environ(const char *var, char ***paths, bool *append)
k = endswith(e, ":");
if (k) {
e = strndupa(e, k - e);
e = strndupa_safe(e, k - e);
*append = true;
}
+5 -5
View File
@@ -12,7 +12,7 @@ static int parse_parts_value_whole(const char *p, const char *symbol) {
if (!pc)
return -EINVAL;
n = strndupa(p, pc - p);
n = strndupa_safe(p, pc - p);
r = safe_atoi(n, &v);
if (r < 0)
return r;
@@ -37,10 +37,10 @@ static int parse_parts_value_with_tenths_place(const char *p, const char *symbol
if (dot[1] < '0' || dot[1] > '9')
return -EINVAL;
q = dot[1] - '0';
n = strndupa(p, dot - p);
n = strndupa_safe(p, dot - p);
} else {
q = 0;
n = strndupa(p, pc - p);
n = strndupa_safe(p, pc - p);
}
r = safe_atoi(n, &v);
if (r < 0)
@@ -81,10 +81,10 @@ static int parse_parts_value_with_hundredths_place(const char *p, const char *sy
/* We do not support zero or more than two places */
return -EINVAL;
n = strndupa(p, dot - p);
n = strndupa_safe(p, dot - p);
} else {
q = 0;
n = strndupa(p, pc - p);
n = strndupa_safe(p, pc - p);
}
r = safe_atoi(n, &v);
if (r < 0)
+1 -1
View File
@@ -135,7 +135,7 @@ int procfs_tasks_get_current(uint64_t *ret) {
p++;
n = strspn(p, DIGITS);
nr = strndupa(p, n);
nr = strndupa_safe(p, n);
return safe_atou64(nr, ret);
}
+5 -5
View File
@@ -671,7 +671,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
goto finish;
} else if ((k = endswith(t, " ago"))) {
t = strndupa(t, k - t);
t = strndupa_safe(t, k - t);
r = parse_sec(t, &minus);
if (r < 0)
@@ -680,7 +680,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
goto finish;
} else if ((k = endswith(t, " left"))) {
t = strndupa(t, k - t);
t = strndupa_safe(t, k - t);
r = parse_sec(t, &plus);
if (r < 0)
@@ -692,7 +692,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
/* See if the timestamp is suffixed with UTC */
utc = endswith_no_case(t, " UTC");
if (utc)
t = strndupa(t, utc - t);
t = strndupa_safe(t, utc - t);
else {
const char *e = NULL;
int j;
@@ -723,7 +723,7 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) {
if (IN_SET(j, 0, 1)) {
/* Found one of the two timezones specified. */
t = strndupa(t, e - t - 1);
t = strndupa_safe(t, e - t - 1);
dst = j;
tzn = tzname[j];
}
@@ -924,7 +924,7 @@ int parse_timestamp(const char *t, usec_t *usec) {
/* Cut off the timezone if we don't need it. */
if (with_tz)
t = strndupa(t, last_space - t);
t = strndupa_safe(t, last_space - t);
shared->return_value = parse_timestamp_impl(t, &shared->usec, with_tz);