Skip to content

Commit

Permalink
alloc-util: add strdupa_safe() + strndupa_safe() and use it everywhere
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
poettering committed Oct 14, 2021
1 parent 5222651 commit 2f82562
Show file tree
Hide file tree
Showing 60 changed files with 164 additions and 131 deletions.
11 changes: 11 additions & 0 deletions coccinelle/strdupa.cocci
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
@@
expression x;
@@
- strdupa(x)
+ strdupa_safe(x)
@@
expression x, n;
@@
- strndupa(x, n)
+ strndupa_safe(x, n)
2 changes: 1 addition & 1 deletion src/backlight/backlight.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ static int run(int argc, char *argv[]) {
if (!sysname)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Requires a subsystem and sysname pair specifying a backlight device.");

ss = strndupa(argv[2], sysname - argv[2]);
ss = strndupa_safe(argv[2], sysname - argv[2]);

sysname++;

Expand Down
16 changes: 16 additions & 0 deletions src/basic/alloc-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion src/basic/cgroup-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
6 changes: 3 additions & 3 deletions src/basic/env-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
};

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/basic/fs-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions src/basic/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/basic/mkdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/basic/mountpoint-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
4 changes: 2 additions & 2 deletions src/basic/parse-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/basic/path-lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
10 changes: 5 additions & 5 deletions src/basic/percent-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/basic/procfs-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
10 changes: 5 additions & 5 deletions src/basic/time-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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];
}
Expand Down Expand Up @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions src/boot/bless-boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ static int parse_counter(
"Can't parse empty 'tries left' counter from LoaderBootCountPath: %s",
path);

z = strndupa(e, k);
z = strndupa_safe(e, k);
r = safe_atou64(z, &left);
if (r < 0)
return log_error_errno(r, "Failed to parse 'tries left' counter from LoaderBootCountPath: %s", path);
Expand All @@ -178,7 +178,7 @@ static int parse_counter(
"Can't parse empty 'tries done' counter from LoaderBootCountPath: %s",
path);

z = strndupa(e, k);
z = strndupa_safe(e, k);
r = safe_atou64(z, &done);
if (r < 0)
return log_error_errno(r, "Failed to parse 'tries done' counter from LoaderBootCountPath: %s", path);
Expand Down
2 changes: 1 addition & 1 deletion src/core/cgroup.c
Original file line number Diff line number Diff line change
Expand Up @@ -3437,7 +3437,7 @@ Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
if (u)
return u;

p = strdupa(cgroup);
p = strdupa_safe(cgroup);
for (;;) {
char *e;

Expand Down
2 changes: 1 addition & 1 deletion src/core/dbus-execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -3462,7 +3462,7 @@ int bus_exec_context_set_transient_property(
if (soft) {
const char *n;

n = strndupa(suffix, soft - suffix);
n = strndupa_safe(suffix, soft - suffix);
ri = rlimit_from_string(n);
if (ri >= 0)
name = strjoina("Limit", n);
Expand Down
2 changes: 1 addition & 1 deletion src/core/dbus-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ int bus_set_transient_usec_internal(
else
*p = v;

char *n = strndupa(name, strlen(name) - 4);
char *n = strndupa_safe(name, strlen(name) - 4);
unit_write_settingf(u, flags, name, "%sSec=%s", n, FORMAT_TIMESPAN(v, USEC_PER_MSEC));
}

Expand Down
10 changes: 5 additions & 5 deletions src/core/execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -6524,7 +6524,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
assert(fds);

n = strcspn(v, " ");
id = strndupa(v, n);
id = strndupa_safe(v, n);
if (v[n] != ' ')
goto finalize;
p = v + n + 1;
Expand Down Expand Up @@ -6556,7 +6556,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
char *buf;

n = strcspn(v, " ");
buf = strndupa(v, n);
buf = strndupa_safe(v, n);

r = safe_atoi(buf, &netns_fdpair[0]);
if (r < 0)
Expand All @@ -6575,7 +6575,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
char *buf;

n = strcspn(v, " ");
buf = strndupa(v, n);
buf = strndupa_safe(v, n);

r = safe_atoi(buf, &netns_fdpair[1]);
if (r < 0)
Expand All @@ -6594,7 +6594,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
char *buf;

n = strcspn(v, " ");
buf = strndupa(v, n);
buf = strndupa_safe(v, n);

r = safe_atoi(buf, &ipcns_fdpair[0]);
if (r < 0)
Expand All @@ -6613,7 +6613,7 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
char *buf;

n = strcspn(v, " ");
buf = strndupa(v, n);
buf = strndupa_safe(v, n);

r = safe_atoi(buf, &ipcns_fdpair[1]);
if (r < 0)
Expand Down
2 changes: 1 addition & 1 deletion src/coredump/coredump-vacuum.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static int uid_from_file_name(const char *filename, uid_t *uid) {
if (!e)
return -EINVAL;

u = strndupa(p, e-p);
u = strndupa_safe(p, e - p);
return parse_uid(u, uid);
}

Expand Down
2 changes: 1 addition & 1 deletion src/home/homed-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ static int on_home_inotify(sd_event_source *s, const struct inotify_event *event
if (!e)
return 0;

n = strndupa(event->name, e - event->name);
n = strndupa_safe(event->name, e - event->name);
if (!suitable_user_name(n))
return 0;

Expand Down
2 changes: 1 addition & 1 deletion src/home/homework-cifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ int home_activate_cifs(
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks CIFS service, refusing.");

assert_se(hdo = user_record_home_directory(h));
hd = strdupa(hdo); /* copy the string out, since it might change later in the home record object */
hd = strdupa_safe(hdo); /* copy the string out, since it might change later in the home record object */

r = home_prepare_cifs(h, false, &setup);
if (r < 0)
Expand Down
4 changes: 2 additions & 2 deletions src/home/homework-directory.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ int home_activate_directory(
assert(ret_home);

assert_se(ipo = user_record_image_path(h));
ip = strdupa(ipo); /* copy out, since reconciliation might cause changing of the field */
ip = strdupa_safe(ipo); /* copy out, since reconciliation might cause changing of the field */

assert_se(hdo = user_record_home_directory(h));
hd = strdupa(hdo);
hd = strdupa_safe(hdo);

r = home_prepare(h, false, cache, &setup, &header_home);
if (r < 0)
Expand Down
6 changes: 3 additions & 3 deletions src/home/homework-luks.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ static int crypt_device_to_evp_cipher(struct crypt_device *cd, const EVP_CIPHER

e = strchr(cipher_mode, '-');
if (e)
cipher_mode = strndupa(cipher_mode, e - cipher_mode);
cipher_mode = strndupa_safe(cipher_mode, e - cipher_mode);

r = sym_crypt_get_volume_key_size(cd);
if (r <= 0)
Expand Down Expand Up @@ -1354,7 +1354,7 @@ int home_activate_luks(
return r;

assert_se(hdo = user_record_home_directory(h));
hd = strdupa(hdo); /* copy the string out, since it might change later in the home record object */
hd = strdupa_safe(hdo); /* copy the string out, since it might change later in the home record object */

r = make_dm_names(h->user_name, &setup.dm_name, &setup.dm_node);
if (r < 0)
Expand Down Expand Up @@ -2709,7 +2709,7 @@ int home_resize_luks(
return r;

assert_se(ipo = user_record_image_path(h));
ip = strdupa(ipo); /* copy out since original might change later in home record object */
ip = strdupa_safe(ipo); /* copy out since original might change later in home record object */

image_fd = open(ip, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
if (image_fd < 0)
Expand Down
Loading

0 comments on commit 2f82562

Please sign in to comment.