Merge pull request #14218 from poettering/homed-preparatory-small-stuff

Assorted smaller stuff split out from homed PR
This commit is contained in:
Lennart Poettering 2019-12-04 13:13:38 +01:00 committed by GitHub
commit f9f8268ac6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 149 additions and 56 deletions

View file

@ -101,3 +101,11 @@ static inline bool ERRNO_IS_PRIVILEGE(int r) {
EACCES,
EPERM);
}
/* Three difference errors for "not enough disk space" */
static inline bool ERRNO_IS_DISK_SPACE(int r) {
return IN_SET(abs(r),
ENOSPC,
EDQUOT,
EFBIG);
}

View file

@ -80,14 +80,21 @@ static inline void* explicit_bzero_safe(void *p, size_t l) {
void *explicit_bzero_safe(void *p, size_t l);
#endif
static inline void erase_and_freep(void *p) {
void *ptr = *(void**) p;
static inline void* erase_and_free(void *p) {
size_t l;
if (ptr) {
size_t l = malloc_usable_size(ptr);
explicit_bzero_safe(ptr, l);
free(ptr);
}
if (!p)
return NULL;
l = malloc_usable_size(p);
explicit_bzero_safe(p, l);
free(p);
return NULL;
}
static inline void erase_and_freep(void *p) {
erase_and_free(*(void**) p);
}
/* Use with _cleanup_ to erase a single 'char' when leaving scope */

View file

@ -50,6 +50,10 @@ static inline void* ordered_set_remove(OrderedSet *s, void *p) {
return ordered_hashmap_remove((OrderedHashmap*) s, p);
}
static inline void* ordered_set_first(OrderedSet *s) {
return ordered_hashmap_first((OrderedHashmap*) s);
}
static inline void* ordered_set_steal_first(OrderedSet *s) {
return ordered_hashmap_steal_first((OrderedHashmap*) s);
}

View file

@ -365,7 +365,6 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
unsigned long l;
assert(s);
assert(ret_u);
assert(base <= 16);
/* strtoul() is happy to parse negative values, and silently
@ -389,7 +388,9 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
if ((unsigned long) (unsigned) l != l)
return -ERANGE;
*ret_u = (unsigned) l;
if (ret_u)
*ret_u = (unsigned) l;
return 0;
}
@ -398,7 +399,6 @@ int safe_atoi(const char *s, int *ret_i) {
long l;
assert(s);
assert(ret_i);
errno = 0;
l = strtol(s, &x, 0);
@ -409,7 +409,9 @@ int safe_atoi(const char *s, int *ret_i) {
if ((long) (int) l != l)
return -ERANGE;
*ret_i = (int) l;
if (ret_i)
*ret_i = (int) l;
return 0;
}
@ -418,7 +420,6 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
unsigned long long l;
assert(s);
assert(ret_llu);
s += strspn(s, WHITESPACE);
@ -431,7 +432,9 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
if (*s == '-')
return -ERANGE;
*ret_llu = l;
if (ret_llu)
*ret_llu = l;
return 0;
}
@ -440,7 +443,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
long long l;
assert(s);
assert(ret_lli);
errno = 0;
l = strtoll(s, &x, 0);
@ -449,7 +451,9 @@ int safe_atolli(const char *s, long long int *ret_lli) {
if (!x || x == s || *x != 0)
return -EINVAL;
*ret_lli = l;
if (ret_lli)
*ret_lli = l;
return 0;
}
@ -458,7 +462,6 @@ int safe_atou8(const char *s, uint8_t *ret) {
unsigned long l;
assert(s);
assert(ret);
s += strspn(s, WHITESPACE);
@ -473,7 +476,8 @@ int safe_atou8(const char *s, uint8_t *ret) {
if ((unsigned long) (uint8_t) l != l)
return -ERANGE;
*ret = (uint8_t) l;
if (ret)
*ret = (uint8_t) l;
return 0;
}
@ -507,7 +511,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
long l;
assert(s);
assert(ret);
errno = 0;
l = strtol(s, &x, 0);
@ -518,7 +521,9 @@ int safe_atoi16(const char *s, int16_t *ret) {
if ((long) (int16_t) l != l)
return -ERANGE;
*ret = (int16_t) l;
if (ret)
*ret = (int16_t) l;
return 0;
}
@ -528,7 +533,6 @@ int safe_atod(const char *s, double *ret_d) {
double d = 0;
assert(s);
assert(ret_d);
loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
if (loc == (locale_t) 0)
@ -541,7 +545,9 @@ int safe_atod(const char *s, double *ret_d) {
if (!x || x == s || *x != 0)
return -EINVAL;
*ret_d = (double) d;
if (ret_d)
*ret_d = (double) d;
return 0;
}

View file

@ -1338,6 +1338,13 @@ int safe_fork_full(
log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
_exit(EXIT_FAILURE);
}
} else if (flags & FORK_STDOUT_TO_STDERR) {
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
log_full_errno(prio, r, "Failed to connect stdout to stderr: %m");
_exit(EXIT_FAILURE);
}
}
if (flags & FORK_RLIMIT_NOFILE_SAFE) {

View file

@ -147,16 +147,17 @@ void reset_cached_pid(void);
int must_be_root(void);
typedef enum ForkFlags {
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */
FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */
FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */
FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */
FORK_WAIT = 1 << 6, /* Wait until child exited */
FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
FORK_RESET_SIGNALS = 1 << 0, /* Reset all signal handlers and signal mask */
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child */
FORK_NULL_STDIO = 1 << 3, /* Connect 0,1,2 to /dev/null */
FORK_REOPEN_LOG = 1 << 4, /* Reopen log connection */
FORK_LOG = 1 << 5, /* Log above LOG_DEBUG log level about failures */
FORK_WAIT = 1 << 6, /* Wait until child exited */
FORK_NEW_MOUNTNS = 1 << 7, /* Run child in its own mount namespace */
FORK_MOUNTNS_SLAVE = 1 << 8, /* Make child's mount namespace MS_SLAVE */
FORK_RLIMIT_NOFILE_SAFE = 1 << 9, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */
FORK_STDOUT_TO_STDERR = 1 << 10, /* Make stdout a copy of stderr */
} ForkFlags;
int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);

View file

@ -1064,3 +1064,13 @@ bool string_is_safe(const char *p) {
return true;
}
char* string_erase(char *x) {
if (!x)
return NULL;
/* A delicious drop of snake-oil! To be called on memory where we stored passphrases or so, after we
* used them. */
explicit_bzero_safe(x, strlen(x));
return x;
}

View file

@ -278,3 +278,5 @@ static inline char* str_realloc(char **p) {
return (*p = t);
}
char* string_erase(char *x);

View file

@ -19,50 +19,60 @@
#include "tmpfile-util.h"
#include "umask-util.h"
int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
FILE *f;
char *t;
int r, fd;
int fopen_temporary(const char *path, FILE **ret_f, char **ret_temp_path) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *t = NULL;
_cleanup_close_ int fd = -1;
int r;
assert(path);
assert(_f);
assert(_temp_path);
if (path) {
r = tempfn_xxxxxx(path, NULL, &t);
if (r < 0)
return r;
} else {
const char *d;
r = tempfn_xxxxxx(path, NULL, &t);
if (r < 0)
return r;
r = tmp_dir(&d);
if (r < 0)
return r;
t = path_join(d, "XXXXXX");
if (!t)
return -ENOMEM;
}
fd = mkostemp_safe(t);
if (fd < 0) {
free(t);
if (fd < 0)
return -errno;
}
/* This assumes that returned FILE object is short-lived and used within the same single-threaded
* context and never shared externally, hence locking is not necessary. */
r = fdopen_unlocked(fd, "w", &f);
if (r < 0) {
unlink(t);
free(t);
safe_close(fd);
(void) unlink(t);
return r;
}
*_f = f;
*_temp_path = t;
TAKE_FD(fd);
if (ret_f)
*ret_f = TAKE_PTR(f);
if (ret_temp_path)
*ret_temp_path = TAKE_PTR(t);
return 0;
}
/* This is much like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern) {
_unused_ _cleanup_umask_ mode_t u = umask(0077);
int fd;
assert(pattern);
fd = mkostemp(pattern, O_CLOEXEC);
RUN_WITH_UMASK(0077)
fd = mkostemp(pattern, O_CLOEXEC);
if (fd < 0)
return -errno;

View file

@ -84,7 +84,7 @@ char *getusername_malloc(void) {
return uid_to_name(getuid());
}
static bool is_nologin_shell(const char *shell) {
bool is_nologin_shell(const char *shell) {
return PATH_IN_SET(shell,
/* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice

View file

@ -57,6 +57,14 @@ int take_etc_passwd_lock(const char *root);
#define ETC_PASSWD_LOCK_PATH "/etc/.pwd.lock"
static inline bool uid_is_system(uid_t uid) {
return uid <= SYSTEM_UID_MAX;
}
static inline bool gid_is_system(gid_t gid) {
return gid <= SYSTEM_GID_MAX;
}
static inline bool uid_is_dynamic(uid_t uid) {
return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
}
@ -65,12 +73,12 @@ static inline bool gid_is_dynamic(gid_t gid) {
return uid_is_dynamic((uid_t) gid);
}
static inline bool uid_is_system(uid_t uid) {
return uid <= SYSTEM_UID_MAX;
static inline bool uid_is_container(uid_t uid) {
return CONTAINER_UID_BASE_MIN <= uid && uid <= CONTAINER_UID_BASE_MAX;
}
static inline bool gid_is_system(gid_t gid) {
return gid <= SYSTEM_GID_MAX;
static inline bool gid_is_container(gid_t gid) {
return uid_is_container((uid_t) gid);
}
/* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer
@ -127,3 +135,5 @@ int putsgent_sane(const struct sgrp *sg, FILE *stream);
#endif
int make_salt(char **ret);
bool is_nologin_shell(const char *shell);

View file

@ -3,6 +3,8 @@
#include <stdlib.h>
#include "sd-daemon.h"
#include "pager.h"
#include "selinux-util.h"
#include "spawn-ask-password-agent.h"
@ -16,6 +18,8 @@
save_argc_argv(argc, argv); \
intro; \
r = impl; \
if (r < 0) \
(void) sd_notifyf(0, "ERRNO=%i", -r); \
ask_password_agent_close(); \
polkit_agent_close(); \
pager_close(); \

View file

@ -9,6 +9,29 @@
#include "utf8.h"
#include "util.h"
static void test_string_erase(void) {
char *x;
x = strdupa("");
assert_se(streq(string_erase(x), ""));
x = strdupa("1");
assert_se(streq(string_erase(x), ""));
x = strdupa("123456789");
assert_se(streq(string_erase(x), ""));
assert_se(x[1] == '\0');
assert_se(x[2] == '\0');
assert_se(x[3] == '\0');
assert_se(x[4] == '\0');
assert_se(x[5] == '\0');
assert_se(x[6] == '\0');
assert_se(x[7] == '\0');
assert_se(x[8] == '\0');
assert_se(x[9] == '\0');
}
static void test_free_and_strndup_one(char **t, const char *src, size_t l, const char *expected, bool change) {
int r;
@ -543,6 +566,7 @@ static void test_memory_startswith_no_case(void) {
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_string_erase();
test_free_and_strndup();
test_ascii_strcasecmp_n();
test_ascii_strcasecmp_nn();