systemd: merge branch systemd into master

This commit is contained in:
Thomas Haller
2018-04-04 15:44:05 +02:00
38 changed files with 527 additions and 270 deletions

View File

@@ -25,6 +25,10 @@
/* Gettext package */ /* Gettext package */
#mesondefine GETTEXT_PACKAGE #mesondefine GETTEXT_PACKAGE
/* Define to 1 if you have the declaration of `reallocarray', and to 0 if
you don't. */
#mesondefine HAVE_DECL_REALLOCARRAY
/* Define to 1 if you have the declaration of `explicit_bzero', and to 0 if /* Define to 1 if you have the declaration of `explicit_bzero', and to 0 if
you don't. */ you don't. */
#mesondefine HAVE_DECL_EXPLICIT_BZERO #mesondefine HAVE_DECL_EXPLICIT_BZERO

View File

@@ -75,6 +75,12 @@ AC_CHECK_DECLS([
#include <string.h> #include <string.h>
]]) ]])
AC_CHECK_DECLS([
reallocarray],
[], [], [[
#include <malloc.h>
]])
AC_CHECK_HEADERS(sys/auxv.h) AC_CHECK_HEADERS(sys/auxv.h)
AC_CHECK_DECLS([getrandom], AC_CHECK_DECLS([getrandom],

View File

@@ -97,22 +97,23 @@ endforeach
# headers # headers
config_h.set10('HAVE_SYS_AUXV_H', cc.has_header('sys/auxv.h')) config_h.set10('HAVE_SYS_AUXV_H', cc.has_header('sys/auxv.h'))
use_sys_random = cc.has_function('getrandom', prefix: '#include<sys/random.h>') use_sys_random = cc.has_function('getrandom', prefix: '#include <sys/random.h>')
config_h.set10('USE_SYS_RANDOM_H', use_sys_random) config_h.set10('USE_SYS_RANDOM_H', use_sys_random)
config_h.set10('HAVE_GETRANDOM', use_sys_random or cc.has_function('getrandom', prefix: '#include<linux/random.h>')) config_h.set10('HAVE_GETRANDOM', use_sys_random or cc.has_function('getrandom', prefix: '#include <linux/random.h>'))
# functions # functions
# FIXME secure_getenv check is not useful? # FIXME secure_getenv check is not useful?
config_h.set('HAVE_SECURE_GETENV', cc.has_function('secure_getenv')) config_h.set('HAVE_SECURE_GETENV', cc.has_function('secure_getenv'))
config_h.set('HAVE___SECURE_GETENV', cc.has_function('__secure_getenv')) config_h.set('HAVE___SECURE_GETENV', cc.has_function('__secure_getenv'))
config_h.set10('HAVE_DECL_EXPLICIT_BZERO', cc.has_function('explicit_bzero', prefix: '#include<string.h>')) config_h.set10('HAVE_DECL_REALLOCARRAY', cc.has_function('reallocarray', prefix: '#include <malloc.h>'))
config_h.set10('HAVE_DECL_EXPLICIT_BZERO', cc.has_function('explicit_bzero', prefix: '#include <string.h>'))
# types # types
config_h.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix: '#include<sys/types.h>')) config_h.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix: '#include <sys/types.h>'))
config_h.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix: '#include<sys/types.h>')) config_h.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix: '#include <sys/types.h>'))
config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix: '#include<sys/types.h>')) config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix: '#include <sys/types.h>'))
if not cc.has_type('pid_t', prefix: '#include<sys/types.h>') if not cc.has_type('pid_t', prefix: '#include <sys/types.h>')
config_h.set('pid_t', 'int') config_h.set('pid_t', 'int')
endif endif

View File

@@ -26,12 +26,16 @@
#include <sys/resource.h> #include <sys/resource.h>
#include <time.h> #include <time.h>
#define noreturn G_GNUC_NORETURN
#ifndef CLOCK_BOOTTIME #ifndef CLOCK_BOOTTIME
#define CLOCK_BOOTTIME 7 #define CLOCK_BOOTTIME 7
#endif #endif
#if defined(HAVE_DECL_REALLOCARRAY) && HAVE_DECL_REALLOCARRAY == 1
#define HAVE_REALLOCARRAY 1
#else
#define HAVE_REALLOCARRAY 0
#endif
#if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1 #if defined(HAVE_DECL_EXPLICIT_BZERO) && HAVE_DECL_EXPLICIT_BZERO == 1
#define HAVE_EXPLICIT_BZERO 1 #define HAVE_EXPLICIT_BZERO 1
#else #else

View File

@@ -74,12 +74,14 @@ _malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t
return malloc(size * need); return malloc(size * need);
} }
_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) { #if !HAVE_REALLOCARRAY
_alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size) {
if (size_multiply_overflow(size, need)) if (size_multiply_overflow(size, need))
return NULL; return NULL;
return realloc(p, size * need); return realloc(p, size * need);
} }
#endif
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) { _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
if (size_multiply_overflow(size, need)) if (size_multiply_overflow(size, need))
@@ -128,3 +130,12 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
_new_ = alloca_align(_size_, (align)); \ _new_ = alloca_align(_size_, (align)); \
(void*)memset(_new_, 0, _size_); \ (void*)memset(_new_, 0, _size_); \
}) })
/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
* NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
#define TAKE_PTR(ptr) \
({ \
typeof(ptr) _ptr_ = (ptr); \
(ptr) = NULL; \
_ptr_; \
})

View File

@@ -196,8 +196,7 @@ finish:
finish_force_next: finish_force_next:
s[sz] = 0; s[sz] = 0;
*ret = s; *ret = TAKE_PTR(s);
s = NULL;
return 1; return 1;
} }

View File

@@ -194,12 +194,6 @@ int fd_cloexec(int fd, bool cloexec) {
} }
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
void stdio_unset_cloexec(void) {
(void) fd_cloexec(STDIN_FILENO, false);
(void) fd_cloexec(STDOUT_FILENO, false);
(void) fd_cloexec(STDERR_FILENO, false);
}
_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) {
unsigned i; unsigned i;
@@ -371,14 +365,21 @@ bool fdname_is_valid(const char *s) {
} }
int fd_get_path(int fd, char **ret) { int fd_get_path(int fd, char **ret) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; _cleanup_close_ int dir = -1;
char fdname[DECIMAL_STR_MAX(int)];
int r; int r;
xsprintf(procfs_path, "/proc/self/fd/%i", fd); dir = open("/proc/self/fd/", O_CLOEXEC | O_DIRECTORY | O_PATH);
if (dir < 0)
/* /proc is not available or not set up properly, we're most likely
* in some chroot environment. */
return errno == ENOENT ? -EOPNOTSUPP : -errno;
r = readlink_malloc(procfs_path, ret); xsprintf(fdname, "%i", fd);
if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */ r = readlinkat_malloc(dir, fdname, ret);
if (r == -ENOENT)
/* If the file doesn't exist the fd is invalid */
return -EBADF; return -EBADF;
return r; return r;
@@ -431,7 +432,6 @@ int move_fd(int from, int to, int cloexec) {
int acquire_data_fd(const void *data, size_t size, unsigned flags) { int acquire_data_fd(const void *data, size_t size, unsigned flags) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_close_pair_ int pipefds[2] = { -1, -1 }; _cleanup_close_pair_ int pipefds[2] = { -1, -1 };
char pattern[] = "/dev/shm/data-fd-XXXXXX"; char pattern[] = "/dev/shm/data-fd-XXXXXX";
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
@@ -488,10 +488,7 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags) {
if (r < 0) if (r < 0)
return r; return r;
r = fd; return TAKE_FD(fd);
fd = -1;
return r;
} }
try_pipe: try_pipe:
@@ -528,10 +525,7 @@ try_pipe:
(void) fd_nonblock(pipefds[0], false); (void) fd_nonblock(pipefds[0], false);
r = pipefds[0]; return TAKE_FD(pipefds[0]);
pipefds[0] = -1;
return r;
} }
try_dev_shm: try_dev_shm:
@@ -547,12 +541,7 @@ try_dev_shm:
return -EIO; return -EIO;
/* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */
xsprintf(procfs_path, "/proc/self/fd/%i", fd); return fd_reopen(fd, O_RDONLY|O_CLOEXEC);
r = open(procfs_path, O_RDONLY|O_CLOEXEC);
if (r < 0)
return -errno;
return r;
} }
try_dev_shm_without_o_tmpfile: try_dev_shm_without_o_tmpfile:
@@ -621,3 +610,139 @@ int fd_move_above_stdio(int fd) {
(void) close(fd); (void) close(fd);
return copy; return copy;
} }
#if 0 /* NM_IGNORED */
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd) {
int fd[3] = { /* Put together an array of fds we work on */
original_input_fd,
original_output_fd,
original_error_fd
};
int r, i,
null_fd = -1, /* if we open /dev/null, we store the fd to it here */
copy_fd[3] = { -1, -1, -1 }; /* This contains all fds we duplicate here temporarily, and hence need to close at the end */
bool null_readable, null_writable;
/* Sets up stdin, stdout, stderr with the three file descriptors passed in. If any of the descriptors is
* specified as -1 it will be connected with /dev/null instead. If any of the file descriptors is passed as
* itself (e.g. stdin as STDIN_FILENO) it is left unmodified, but the O_CLOEXEC bit is turned off should it be
* on.
*
* Note that if any of the passed file descriptors are > 2 they will be closed — both on success and on
* failure! Thus, callers should assume that when this function returns the input fds are invalidated.
*
* Note that when this function fails stdin/stdout/stderr might remain half set up!
*
* O_CLOEXEC is turned off for all three file descriptors (which is how it should be for
* stdin/stdout/stderr). */
null_readable = original_input_fd < 0;
null_writable = original_output_fd < 0 || original_error_fd < 0;
/* First step, open /dev/null once, if we need it */
if (null_readable || null_writable) {
/* Let's open this with O_CLOEXEC first, and convert it to non-O_CLOEXEC when we move the fd to the final position. */
null_fd = open("/dev/null", (null_readable && null_writable ? O_RDWR :
null_readable ? O_RDONLY : O_WRONLY) | O_CLOEXEC);
if (null_fd < 0) {
r = -errno;
goto finish;
}
/* If this fd is in the 0…2 range, let's move it out of it */
if (null_fd < 3) {
int copy;
copy = fcntl(null_fd, F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
if (copy < 0) {
r = -errno;
goto finish;
}
safe_close(null_fd);
null_fd = copy;
}
}
/* Let's assemble fd[] with the fds to install in place of stdin/stdout/stderr */
for (i = 0; i < 3; i++) {
if (fd[i] < 0)
fd[i] = null_fd; /* A negative parameter means: connect this one to /dev/null */
else if (fd[i] != i && fd[i] < 3) {
/* This fd is in the 0…2 territory, but not at its intended place, move it out of there, so that we can work there. */
copy_fd[i] = fcntl(fd[i], F_DUPFD_CLOEXEC, 3); /* Duplicate this with O_CLOEXEC set */
if (copy_fd[i] < 0) {
r = -errno;
goto finish;
}
fd[i] = copy_fd[i];
}
}
/* At this point we now have the fds to use in fd[], and they are all above the stdio range, so that we
* have freedom to move them around. If the fds already were at the right places then the specific fds are
* -1. Let's now move them to the right places. This is the point of no return. */
for (i = 0; i < 3; i++) {
if (fd[i] == i) {
/* fd is already in place, but let's make sure O_CLOEXEC is off */
r = fd_cloexec(i, false);
if (r < 0)
goto finish;
} else {
assert(fd[i] > 2);
if (dup2(fd[i], i) < 0) { /* Turns off O_CLOEXEC on the new fd. */
r = -errno;
goto finish;
}
}
}
r = 0;
finish:
/* Close the original fds, but only if they were outside of the stdio range. Also, properly check for the same
* fd passed in multiple times. */
safe_close_above_stdio(original_input_fd);
if (original_output_fd != original_input_fd)
safe_close_above_stdio(original_output_fd);
if (original_error_fd != original_input_fd && original_error_fd != original_output_fd)
safe_close_above_stdio(original_error_fd);
/* Close the copies we moved > 2 */
for (i = 0; i < 3; i++)
safe_close(copy_fd[i]);
/* Close our null fd, if it's > 2 */
safe_close_above_stdio(null_fd);
return r;
}
int fd_reopen(int fd, int flags) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
int new_fd;
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
* turn O_RDWR fds into O_RDONLY fds.
*
* This doesn't work on sockets (since they cannot be open()ed, ever).
*
* This implicitly resets the file read index to 0. */
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
new_fd = open(procfs_path, flags);
if (new_fd < 0)
return -errno;
return new_fd;
}
#endif /* NM_IGNORED */

View File

@@ -35,6 +35,13 @@ int close_nointr(int fd);
int safe_close(int fd); int safe_close(int fd);
void safe_close_pair(int p[]); void safe_close_pair(int p[]);
static inline int safe_close_above_stdio(int fd) {
if (fd < 3) /* Don't close stdin/stdout/stderr, but still invalidate the fd by returning -1 */
return -1;
return safe_close(fd);
}
void close_many(const int fds[], unsigned n_fd); void close_many(const int fds[], unsigned n_fd);
int fclose_nointr(FILE *f); int fclose_nointr(FILE *f);
@@ -64,7 +71,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir);
int fd_nonblock(int fd, bool nonblock); int fd_nonblock(int fd, bool nonblock);
int fd_cloexec(int fd, bool cloexec); int fd_cloexec(int fd, bool cloexec);
void stdio_unset_cloexec(void);
int close_all_fds(const int except[], unsigned n_except); int close_all_fds(const int except[], unsigned n_except);
@@ -93,3 +99,19 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags);
IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
int fd_move_above_stdio(int fd); int fd_move_above_stdio(int fd);
int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
static inline int make_null_stdio(void) {
return rearrange_stdio(-1, -1, -1);
}
/* Like TAKE_PTR() but for file descriptors, resetting them to -1 */
#define TAKE_FD(fd) \
({ \
int _fd_ = (fd); \
(fd) = -1; \
_fd_; \
})
int fd_reopen(int fd, int flags);

View File

@@ -334,8 +334,7 @@ int read_full_stream(FILE *f, char **contents, size_t *size) {
} }
buf[l] = 0; buf[l] = 0;
*contents = buf; *contents = TAKE_PTR(buf);
buf = NULL; /* do not free */
if (size) if (size)
*size = l; *size = l;
@@ -367,11 +366,11 @@ static int parse_env_file_internal(
void *userdata, void *userdata,
int *n_pushed) { int *n_pushed) {
_cleanup_free_ char *contents = NULL, *key = NULL;
size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1;
char *p, *value = NULL; _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL;
int r;
unsigned line = 1; unsigned line = 1;
char *p;
int r;
enum { enum {
PRE_KEY, PRE_KEY,
@@ -408,10 +407,8 @@ static int parse_env_file_internal(
state = KEY; state = KEY;
last_key_whitespace = (size_t) -1; last_key_whitespace = (size_t) -1;
if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
key[n_key++] = c; key[n_key++] = c;
} }
@@ -431,10 +428,8 @@ static int parse_env_file_internal(
else if (last_key_whitespace == (size_t) -1) else if (last_key_whitespace == (size_t) -1)
last_key_whitespace = n_key; last_key_whitespace = n_key;
if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { if (!GREEDY_REALLOC(key, key_alloc, n_key+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
key[n_key++] = c; key[n_key++] = c;
} }
@@ -456,7 +451,7 @@ static int parse_env_file_internal(
r = push(fname, line, key, value, userdata, n_pushed); r = push(fname, line, key, value, userdata, n_pushed);
if (r < 0) if (r < 0)
goto fail; return r;
n_key = 0; n_key = 0;
value = NULL; value = NULL;
@@ -471,10 +466,8 @@ static int parse_env_file_internal(
else if (!strchr(WHITESPACE, c)) { else if (!strchr(WHITESPACE, c)) {
state = VALUE; state = VALUE;
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -501,7 +494,7 @@ static int parse_env_file_internal(
r = push(fname, line, key, value, userdata, n_pushed); r = push(fname, line, key, value, userdata, n_pushed);
if (r < 0) if (r < 0)
goto fail; return r;
n_key = 0; n_key = 0;
value = NULL; value = NULL;
@@ -516,10 +509,8 @@ static int parse_env_file_internal(
else if (last_value_whitespace == (size_t) -1) else if (last_value_whitespace == (size_t) -1)
last_value_whitespace = n_value; last_value_whitespace = n_value;
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -531,10 +522,8 @@ static int parse_env_file_internal(
if (!strchr(newline, c)) { if (!strchr(newline, c)) {
/* Escaped newlines we eat up entirely */ /* Escaped newlines we eat up entirely */
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -546,10 +535,8 @@ static int parse_env_file_internal(
else if (c == '\\') else if (c == '\\')
state = SINGLE_QUOTE_VALUE_ESCAPE; state = SINGLE_QUOTE_VALUE_ESCAPE;
else { else {
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -560,10 +547,8 @@ static int parse_env_file_internal(
state = SINGLE_QUOTE_VALUE; state = SINGLE_QUOTE_VALUE;
if (!strchr(newline, c)) { if (!strchr(newline, c)) {
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -575,10 +560,8 @@ static int parse_env_file_internal(
else if (c == '\\') else if (c == '\\')
state = DOUBLE_QUOTE_VALUE_ESCAPE; state = DOUBLE_QUOTE_VALUE_ESCAPE;
else { else {
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -589,10 +572,8 @@ static int parse_env_file_internal(
state = DOUBLE_QUOTE_VALUE; state = DOUBLE_QUOTE_VALUE;
if (!strchr(newline, c)) { if (!strchr(newline, c)) {
if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2))
r = -ENOMEM; return -ENOMEM;
goto fail;
}
value[n_value++] = c; value[n_value++] = c;
} }
@@ -637,14 +618,12 @@ static int parse_env_file_internal(
r = push(fname, line, key, value, userdata, n_pushed); r = push(fname, line, key, value, userdata, n_pushed);
if (r < 0) if (r < 0)
goto fail; return r;
value = NULL;
} }
return 0; return 0;
fail:
free(value);
return r;
} }
static int check_utf8ness_and_warn( static int check_utf8ness_and_warn(
@@ -1465,8 +1444,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
if (fd < 0) if (fd < 0)
return -errno; return -errno;
*ret_path = tmp; *ret_path = TAKE_PTR(tmp);
tmp = NULL;
return fd; return fd;
} }
@@ -1552,8 +1530,7 @@ int read_nul_string(FILE *f, char **ret) {
return -ENOMEM; return -ENOMEM;
} }
*ret = x; *ret = TAKE_PTR(x);
x = NULL;
return 0; return 0;
} }

View File

@@ -465,10 +465,8 @@ int get_files_in_directory(const char *path, char ***list) {
n++; n++;
} }
if (list) { if (list)
*list = l; *list = TAKE_PTR(l);
l = NULL; /* avoid freeing */
}
return n; return n;
} }
@@ -586,6 +584,10 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r; return r;
} }
static bool noop_root(const char *root) {
return isempty(root) || path_equal(root, "/");
}
static bool safe_transition(const struct stat *a, const struct stat *b) { static bool safe_transition(const struct stat *a, const struct stat *b) {
/* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to
* privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files
@@ -636,9 +638,19 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
* specified path. */ * specified path. */
/* A root directory of "/" or "" is identical to none */ /* A root directory of "/" or "" is identical to none */
if (isempty(original_root) || path_equal(original_root, "/")) if (noop_root(original_root))
original_root = NULL; original_root = NULL;
if (!original_root && !ret && (flags & (CHASE_NONEXISTENT|CHASE_NO_AUTOFS|CHASE_SAFE|CHASE_OPEN)) == CHASE_OPEN) {
/* Shortcut the CHASE_OPEN case if the caller isn't interested in the actual path and has no root set
* and doesn't care about any of the other special features we provide either. */
r = open(path, O_PATH|O_CLOEXEC);
if (r < 0)
return -errno;
return r;
}
if (original_root) { if (original_root) {
r = path_make_absolute_cwd(original_root, &root); r = path_make_absolute_cwd(original_root, &root);
if (r < 0) if (r < 0)
@@ -692,8 +704,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
/* Just a single slash? Then we reached the end. */ /* Just a single slash? Then we reached the end. */
if (path_equal(first, "/")) { if (path_equal(first, "/")) {
/* Preserve the trailing slash */ /* Preserve the trailing slash */
if (!strextend(&done, "/", NULL))
return -ENOMEM; if (flags & CHASE_TRAIL_SLASH)
if (!strextend(&done, "/", NULL))
return -ENOMEM;
break; break;
} }
@@ -739,8 +753,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
} }
safe_close(fd); safe_close(fd);
fd = fd_parent; fd = TAKE_FD(fd_parent);
fd_parent = -1;
continue; continue;
} }
@@ -845,10 +858,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
} }
/* If this is not a symlink, then let's just add the name we read to what we already verified. */ /* If this is not a symlink, then let's just add the name we read to what we already verified. */
if (!done) { if (!done)
done = first; done = TAKE_PTR(first);
first = NULL; else {
} else {
/* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */
if (streq(done, "/")) if (streq(done, "/"))
*done = '\0'; *done = '\0';
@@ -859,8 +871,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
/* And iterate again, but go one directory further down. */ /* And iterate again, but go one directory further down. */
safe_close(fd); safe_close(fd);
fd = child; fd = TAKE_FD(child);
child = -1;
} }
if (!done) { if (!done) {
@@ -870,27 +881,100 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
return -ENOMEM; return -ENOMEM;
} }
if (ret) { if (ret)
*ret = done; *ret = TAKE_PTR(done);
done = NULL;
}
if (flags & CHASE_OPEN) { if (flags & CHASE_OPEN) {
int q;
/* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by
* opening /proc/self/fd/xyz. */ * opening /proc/self/fd/xyz. */
assert(fd >= 0); assert(fd >= 0);
q = fd; return TAKE_FD(fd);
fd = -1;
return q;
} }
return exists; return exists;
} }
int chase_symlinks_and_open(
const char *path,
const char *root,
unsigned chase_flags,
int open_flags,
char **ret_path) {
_cleanup_close_ int path_fd = -1;
_cleanup_free_ char *p = NULL;
int r;
if (chase_flags & CHASE_NONEXISTENT)
return -EINVAL;
if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
r = open(path, open_flags);
if (r < 0)
return -errno;
return r;
}
path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
if (path_fd < 0)
return path_fd;
r = fd_reopen(path_fd, open_flags);
if (r < 0)
return r;
if (ret_path)
*ret_path = TAKE_PTR(p);
return r;
}
int chase_symlinks_and_opendir(
const char *path,
const char *root,
unsigned chase_flags,
char **ret_path,
DIR **ret_dir) {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
_cleanup_close_ int path_fd = -1;
_cleanup_free_ char *p = NULL;
DIR *d;
if (!ret_dir)
return -EINVAL;
if (chase_flags & CHASE_NONEXISTENT)
return -EINVAL;
if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) {
/* Shortcut this call if none of the special features of this call are requested */
d = opendir(path);
if (!d)
return -errno;
*ret_dir = d;
return 0;
}
path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL);
if (path_fd < 0)
return path_fd;
xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
d = opendir(procfs_path);
if (!d)
return -errno;
if (ret_path)
*ret_path = TAKE_PTR(p);
*ret_dir = d;
return 0;
}
int access_fd(int fd, int mode) { int access_fd(int fd, int mode) {
char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
int r; int r;
@@ -898,10 +982,9 @@ int access_fd(int fd, int mode) {
/* Like access() but operates on an already open fd */ /* Like access() but operates on an already open fd */
xsprintf(p, "/proc/self/fd/%i", fd); xsprintf(p, "/proc/self/fd/%i", fd);
r = access(p, mode); r = access(p, mode);
if (r < 0) if (r < 0)
r = -errno; return -errno;
return r; return r;
} }
@@ -985,8 +1068,19 @@ int fsync_directory_of_file(int fd) {
return r; return r;
r = fd_get_path(fd, &path); r = fd_get_path(fd, &path);
if (r < 0) if (r < 0) {
log_debug("Failed to query /proc/self/fd/%d%s: %m",
fd,
r == -EOPNOTSUPP ? ", ignoring" : "");
if (r == -EOPNOTSUPP)
/* If /proc is not available, we're most likely running in some
* chroot environment, and syncing the directory is not very
* important in that case. Let's just silently do nothing. */
return 0;
return r; return r;
}
if (!path_is_absolute(path)) if (!path_is_absolute(path))
return -EINVAL; return -EINVAL;

View File

@@ -20,6 +20,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>. along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/ ***/
#include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdbool.h> #include <stdbool.h>
@@ -86,10 +87,14 @@ enum {
CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */ CHASE_NO_AUTOFS = 1U << 2, /* If set, return -EREMOTE if autofs mount point found */
CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */ CHASE_SAFE = 1U << 3, /* If set, return EPERM if we ever traverse from unprivileged to privileged files or directories */
CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */ CHASE_OPEN = 1U << 4, /* If set, return an O_PATH object to the final component */
CHASE_TRAIL_SLASH = 1U << 5, /* If set, any trailing slash will be preserved */
}; };
int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret);
int chase_symlinks_and_open(const char *path, const char *root, unsigned chase_flags, int open_flags, char **ret_path);
int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chase_flags, char **ret_path, DIR **ret_dir);
/* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */
static inline void rmdir_and_free(char *p) { static inline void rmdir_and_free(char *p) {
PROTECT_ERRNO; PROTECT_ERRNO;

View File

@@ -586,7 +586,7 @@ static int base64_append_width(
if (len <= 0) if (len <= 0)
return len; return len;
lines = (len + width - 1) / width; lines = DIV_ROUND_UP(len, width);
slen = strlen_ptr(sep); slen = strlen_ptr(sep);
t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines); t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);

View File

@@ -149,19 +149,6 @@ int log_object_internal(
const char *extra, const char *extra,
const char *format, ...) _printf_(10,11); const char *format, ...) _printf_(10,11);
int log_object_internalv(
int level,
int error,
const char *file,
int line,
const char *func,
const char *object_field,
const char *object,
const char *extra_field,
const char *extra,
const char *format,
va_list ap) _printf_(10,0);
int log_struct_internal( int log_struct_internal(
int level, int level,
int error, int error,
@@ -204,7 +191,7 @@ int log_dump_internal(
char *buffer); char *buffer);
/* Logging for various assertions */ /* Logging for various assertions */
noreturn void log_assert_failed_realm( _noreturn_ void log_assert_failed_realm(
LogRealm realm, LogRealm realm,
const char *text, const char *text,
const char *file, const char *file,
@@ -213,7 +200,7 @@ noreturn void log_assert_failed_realm(
#define log_assert_failed(text, ...) \ #define log_assert_failed(text, ...) \
log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__) log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__)
noreturn void log_assert_failed_unreachable_realm( _noreturn_ void log_assert_failed_unreachable_realm(
LogRealm realm, LogRealm realm,
const char *text, const char *text,
const char *file, const char *file,

View File

@@ -53,6 +53,26 @@
#else #else
#define _fallthrough_ #define _fallthrough_
#endif #endif
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
* compiler versions */
#ifndef _noreturn_
#if __STDC_VERSION__ >= 201112L
#define _noreturn_ _Noreturn
#else
#define _noreturn_ __attribute__((noreturn))
#endif
#endif
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
# if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# define HAS_FEATURE_MEMORY_SANITIZER 1
# endif
# endif
# if !defined(HAS_FEATURE_MEMORY_SANITIZER)
# define HAS_FEATURE_MEMORY_SANITIZER 0
# endif
#endif
#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__) #if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__)
/* Temporarily disable some warnings */ /* Temporarily disable some warnings */
@@ -423,21 +443,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#endif #endif
#endif #endif
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
* compiler versions */
#ifndef noreturn
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#else
#define noreturn __attribute__((noreturn))
#endif
#endif
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \ static inline void func##p(type *p) { \
if (*p) \ if (*p) \
func(*p); \ func(*p); \
} \ }
struct __useless_struct_to_allow_trailing_semicolon__
#include "log.h" #include "log.h"

View File

@@ -327,8 +327,7 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
return -EINVAL; return -EINVAL;
*error = e; *error = e;
*name = n; *name = TAKE_PTR(n);
n = NULL;
return 0; return 0;
} }
@@ -375,12 +374,13 @@ finish:
} }
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
int safe_atou(const char *s, unsigned *ret_u) { int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
char *x = NULL; char *x = NULL;
unsigned long l; unsigned long l;
assert(s); assert(s);
assert(ret_u); assert(ret_u);
assert(base <= 16);
/* strtoul() is happy to parse negative values, and silently /* strtoul() is happy to parse negative values, and silently
* converts them to unsigned values without generating an * converts them to unsigned values without generating an
@@ -393,7 +393,7 @@ int safe_atou(const char *s, unsigned *ret_u) {
s += strspn(s, WHITESPACE); s += strspn(s, WHITESPACE);
errno = 0; errno = 0;
l = strtoul(s, &x, 0); l = strtoul(s, &x, base);
if (errno > 0) if (errno > 0)
return -errno; return -errno;
if (!x || x == s || *x != 0) if (!x || x == s || *x != 0)
@@ -491,17 +491,18 @@ int safe_atou8(const char *s, uint8_t *ret) {
return 0; return 0;
} }
int safe_atou16(const char *s, uint16_t *ret) { int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
char *x = NULL; char *x = NULL;
unsigned long l; unsigned long l;
assert(s); assert(s);
assert(ret); assert(ret);
assert(base <= 16);
s += strspn(s, WHITESPACE); s += strspn(s, WHITESPACE);
errno = 0; errno = 0;
l = strtoul(s, &x, 0); l = strtoul(s, &x, base);
if (errno > 0) if (errno > 0)
return -errno; return -errno;
if (!x || x == s || *x != 0) if (!x || x == s || *x != 0)
@@ -536,30 +537,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
} }
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
int safe_atoux16(const char *s, uint16_t *ret) {
char *x = NULL;
unsigned long l;
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoul(s, &x, 16);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
if (s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint16_t) l != l)
return -ERANGE;
*ret = (uint16_t) l;
return 0;
}
int safe_atod(const char *s, double *ret_d) { int safe_atod(const char *s, double *ret_d) {
_cleanup_(freelocalep) locale_t loc = (locale_t) 0; _cleanup_(freelocalep) locale_t loc = (locale_t) 0;
char *x = NULL; char *x = NULL;

View File

@@ -44,17 +44,29 @@ int parse_syscall_and_errno(const char *in, char **name, int *error);
#define FORMAT_BYTES_MAX 8 #define FORMAT_BYTES_MAX 8
char *format_bytes(char *buf, size_t l, uint64_t t); char *format_bytes(char *buf, size_t l, uint64_t t);
int safe_atou(const char *s, unsigned *ret_u); int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
static inline int safe_atou(const char *s, unsigned *ret_u) {
return safe_atou_full(s, 0, ret_u);
}
int safe_atoi(const char *s, int *ret_i); int safe_atoi(const char *s, int *ret_i);
int safe_atollu(const char *s, unsigned long long *ret_u); int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i); int safe_atolli(const char *s, long long int *ret_i);
int safe_atou8(const char *s, uint8_t *ret); int safe_atou8(const char *s, uint8_t *ret);
int safe_atou16(const char *s, uint16_t *ret); int safe_atou16_full(const char *s, unsigned base, uint16_t *ret);
int safe_atoi16(const char *s, int16_t *ret);
int safe_atoux16(const char *s, uint16_t *ret); static inline int safe_atou16(const char *s, uint16_t *ret) {
return safe_atou16_full(s, 0, ret);
}
static inline int safe_atoux16(const char *s, uint16_t *ret) {
return safe_atou16_full(s, 16, ret);
}
int safe_atoi16(const char *s, int16_t *ret);
static inline int safe_atou32(const char *s, uint32_t *ret_u) { static inline int safe_atou32(const char *s, uint32_t *ret_u) {
assert_cc(sizeof(uint32_t) == sizeof(unsigned)); assert_cc(sizeof(uint32_t) == sizeof(unsigned));

View File

@@ -293,8 +293,7 @@ char **path_strv_resolve(char **l, const char *root) {
r = chase_symlinks(t, root, 0, &u); r = chase_symlinks(t, root, 0, &u);
if (r == -ENOENT) { if (r == -ENOENT) {
if (root) { if (root) {
u = orig; u = TAKE_PTR(orig);
orig = NULL;
free(t); free(t);
} else } else
u = t; u = t;

View File

@@ -29,8 +29,14 @@
#include "time-util.h" #include "time-util.h"
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" #if HAVE_SPLIT_BIN
#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" # define PATH_SBIN_BIN(x) x "sbin:" x "bin"
#else
# define PATH_SBIN_BIN(x) x "bin"
#endif
#define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/")
#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/")
#if HAVE_SPLIT_USR #if HAVE_SPLIT_USR
# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR

View File

@@ -175,7 +175,7 @@ int prioq_put(Prioq *q, void *data, unsigned *idx) {
struct prioq_item *j; struct prioq_item *j;
n = MAX((q->n_items+1) * 2, 16u); n = MAX((q->n_items+1) * 2, 16u);
j = realloc(q->items, sizeof(struct prioq_item) * n); j = reallocarray(q->items, n, sizeof(struct prioq_item));
if (!j) if (!j)
return -ENOMEM; return -ENOMEM;

View File

@@ -628,8 +628,7 @@ int get_process_environ(pid_t pid, char **env) {
} else } else
outcome[sz] = '\0'; outcome[sz] = '\0';
*env = outcome; *env = TAKE_PTR(outcome);
outcome = NULL;
return 0; return 0;
} }
@@ -994,7 +993,7 @@ bool is_main_thread(void) {
} }
#if 0 /* NM_IGNORED */ #if 0 /* NM_IGNORED */
noreturn void freeze(void) { _noreturn_ void freeze(void) {
log_close(); log_close();
@@ -1174,6 +1173,7 @@ extern int __register_atfork(void (*prepare) (void), void (*parent) (void), void
extern void* __dso_handle __attribute__ ((__weak__)); extern void* __dso_handle __attribute__ ((__weak__));
pid_t getpid_cached(void) { pid_t getpid_cached(void) {
static bool installed = false;
pid_t current_value; pid_t current_value;
/* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a /* getpid_cached() is much like getpid(), but caches the value in local memory, to avoid having to invoke a
@@ -1194,10 +1194,18 @@ pid_t getpid_cached(void) {
new_pid = raw_getpid(); new_pid = raw_getpid();
if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) { if (!installed) {
/* OOM? Let's try again later */ /* __register_atfork() either returns 0 or -ENOMEM, in its glibc implementation. Since it's
cached_pid = CACHED_PID_UNSET; * only half-documented (glibc doesn't document it but LSB does — though only superficially)
return new_pid; * we'll check for errors only in the most generic fashion possible. */
if (__register_atfork(NULL, NULL, reset_cached_pid, __dso_handle) != 0) {
/* OOM? Let's try again later */
cached_pid = CACHED_PID_UNSET;
return new_pid;
}
installed = true;
} }
cached_pid = new_pid; cached_pid = new_pid;
@@ -1437,8 +1445,7 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (fd > STDERR_FILENO) safe_close_above_stdio(fd);
close(fd);
} }
/* Count arguments */ /* Count arguments */
@@ -1467,7 +1474,7 @@ static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_IDLE] = "idle" [IOPRIO_CLASS_IDLE] = "idle"
}; };
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, IOPRIO_N_CLASSES);
static const char *const sigchld_code_table[] = { static const char *const sigchld_code_table[] = {
[CLD_EXITED] = "exited", [CLD_EXITED] = "exited",

View File

@@ -91,7 +91,7 @@ int pid_from_same_root_fs(pid_t pid);
bool is_main_thread(void); bool is_main_thread(void);
noreturn void freeze(void); _noreturn_ void freeze(void);
bool oom_score_adjust_is_valid(int oa); bool oom_score_adjust_is_valid(int oa);

View File

@@ -988,8 +988,7 @@ int getpeersec(int fd, char **ret) {
if (isempty(s)) if (isempty(s))
return -EOPNOTSUPP; return -EOPNOTSUPP;
*ret = s; *ret = TAKE_PTR(s);
s = NULL;
return 0; return 0;
} }

View File

@@ -27,9 +27,11 @@
#include "macro.h" #include "macro.h"
#define xsprintf(buf, fmt, ...) \ #define snprintf_ok(buf, len, fmt, ...) \
assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
#define xsprintf(buf, fmt, ...) \
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
#define VA_FORMAT_ADVANCE(format, ap) \ #define VA_FORMAT_ADVANCE(format, ap) \
do { \ do { \

View File

@@ -93,13 +93,11 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope)
struct __useless_struct_to_allow_trailing_semicolon__
#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ #define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope)
struct __useless_struct_to_allow_trailing_semicolon__
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
@@ -111,8 +109,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
/* For string conversions where numbers are also acceptable */ /* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,)
struct __useless_struct_to_allow_trailing_semicolon__
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \ #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static)

View File

@@ -216,7 +216,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
p = strv_length(*a); p = strv_length(*a);
q = strv_length(b); q = strv_length(b);
t = realloc(*a, sizeof(char*) * (p + q + 1)); t = reallocarray(*a, p + q + 1, sizeof(char *));
if (!t) if (!t)
return -ENOMEM; return -ENOMEM;
@@ -344,8 +344,7 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
if (!GREEDY_REALLOC(l, allocated, n + 2)) if (!GREEDY_REALLOC(l, allocated, n + 2))
return -ENOMEM; return -ENOMEM;
l[n++] = word; l[n++] = TAKE_PTR(word);
word = NULL;
l[n] = NULL; l[n] = NULL;
} }
@@ -356,8 +355,7 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
return -ENOMEM; return -ENOMEM;
} }
*t = l; *t = TAKE_PTR(l);
l = NULL;
return (int) n; return (int) n;
} }
@@ -411,7 +409,7 @@ int strv_push(char ***l, char *value) {
if (m < n) if (m < n)
return -ENOMEM; return -ENOMEM;
c = realloc_multiply(*l, sizeof(char*), m); c = reallocarray(*l, m, sizeof(char*));
if (!c) if (!c)
return -ENOMEM; return -ENOMEM;
@@ -436,7 +434,7 @@ int strv_push_pair(char ***l, char *a, char *b) {
if (m < n) if (m < n)
return -ENOMEM; return -ENOMEM;
c = realloc_multiply(*l, sizeof(char*), m); c = reallocarray(*l, m, sizeof(char*));
if (!c) if (!c)
return -ENOMEM; return -ENOMEM;
@@ -550,7 +548,7 @@ int strv_extend_front(char ***l, const char *value) {
if (!v) if (!v)
return -ENOMEM; return -ENOMEM;
c = realloc_multiply(*l, sizeof(char*), m); c = reallocarray(*l, m, sizeof(char*));
if (!c) { if (!c) {
free(v); free(v);
return -ENOMEM; return -ENOMEM;
@@ -865,7 +863,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) {
k = strv_length(*l); k = strv_length(*l);
nl = realloc(*l, sizeof(char*) * (k + n + 1)); nl = reallocarray(*l, k + n + 1, sizeof(char *));
if (!nl) if (!nl)
return -ENOMEM; return -ENOMEM;

View File

@@ -186,11 +186,13 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
const void *p; const void *p;
int comparison; int comparison;
assert(!size_multiply_overflow(nmemb, size));
l = 0; l = 0;
u = nmemb; u = nmemb;
while (l < u) { while (l < u) {
idx = (l + u) / 2; idx = (l + u) / 2;
p = (const char *) base + idx * size; p = (const uint8_t*) base + idx * size;
comparison = compar(key, p, arg); comparison = compar(key, p, arg);
if (comparison < 0) if (comparison < 0)
u = idx; u = idx;

View File

@@ -91,6 +91,19 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *), int (*compar) (const void *, const void *, void *),
void *arg); void *arg);
/**
* Normal bsearch requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
static inline void* bsearch_safe(const void *key, const void *base,
size_t nmemb, size_t size, comparison_fn_t compar) {
if (nmemb <= 0)
return NULL;
assert(base);
return bsearch(key, base, nmemb, size, compar);
}
/** /**
* Normal qsort requires base to be nonnull. Here were require * Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0. * that only if nmemb > 0.

View File

@@ -105,10 +105,7 @@ int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_
if (r < 0) if (r < 0)
return -errno; return -errno;
r = s; return TAKE_FD(s);
s = -1;
return r;
} }
static int arp_send_packet(int fd, int ifindex, static int arp_send_packet(int fd, int ifindex,

View File

@@ -125,10 +125,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
if (r < 0) if (r < 0)
return -errno; return -errno;
r = s; return TAKE_FD(s);
s = -1;
return r;
} }
int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
@@ -213,10 +210,7 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
if (r < 0) if (r < 0)
return -errno; return -errno;
r = s; return TAKE_FD(s);
s = -1;
return r;
} }
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,

View File

@@ -255,10 +255,8 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c
if (message_type == 0) if (message_type == 0)
return -ENOMSG; return -ENOMSG;
if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) { if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE))
*_error_message = error_message; *_error_message = TAKE_PTR(error_message);
error_message = NULL;
}
return message_type; return message_type;
} }

View File

@@ -69,9 +69,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
if (r < 0) if (r < 0)
return -errno; return -errno;
r = s; return TAKE_FD(s);
s = -1;
return r;
} }
int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,

View File

@@ -619,8 +619,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
idx++; idx++;
} }
*str_arr = names; *str_arr = TAKE_PTR(names);
names = NULL;
return idx; return idx;

View File

@@ -94,8 +94,5 @@ int lldp_network_bind_raw_socket(int ifindex) {
if (r < 0) if (r < 0)
return -errno; return -errno;
r = fd; return TAKE_FD(fd);
fd = -1;
return r;
} }

View File

@@ -279,10 +279,9 @@ int config_parse_ifalias(const char *unit,
} }
free(*s); free(*s);
if (*n) { if (*n)
*s = n; *s = TAKE_PTR(n);
n = NULL; else
} else
*s = NULL; *s = NULL;
return 0; return 0;
@@ -428,7 +427,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
if (r == 0) if (r == 0)
break; break;
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr));
if (!new_addresses) if (!new_addresses)
return -ENOMEM; return -ENOMEM;
else else
@@ -441,8 +440,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
size++; size++;
} }
*ret = addresses; *ret = TAKE_PTR(addresses);
addresses = NULL;
return size; return size;
} }
@@ -482,7 +480,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
if (r == 0) if (r == 0)
break; break;
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr));
if (!new_addresses) if (!new_addresses)
return -ENOMEM; return -ENOMEM;
else else
@@ -495,8 +493,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
size++; size++;
} }
*ret = addresses; *ret = TAKE_PTR(addresses);
addresses = NULL;
return size; return size;
} }
@@ -589,8 +586,7 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
*ret_size = size; *ret_size = size;
*ret_allocated = allocated; *ret_allocated = allocated;
*ret = routes; *ret = TAKE_PTR(routes);
routes = NULL;
return 0; return 0;
} }

View File

@@ -358,9 +358,10 @@ int sd_dhcp_client_set_client_id(
* without further modification. Otherwise, if duid_type is supported, DUID * without further modification. Otherwise, if duid_type is supported, DUID
* is set based on that type. Otherwise, an error is returned. * is set based on that type. Otherwise, an error is returned.
*/ */
int sd_dhcp_client_set_iaid_duid( static int dhcp_client_set_iaid_duid(
sd_dhcp_client *client, sd_dhcp_client *client,
uint32_t iaid, uint32_t iaid,
bool append_iaid,
uint16_t duid_type, uint16_t duid_type,
const void *duid, const void *duid,
size_t duid_len) { size_t duid_len) {
@@ -381,15 +382,17 @@ int sd_dhcp_client_set_iaid_duid(
zero(client->client_id); zero(client->client_id);
client->client_id.type = 255; client->client_id.type = 255;
/* If IAID is not configured, generate it. */ if (append_iaid) {
if (iaid == 0) { /* If IAID is not configured, generate it. */
r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, if (iaid == 0) {
client->mac_addr_len, r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr,
&client->client_id.ns.iaid); client->mac_addr_len,
if (r < 0) &client->client_id.ns.iaid);
return r; if (r < 0)
} else return r;
client->client_id.ns.iaid = htobe32(iaid); } else
client->client_id.ns.iaid = htobe32(iaid);
}
if (duid != NULL) { if (duid != NULL) {
client->client_id.ns.duid.type = htobe16(duid_type); client->client_id.ns.duid.type = htobe16(duid_type);
@@ -403,7 +406,7 @@ int sd_dhcp_client_set_iaid_duid(
return -EOPNOTSUPP; return -EOPNOTSUPP;
client->client_id_len = sizeof(client->client_id.type) + len + client->client_id_len = sizeof(client->client_id.type) + len +
sizeof(client->client_id.ns.iaid); (append_iaid ? sizeof(client->client_id.ns.iaid) : 0);
if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
log_dhcp_client(client, "Configured IAID+DUID, restarting."); log_dhcp_client(client, "Configured IAID+DUID, restarting.");
@@ -413,6 +416,23 @@ int sd_dhcp_client_set_iaid_duid(
return 0; return 0;
} }
int sd_dhcp_client_set_iaid_duid(
sd_dhcp_client *client,
uint32_t iaid,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len);
}
int sd_dhcp_client_set_duid(
sd_dhcp_client *client,
uint16_t duid_type,
const void *duid,
size_t duid_len) {
return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len);
}
#endif /* NM_IGNORED */ #endif /* NM_IGNORED */
int sd_dhcp_client_set_hostname( int sd_dhcp_client_set_hostname(

View File

@@ -809,8 +809,7 @@ int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***d
pos = next_chunk; pos = next_chunk;
} }
*domains = names; *domains = TAKE_PTR(names);
names = NULL;
return cnt; return cnt;
} }

View File

@@ -302,8 +302,7 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {
if (r < 0) if (r < 0)
return r; return r;
*ret = s; *ret = TAKE_PTR(s);
s = NULL;
return r; return r;
} }
@@ -610,8 +609,7 @@ int dns_name_endswith(const char *name, const char *suffix) {
/* Not the same, let's jump back, and try with the next label again */ /* Not the same, let's jump back, and try with the next label again */
s = suffix; s = suffix;
n = saved_n; n = TAKE_PTR(saved_n);
saved_n = NULL;
} }
} }
} }

View File

@@ -132,6 +132,11 @@ int sd_dhcp_client_set_iaid_duid(
uint16_t duid_type, uint16_t duid_type,
const void *duid, const void *duid,
size_t duid_len); size_t duid_len);
int sd_dhcp_client_set_duid(
sd_dhcp_client *client,
uint16_t duid_type,
const void *duid,
size_t duid_len);
int sd_dhcp_client_get_client_id( int sd_dhcp_client_get_client_id(
sd_dhcp_client *client, sd_dhcp_client *client,
uint8_t *type, uint8_t *type,