diff options
Diffstat (limited to 'shared')
23 files changed, 363 insertions, 103 deletions
diff --git a/shared/systemd/src/basic/fileio.c b/shared/systemd/src/basic/fileio.c index f2f1e1139f..c3d55d209a 100644 --- a/shared/systemd/src/basic/fileio.c +++ b/shared/systemd/src/basic/fileio.c @@ -22,6 +22,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "socket-util.h" #include "stdio-util.h" #include "string-util.h" #include "tmpfile-util.h" @@ -482,13 +483,12 @@ int read_full_stream_full( assert(f); assert(ret_contents); assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)); - assert(!(flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) || ret_size); n_next = LINE_MAX; /* Start size */ fd = fileno(f); - if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's - * optimize our buffering) */ + if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's + * optimize our buffering */ if (fstat(fd, &st) < 0) return -errno; @@ -505,7 +505,7 @@ int read_full_stream_full( if (st.st_size > 0) n_next = st.st_size + 1; - if (flags & READ_FULL_FILE_SECURE) + if (flags & READ_FULL_FILE_WARN_WORLD_READABLE) (void) warn_file_is_world_accessible(filename, &st, NULL, 0); } } @@ -535,21 +535,18 @@ int read_full_stream_full( errno = 0; k = fread(buf + l, 1, n - l, f); - if (k > 0) - l += k; + + assert(k <= n - l); + l += k; if (ferror(f)) { r = errno_or_else(EIO); goto finalize; } - if (feof(f)) break; - /* We aren't expecting fread() to return a short read outside - * of (error && eof), assert buffer is full and enlarge buffer. - */ - assert(l == n); + assert(k > 0); /* we can't have read zero bytes because that would have been EOF */ /* Safety check */ if (n >= READ_FULL_BYTES_MAX) { @@ -561,12 +558,21 @@ int read_full_stream_full( } if (flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) { + _cleanup_free_ void *decoded = NULL; + size_t decoded_size; + buf[l++] = 0; if (flags & READ_FULL_FILE_UNBASE64) - r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size); + r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size); else - r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size); - goto finalize; + r = unhexmem_full(buf, l, flags & READ_FULL_FILE_SECURE, &decoded, &decoded_size); + if (r < 0) + goto finalize; + + if (flags & READ_FULL_FILE_SECURE) + explicit_bzero_safe(buf, n); + free_and_replace(buf, decoded); + n = l = decoded_size; } if (!ret_size) { @@ -603,8 +609,54 @@ int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flag assert(contents); r = xfopenat(dir_fd, filename, "re", 0, &f); - if (r < 0) - return r; + if (r < 0) { + _cleanup_close_ int dfd = -1, sk = -1; + union sockaddr_union sa; + + /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */ + if (r != -ENXIO) + return r; + + /* If this is enabled, let's try to connect to it */ + if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET)) + return -ENXIO; + + if (dir_fd == AT_FDCWD) + r = sockaddr_un_set_path(&sa.un, filename); + else { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + /* If we shall operate relative to some directory, then let's use O_PATH first to + * open the socket inode, and then connect to it via /proc/self/fd/. We have to do + * this since there's not connectat() that takes a directory fd as first arg. */ + + dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC); + if (dfd < 0) + return -errno; + + xsprintf(procfs_path, "/proc/self/fd/%i", dfd); + r = sockaddr_un_set_path(&sa.un, procfs_path); + } + if (r < 0) + return r; + + sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (sk < 0) + return -errno; + + if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) + return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is + * not a socket after all */ + + if (shutdown(sk, SHUT_WR) < 0) + return -errno; + + f = fdopen(sk, "r"); + if (!f) + return -errno; + + TAKE_FD(sk); + } (void) __fsetlocking(f, FSETLOCKING_BYCALLER); diff --git a/shared/systemd/src/basic/fileio.h b/shared/systemd/src/basic/fileio.h index e2830b7963..7d58fa7cfc 100644 --- a/shared/systemd/src/basic/fileio.h +++ b/shared/systemd/src/basic/fileio.h @@ -32,9 +32,11 @@ typedef enum { } WriteStringFileFlags; typedef enum { - READ_FULL_FILE_SECURE = 1 << 0, - READ_FULL_FILE_UNBASE64 = 1 << 1, - READ_FULL_FILE_UNHEX = 1 << 2, + READ_FULL_FILE_SECURE = 1 << 0, /* erase any buffers we employ internally, after use */ + READ_FULL_FILE_UNBASE64 = 1 << 1, /* base64 decode what we read */ + READ_FULL_FILE_UNHEX = 1 << 2, /* hex decode what we read */ + READ_FULL_FILE_WARN_WORLD_READABLE = 1 << 3, /* if regular file, log at LOG_WARNING level if access mode above 0700 */ + READ_FULL_FILE_CONNECT_SOCKET = 1 << 4, /* if socket inode, connect to it and read off it */ } ReadFullFileFlags; int fopen_unlocked(const char *path, const char *options, FILE **ret); diff --git a/shared/systemd/src/basic/fs-util.c b/shared/systemd/src/basic/fs-util.c index 943bc56319..34a2260783 100644 --- a/shared/systemd/src/basic/fs-util.c +++ b/shared/systemd/src/basic/fs-util.c @@ -1576,7 +1576,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) { d = opendir(p); if (!d) { - if (errno == ENOENT) /* Doesn't have slaves */ + if (errno == ENOENT) /* Doesn't have underlying devices */ return false; return -errno; @@ -1592,7 +1592,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) { if (errno != 0) return -errno; - break; /* No more slaves */ + break; /* No more underlying devices */ } q = path_join(p, de->d_name); diff --git a/shared/systemd/src/basic/hashmap.c b/shared/systemd/src/basic/hashmap.c index 15c8c4723c..67c4391230 100644 --- a/shared/systemd/src/basic/hashmap.c +++ b/shared/systemd/src/basic/hashmap.c @@ -768,7 +768,7 @@ static void reset_direct_storage(HashmapBase *h) { memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); } -static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { +static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; bool up; @@ -808,19 +808,19 @@ static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enu } Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); + return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); } OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); + return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); } Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); + return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); } static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops, - enum HashmapType type HASHMAP_DEBUG_PARAMS) { + enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *q; assert(h); @@ -828,7 +828,7 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops if (*h) return 0; - q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); + q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); if (!q) return -ENOMEM; @@ -837,15 +837,15 @@ static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops } int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); } int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); } int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { - return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); + return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); } static void hashmap_free_no_clear(HashmapBase *h) { @@ -1247,6 +1247,30 @@ int set_put(Set *s, const void *key) { return hashmap_put_boldly(s, hash, &swap, true); } +int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS) { + int r; + + r = _set_ensure_allocated(s, hash_ops HASHMAP_DEBUG_PASS_ARGS); + if (r < 0) + return r; + + return set_put(*s, key); +} + +int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS) { + int r; + + r = _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_PASS_ARGS); + if (r <= 0) { + if (hash_ops && hash_ops->free_key) + hash_ops->free_key(key); + else + free(key); + } + + return r; +} + int hashmap_replace(Hashmap *h, const void *key, void *value) { struct swap_entries swap; struct plain_hashmap_entry *e; @@ -1687,13 +1711,13 @@ int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) { return 0; } -HashmapBase *_hashmap_copy(HashmapBase *h) { +HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) { HashmapBase *copy; int r; assert(h); - copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); + copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_PASS_ARGS); if (!copy) return NULL; @@ -1709,10 +1733,8 @@ HashmapBase *_hashmap_copy(HashmapBase *h) { assert_not_reached("Unknown hashmap type"); } - if (r < 0) { - _hashmap_free(copy, false, false); - return NULL; - } + if (r < 0) + return _hashmap_free(copy, false, false); return copy; } @@ -1765,10 +1787,10 @@ int set_consume(Set *s, void *value) { return r; } -int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) { +int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS) { int r; - r = hashmap_ensure_allocated(h, &string_hash_ops_free_free); + r = _hashmap_ensure_allocated(h, &string_hash_ops_free_free HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1799,14 +1821,14 @@ int hashmap_put_strdup(Hashmap **h, const char *k, const char *v) { return r; } -int set_put_strdup(Set **s, const char *p) { +int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS) { char *c; int r; assert(s); assert(p); - r = set_ensure_allocated(s, &string_hash_ops_free); + r = _set_ensure_allocated(s, &string_hash_ops_free HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -1820,14 +1842,14 @@ int set_put_strdup(Set **s, const char *p) { return set_consume(*s, c); } -int set_put_strdupv(Set **s, char **l) { +int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS) { int n = 0, r; char **i; assert(s); STRV_FOREACH(i, l) { - r = set_put_strdup(s, *i); + r = _set_put_strdup(s, *i HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; diff --git a/shared/systemd/src/basic/hashmap.h b/shared/systemd/src/basic/hashmap.h index 230d322213..6009441621 100644 --- a/shared/systemd/src/basic/hashmap.h +++ b/shared/systemd/src/basic/hashmap.h @@ -128,13 +128,9 @@ static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) IteratedCache *iterated_cache_free(IteratedCache *cache); int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries); -HashmapBase *_hashmap_copy(HashmapBase *h); -static inline Hashmap *hashmap_copy(Hashmap *h) { - return (Hashmap*) _hashmap_copy(HASHMAP_BASE(h)); -} -static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) { - return (OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h)); -} +HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS); +#define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) +#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); @@ -154,7 +150,8 @@ static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void * return hashmap_put(PLAIN_HASHMAP(h), key, value); } -int hashmap_put_strdup(Hashmap **h, const char *k, const char *v); +int _hashmap_put_strdup(Hashmap **h, const char *k, const char *v HASHMAP_DEBUG_PARAMS); +#define hashmap_put_strdup(h, k, v) _hashmap_put_strdup(h, k, v HASHMAP_DEBUG_SRC_ARGS) int hashmap_update(Hashmap *h, const void *key, void *value); static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { diff --git a/shared/systemd/src/basic/in-addr-util.c b/shared/systemd/src/basic/in-addr-util.c index 9feee66343..ea50e26197 100644 --- a/shared/systemd/src/basic/in-addr-util.c +++ b/shared/systemd/src/basic/in-addr-util.c @@ -14,6 +14,7 @@ #include "macro.h" #include "parse-util.h" #include "random-util.h" +#include "string-util.h" #include "strxcpyx.h" #include "util.h" @@ -107,11 +108,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_ return in4_addr_equal(&a->in, &b->in); if (family == AF_INET6) - return - a->in6.s6_addr32[0] == b->in6.s6_addr32[0] && - a->in6.s6_addr32[1] == b->in6.s6_addr32[1] && - a->in6.s6_addr32[2] == b->in6.s6_addr32[2] && - a->in6.s6_addr32[3] == b->in6.s6_addr32[3]; + return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6); return -EAFNOSUPPORT; } @@ -445,6 +442,61 @@ fallback: return in_addr_to_string(family, u, ret); } +int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret) { + _cleanup_free_ char *ip_str = NULL, *x = NULL; + int r; + + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(u); + assert(ret); + + /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly + * handle IPv6 link-local addresses. */ + + r = in_addr_to_string(family, u, &ip_str); + if (r < 0) + return r; + + if (family == AF_INET6) { + r = in_addr_is_link_local(family, u); + if (r < 0) + return r; + if (r == 0) + ifindex = 0; + } else + ifindex = 0; /* For IPv4 address, ifindex is always ignored. */ + + if (port == 0 && ifindex == 0 && isempty(server_name)) { + *ret = TAKE_PTR(ip_str); + return 0; + } + + const char *separator = isempty(server_name) ? "" : "#"; + server_name = strempty(server_name); + + if (port > 0) { + if (family == AF_INET6) { + if (ifindex > 0) + r = asprintf(&x, "[%s]:%"PRIu16"%%%i%s%s", ip_str, port, ifindex, separator, server_name); + else + r = asprintf(&x, "[%s]:%"PRIu16"%s%s", ip_str, port, separator, server_name); + } else + r = asprintf(&x, "%s:%"PRIu16"%s%s", ip_str, port, separator, server_name); + } else { + if (ifindex > 0) + r = asprintf(&x, "%s%%%i%s%s", ip_str, ifindex, separator, server_name); + else { + x = strjoin(ip_str, separator, server_name); + r = x ? 0 : -ENOMEM; + } + } + if (r < 0) + return -ENOMEM; + + *ret = TAKE_PTR(x); + return 0; +} + int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { union in_addr_union buffer; assert(s); diff --git a/shared/systemd/src/basic/in-addr-util.h b/shared/systemd/src/basic/in-addr-util.h index 90d79a5ef5..dc3f575bc9 100644 --- a/shared/systemd/src/basic/in-addr-util.h +++ b/shared/systemd/src/basic/in-addr-util.h @@ -41,6 +41,7 @@ int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret); +int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); int in_addr_from_string(int family, const char *s, union in_addr_union *ret); int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret); diff --git a/shared/systemd/src/basic/list.h b/shared/systemd/src/basic/list.h index f7f97000e0..b62c374985 100644 --- a/shared/systemd/src/basic/list.h +++ b/shared/systemd/src/basic/list.h @@ -169,3 +169,18 @@ #define LIST_IS_EMPTY(head) \ (!(head)) + +/* Join two lists tail to head: a->b, c->d to a->b->c->d and de-initialise second list */ +#define LIST_JOIN(name,a,b) \ + do { \ + assert(b); \ + if (!(a)) \ + (a) = (b); \ + else { \ + typeof(*(a)) *_head = (b), *_tail; \ + LIST_FIND_TAIL(name, (a), _tail); \ + _tail->name##_next = _head; \ + _head->name##_prev = _tail; \ + } \ + (b) = NULL; \ + } while (false) diff --git a/shared/systemd/src/basic/log.h b/shared/systemd/src/basic/log.h index 2c1b00fb88..15807d3029 100644 --- a/shared/systemd/src/basic/log.h +++ b/shared/systemd/src/basic/log.h @@ -84,8 +84,11 @@ void log_close(void); void log_forget_fds(void); void log_parse_environment_realm(LogRealm realm); +void log_parse_environment_cli_realm(LogRealm realm); #define log_parse_environment() \ log_parse_environment_realm(LOG_REALM) +#define log_parse_environment_cli() \ + log_parse_environment_cli_realm(LOG_REALM) int log_dispatch_internal( int level, @@ -341,3 +344,4 @@ int log_syntax_invalid_utf8_internal( #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) void log_setup_service(void); +void log_setup_cli(void); diff --git a/shared/systemd/src/basic/macro.h b/shared/systemd/src/basic/macro.h index 78e4262e41..ceea8176f5 100644 --- a/shared/systemd/src/basic/macro.h +++ b/shared/systemd/src/basic/macro.h @@ -286,6 +286,15 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ }) +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define CONST_MIN(_A, _B) \ + (__builtin_choose_expr( \ + __builtin_constant_p(_A) && \ + __builtin_constant_p(_B) && \ + __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ + ((_A) < (_B)) ? (_A) : (_B), \ + VOID_0)) + #define MIN3(x, y, z) \ ({ \ const typeof(x) _c = MIN(x, y); \ @@ -529,6 +538,12 @@ static inline int __coverity_check_and_return__(int condition) { (y) = (_t); \ } while (false) +/* Iterates through a specified list of pointers. Accepts NULL pointers, but uses (void*) -1 as internal marker for EOL. */ +#define FOREACH_POINTER(p, x, ...) \ + for (typeof(p) *_l = (typeof(p)[]) { ({ p = x; }), ##__VA_ARGS__, (void*) -1 }; \ + p != (typeof(p)) (void*) -1; \ + p = *(++_l)) + /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local diff --git a/shared/systemd/src/basic/memory-util.h b/shared/systemd/src/basic/memory-util.h index a6a2ccdbc2..4f596cffb7 100644 --- a/shared/systemd/src/basic/memory-util.h +++ b/shared/systemd/src/basic/memory-util.h @@ -13,6 +13,7 @@ size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) #define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1)) +#define PAGE_OFFSET(l) ((l) & (page_size() - 1)) /* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */ static inline void memcpy_safe(void *dst, const void *src, size_t n) { diff --git a/shared/systemd/src/basic/path-util.c b/shared/systemd/src/basic/path-util.c index 986dfe94a4..c4e022b3a1 100644 --- a/shared/systemd/src/basic/path-util.c +++ b/shared/systemd/src/basic/path-util.c @@ -640,10 +640,8 @@ int find_binary(const char *name, char **ret) { if (access(j, X_OK) >= 0) { /* Found it! */ - if (ret) { - *ret = path_simplify(j, false); - j = NULL; - } + if (ret) + *ret = path_simplify(TAKE_PTR(j), false); return 0; } diff --git a/shared/systemd/src/basic/process-util.c b/shared/systemd/src/basic/process-util.c index f6ecc7f86f..80f13048c1 100644 --- a/shared/systemd/src/basic/process-util.c +++ b/shared/systemd/src/basic/process-util.c @@ -1334,7 +1334,7 @@ int safe_fork_full( ppid = getppid(); if (ppid == 0) - /* Parent is in a differn't PID namespace. */; + /* Parent is in a different PID namespace. */; else if (ppid != original_pid) { log_debug("Parent died early, raising SIGTERM."); (void) raise(SIGTERM); diff --git a/shared/systemd/src/basic/process-util.h b/shared/systemd/src/basic/process-util.h index e0b52246ba..49bb74ac0f 100644 --- a/shared/systemd/src/basic/process-util.h +++ b/shared/systemd/src/basic/process-util.h @@ -20,14 +20,16 @@ #define procfs_file_alloca(pid, field) \ ({ \ pid_t _pid_ = (pid); \ - const char *_r_; \ + const char *_field_ = (field); \ + char *_r_; \ if (_pid_ == 0) { \ - _r_ = ("/proc/self/" field); \ + _r_ = newa(char, STRLEN("/proc/self/") + strlen(_field_) + 1); \ + strcpy(stpcpy(_r_, "/proc/self/"), _field_); \ } else { \ - _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ - sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ + _r_ = newa(char, STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + strlen(_field_) + 1); \ + sprintf(_r_, "/proc/" PID_FMT "/%s", _pid_, _field_); \ } \ - _r_; \ + (const char*) _r_; \ }) typedef enum ProcessCmdlineFlags { diff --git a/shared/systemd/src/basic/random-util.c b/shared/systemd/src/basic/random-util.c index 73cc7272db..6eeed9af34 100644 --- a/shared/systemd/src/basic/random-util.c +++ b/shared/systemd/src/basic/random-util.c @@ -7,11 +7,13 @@ #include <elf.h> #include <errno.h> #include <fcntl.h> +#include <linux/random.h> #include <pthread.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <string.h> +#include <sys/ioctl.h> #include <sys/time.h> #if HAVE_SYS_AUXV_H @@ -75,7 +77,7 @@ int rdrand(unsigned long *ret) { * hash functions for its hash tables, with a seed generated randomly. The hash tables * systemd employs watch the fill level closely and reseed if necessary. This allows use of * a low quality RNG initially, as long as it improves should a hash table be under attack: - * the attacker after all needs to to trigger many collisions to exploit it for the purpose + * the attacker after all needs to trigger many collisions to exploit it for the purpose * of DoS, but if doing so improves the seed the attack surface is reduced as the attack * takes place. * @@ -438,3 +440,36 @@ size_t random_pool_size(void) { /* Use the minimum as default, if we can't retrieve the correct value */ return RANDOM_POOL_SIZE_MIN; } + +int random_write_entropy(int fd, const void *seed, size_t size, bool credit) { + int r; + + assert(fd >= 0); + assert(seed && size > 0); + + if (credit) { + _cleanup_free_ struct rand_pool_info *info = NULL; + + /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any + * chance for confusion here. */ + if (size > INT_MAX / 8) + return -EOVERFLOW; + + info = malloc(offsetof(struct rand_pool_info, buf) + size); + if (!info) + return -ENOMEM; + + info->entropy_count = size * 8; + info->buf_size = size; + memcpy(info->buf, seed, size); + + if (ioctl(fd, RNDADDENTROPY, info) < 0) + return -errno; + } else { + r = loop_write(fd, seed, size, false); + if (r < 0) + return r; + } + + return 0; +} diff --git a/shared/systemd/src/basic/random-util.h b/shared/systemd/src/basic/random-util.h index d8e067d96e..7824ffaceb 100644 --- a/shared/systemd/src/basic/random-util.h +++ b/shared/systemd/src/basic/random-util.h @@ -38,3 +38,5 @@ int rdrand(unsigned long *ret); #define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U) size_t random_pool_size(void); + +int random_write_entropy(int fd, const void *seed, size_t size, bool credit); diff --git a/shared/systemd/src/basic/set.h b/shared/systemd/src/basic/set.h index 621e83bf27..e4fc1e3c4a 100644 --- a/shared/systemd/src/basic/set.h +++ b/shared/systemd/src/basic/set.h @@ -26,9 +26,7 @@ static inline Set *set_free_free(Set *s) { /* no set_free_free_free */ -static inline Set *set_copy(Set *s) { - return (Set*) _hashmap_copy(HASHMAP_BASE(s)); -} +#define set_copy(s) ((Set*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_ensure_allocated(h, ops) _set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) @@ -120,9 +118,19 @@ static inline char **set_get_strv(Set *s) { return _hashmap_get_strv(HASHMAP_BASE(s)); } +int _set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key HASHMAP_DEBUG_PARAMS); +#define set_ensure_put(s, hash_ops, key) _set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS) + +int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HASHMAP_DEBUG_PARAMS); +#define set_ensure_consume(s, hash_ops, key) _set_ensure_consume(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS) + int set_consume(Set *s, void *value); -int set_put_strdup(Set **s, const char *p); -int set_put_strdupv(Set **s, char **l); + +int _set_put_strdup(Set **s, const char *p HASHMAP_DEBUG_PARAMS); +#define set_put_strdup(s, p) _set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS) +int _set_put_strdupv(Set **s, char **l HASHMAP_DEBUG_PARAMS); +#define set_put_strdupv(s, l) _set_put_strdupv(s, l HASHMAP_DEBUG_SRC_ARGS) + int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags); #define SET_FOREACH(e, s, i) \ diff --git a/shared/systemd/src/basic/siphash24.h b/shared/systemd/src/basic/siphash24.h index 1937fea298..7f799ede3d 100644 --- a/shared/systemd/src/basic/siphash24.h +++ b/shared/systemd/src/basic/siphash24.h @@ -17,9 +17,21 @@ struct siphash { void siphash24_init(struct siphash *state, const uint8_t k[static 16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); -void siphash24_compress_boolean(bool in, struct siphash *state); #define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) +static inline void siphash24_compress_boolean(bool in, struct siphash *state) { + uint8_t i = in; + + siphash24_compress(&i, sizeof i, state); +} + +static inline void siphash24_compress_string(const char *in, struct siphash *state) { + if (!in) + return; + + siphash24_compress(in, strlen(in), state); +} + uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]); diff --git a/shared/systemd/src/basic/socket-util.c b/shared/systemd/src/basic/socket-util.c index 07f534f34d..fb12659857 100644 --- a/shared/systemd/src/basic/socket-util.c +++ b/shared/systemd/src/basic/socket-util.c @@ -105,7 +105,7 @@ int socket_address_verify(const SocketAddress *a, bool strict) { if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1) return -EINVAL; } else { - /* If there's no embedded NUL byte, then then the size needs to match the whole + /* If there's no embedded NUL byte, then the size needs to match the whole * structure or the structure with one extra NUL byte suffixed. (Yeah, Linux is awful, * and considers both equivalent: getsockname() even extends sockaddr_un beyond its * size if the path is non NUL terminated.)*/ @@ -1130,6 +1130,7 @@ int socket_bind_to_ifname(int fd, const char *ifname) { int socket_bind_to_ifindex(int fd, int ifindex) { char ifname[IF_NAMESIZE + 1]; + int r; assert(fd >= 0); @@ -1141,10 +1142,9 @@ int socket_bind_to_ifindex(int fd, int ifindex) { return 0; } - if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0) - return 0; - if (errno != ENOPROTOOPT) - return -errno; + r = setsockopt_int(fd, SOL_SOCKET, SO_BINDTOIFINDEX, ifindex); + if (r != -ENOPROTOOPT) + return r; /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */ if (!format_ifname(ifindex, ifname)) diff --git a/shared/systemd/src/basic/string-table.c b/shared/systemd/src/basic/string-table.c index 34931b03d8..0168cff886 100644 --- a/shared/systemd/src/basic/string-table.c +++ b/shared/systemd/src/basic/string-table.c @@ -4,12 +4,10 @@ #include "string-util.h" ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { - size_t i; - if (!key) return -1; - for (i = 0; i < len; ++i) + for (size_t i = 0; i < len; ++i) if (streq_ptr(table[i], key)) return (ssize_t) i; diff --git a/shared/systemd/src/basic/time-util.c b/shared/systemd/src/basic/time-util.c index 105584e2e7..15cc1b8851 100644 --- a/shared/systemd/src/basic/time-util.c +++ b/shared/systemd/src/basic/time-util.c @@ -82,43 +82,82 @@ triple_timestamp* triple_timestamp_get(triple_timestamp *ts) { return ts; } +static usec_t map_clock_usec_internal(usec_t from, usec_t from_base, usec_t to_base) { + + /* Maps the time 'from' between two clocks, based on a common reference point where the first clock + * is at 'from_base' and the second clock at 'to_base'. Basically calculates: + * + * from - from_base + to_base + * + * But takes care of overflows/underflows and avoids signed operations. */ + + if (from >= from_base) { /* In the future */ + usec_t delta = from - from_base; + + if (to_base >= USEC_INFINITY - delta) /* overflow? */ + return USEC_INFINITY; + + return to_base + delta; + + } else { /* In the past */ + usec_t delta = from_base - from; + + if (to_base <= delta) /* underflow? */ + return 0; + + return to_base - delta; + } +} + +usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) { + + /* Try to avoid any inaccuracy needlessly added in case we convert from effectively the same clock + * onto itself */ + if (map_clock_id(from_clock) == map_clock_id(to_clock)) + return from; + + /* Keep infinity as is */ + if (from == USEC_INFINITY) + return from; + + return map_clock_usec_internal(from, now(from_clock), now(to_clock)); +} + dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { - int64_t delta; assert(ts); - if (u == USEC_INFINITY || u <= 0) { + if (u == USEC_INFINITY || u == 0) { ts->realtime = ts->monotonic = u; return ts; } ts->realtime = u; - - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta); - + ts->monotonic = map_clock_usec(u, CLOCK_REALTIME, CLOCK_MONOTONIC); return ts; } triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) { - int64_t delta; + usec_t nowr; assert(ts); - if (u == USEC_INFINITY || u <= 0) { + if (u == USEC_INFINITY || u == 0) { ts->realtime = ts->monotonic = ts->boottime = u; return ts; } + nowr = now(CLOCK_REALTIME); + ts->realtime = u; - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - ts->monotonic = usec_sub_signed(now(CLOCK_MONOTONIC), delta); - ts->boottime = clock_boottime_supported() ? usec_sub_signed(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY; + ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC)); + ts->boottime = clock_boottime_supported() ? + map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME)) : + USEC_INFINITY; return ts; } dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { - int64_t delta; assert(ts); if (u == USEC_INFINITY) { @@ -127,25 +166,28 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { } ts->monotonic = u; - delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u; - ts->realtime = usec_sub_signed(now(CLOCK_REALTIME), delta); - + ts->realtime = map_clock_usec(u, CLOCK_MONOTONIC, CLOCK_REALTIME); return ts; } dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) { - int64_t delta; + clockid_t cid; + usec_t nowm; if (u == USEC_INFINITY) { ts->realtime = ts->monotonic = USEC_INFINITY; return ts; } - dual_timestamp_get(ts); - delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u; - ts->realtime = usec_sub_signed(ts->realtime, delta); - ts->monotonic = usec_sub_signed(ts->monotonic, delta); + cid = clock_boottime_or_monotonic(); + nowm = now(cid); + + if (cid == CLOCK_MONOTONIC) + ts->monotonic = u; + else + ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC)); + ts->realtime = map_clock_usec_internal(u, nowm, now(CLOCK_REALTIME)); return ts; } diff --git a/shared/systemd/src/basic/time-util.h b/shared/systemd/src/basic/time-util.h index 4c371257e3..9bbe986306 100644 --- a/shared/systemd/src/basic/time-util.h +++ b/shared/systemd/src/basic/time-util.h @@ -29,8 +29,8 @@ typedef struct triple_timestamp { usec_t boottime; } triple_timestamp; -#define USEC_INFINITY ((usec_t) -1) -#define NSEC_INFINITY ((nsec_t) -1) +#define USEC_INFINITY ((usec_t) UINT64_MAX) +#define NSEC_INFINITY ((nsec_t) UINT64_MAX) #define MSEC_PER_SEC 1000ULL #define USEC_PER_SEC ((usec_t) 1000000ULL) @@ -67,6 +67,8 @@ typedef struct triple_timestamp { usec_t now(clockid_t clock); nsec_t now_nsec(clockid_t clock); +usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock); + dual_timestamp* dual_timestamp_get(dual_timestamp *ts); dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); diff --git a/shared/systemd/src/basic/tmpfile-util.c b/shared/systemd/src/basic/tmpfile-util.c index 9cbca312fc..a49f7eee70 100644 --- a/shared/systemd/src/basic/tmpfile-util.c +++ b/shared/systemd/src/basic/tmpfile-util.c @@ -257,7 +257,7 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { assert((flags & O_EXCL) == 0); /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in - * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in + * which case "ret_path" will be returned as NULL. If not possible the temporary path name used is returned in * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */ fd = open_parent(target, O_TMPFILE|flags, 0640); |