systemd: update code from upstream (2024-04-19)

This is a direct dump from systemd git.

  $ git clean -fdx && \
    git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \
    git add .

======

SYSTEMD_DIR=../systemd
COMMIT=fa6ea8095855696cf14cb65214020cdcdee79d6b

(
  cd "$SYSTEMD_DIR"
  git checkout "$COMMIT"
  git reset --hard
  git clean -fdx
)

git ls-files -z :/src/libnm-systemd-core/src/ \
                :/src/libnm-systemd-shared/src/ \
                :/src/libnm-std-aux/unaligned-fundamental.h \
                :/src/libnm-std-aux/unaligned.h | \
  xargs -0 rm -f

nm_copy_sd_shared() {
    mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1"
}

nm_copy_sd_core() {
    mkdir -p "./src/libnm-systemd-core/$(dirname "$1")"
    cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1"
}

nm_copy_sd_stdaux() {
    mkdir -p "./src/libnm-std-aux/"
    cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}"
}

nm_copy_sd_core "src/libsystemd-network/dhcp-duid-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-client-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h"
nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c"
nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd_core "src/libsystemd-network/network-common.c"
nm_copy_sd_core "src/libsystemd-network/network-common.h"
nm_copy_sd_core "src/libsystemd-network/network-internal.h"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp-duid.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd_core "src/libsystemd/sd-device/device-internal.h"
nm_copy_sd_core "src/libsystemd/sd-device/device-private.c"
nm_copy_sd_core "src/libsystemd/sd-device/device-private.h"
nm_copy_sd_core "src/libsystemd/sd-device/device-util.h"
nm_copy_sd_core "src/libsystemd/sd-device/sd-device.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-source.h"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.c"
nm_copy_sd_core "src/libsystemd/sd-event/event-util.h"
nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c"
nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h"
nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd_core "src/systemd/_sd-common.h"
nm_copy_sd_core "src/systemd/sd-device.h"
nm_copy_sd_core "src/systemd/sd-dhcp-duid.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-client.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-option.h"
nm_copy_sd_core "src/systemd/sd-dhcp6-protocol.h"
nm_copy_sd_core "src/systemd/sd-event.h"
nm_copy_sd_core "src/systemd/sd-id128.h"
nm_copy_sd_core "src/systemd/sd-ndisc.h"
nm_copy_sd_shared "src/basic/alloc-util.c"
nm_copy_sd_shared "src/basic/alloc-util.h"
nm_copy_sd_shared "src/basic/arphrd-util.h"
nm_copy_sd_shared "src/basic/btrfs.c"
nm_copy_sd_shared "src/basic/btrfs.h"
nm_copy_sd_shared "src/basic/cgroup-util.h"
nm_copy_sd_shared "src/basic/chase.h"
nm_copy_sd_shared "src/basic/constants.h"
nm_copy_sd_shared "src/basic/devnum-util.c"
nm_copy_sd_shared "src/basic/devnum-util.h"
nm_copy_sd_shared "src/basic/dns-def.h"
nm_copy_sd_shared "src/basic/env-file.c"
nm_copy_sd_shared "src/basic/env-file.h"
nm_copy_sd_shared "src/basic/env-util.c"
nm_copy_sd_shared "src/basic/env-util.h"
nm_copy_sd_shared "src/basic/errno-util.h"
nm_copy_sd_shared "src/basic/escape.c"
nm_copy_sd_shared "src/basic/escape.h"
nm_copy_sd_shared "src/basic/ether-addr-util.c"
nm_copy_sd_shared "src/basic/ether-addr-util.h"
nm_copy_sd_shared "src/basic/extract-word.c"
nm_copy_sd_shared "src/basic/extract-word.h"
nm_copy_sd_shared "src/basic/fd-util.c"
nm_copy_sd_shared "src/basic/fd-util.h"
nm_copy_sd_shared "src/basic/fileio.c"
nm_copy_sd_shared "src/basic/fileio.h"
nm_copy_sd_shared "src/basic/format-util.c"
nm_copy_sd_shared "src/basic/format-util.h"
nm_copy_sd_shared "src/basic/fs-util.c"
nm_copy_sd_shared "src/basic/fs-util.h"
nm_copy_sd_shared "src/basic/glyph-util.c"
nm_copy_sd_shared "src/basic/glyph-util.h"
nm_copy_sd_shared "src/basic/hash-funcs.c"
nm_copy_sd_shared "src/basic/hash-funcs.h"
nm_copy_sd_shared "src/basic/hashmap.c"
nm_copy_sd_shared "src/basic/hashmap.h"
nm_copy_sd_shared "src/basic/hexdecoct.c"
nm_copy_sd_shared "src/basic/hexdecoct.h"
nm_copy_sd_shared "src/basic/hostname-util.c"
nm_copy_sd_shared "src/basic/hostname-util.h"
nm_copy_sd_shared "src/basic/in-addr-util.c"
nm_copy_sd_shared "src/basic/in-addr-util.h"
nm_copy_sd_shared "src/basic/inotify-util.c"
nm_copy_sd_shared "src/basic/inotify-util.h"
nm_copy_sd_shared "src/basic/io-util.c"
nm_copy_sd_shared "src/basic/io-util.h"
nm_copy_sd_shared "src/basic/iovec-util.h"
nm_copy_sd_shared "src/basic/label.c"
nm_copy_sd_shared "src/basic/label.h"
nm_copy_sd_shared "src/basic/list.h"
nm_copy_sd_shared "src/basic/locale-util.c"
nm_copy_sd_shared "src/basic/locale-util.h"
nm_copy_sd_shared "src/basic/lock-util.h"
nm_copy_sd_shared "src/basic/log.h"
nm_copy_sd_shared "src/basic/macro.h"
nm_copy_sd_shared "src/basic/memory-util.c"
nm_copy_sd_shared "src/basic/memory-util.h"
nm_copy_sd_shared "src/basic/mempool.c"
nm_copy_sd_shared "src/basic/mempool.h"
nm_copy_sd_shared "src/basic/missing_fcntl.h"
nm_copy_sd_shared "src/basic/missing_random.h"
nm_copy_sd_shared "src/basic/missing_socket.h"
nm_copy_sd_shared "src/basic/missing_stat.h"
nm_copy_sd_shared "src/basic/missing_syscall.h"
nm_copy_sd_shared "src/basic/missing_threads.h"
nm_copy_sd_shared "src/basic/missing_type.h"
nm_copy_sd_shared "src/basic/namespace-util.h"
nm_copy_sd_shared "src/basic/ordered-set.c"
nm_copy_sd_shared "src/basic/ordered-set.h"
nm_copy_sd_shared "src/basic/origin-id.h"
nm_copy_sd_shared "src/basic/parse-util.c"
nm_copy_sd_shared "src/basic/parse-util.h"
nm_copy_sd_shared "src/basic/path-util.c"
nm_copy_sd_shared "src/basic/path-util.h"
nm_copy_sd_shared "src/basic/pidref.h"
nm_copy_sd_shared "src/basic/prioq.c"
nm_copy_sd_shared "src/basic/prioq.h"
nm_copy_sd_shared "src/basic/process-util.c"
nm_copy_sd_shared "src/basic/process-util.h"
nm_copy_sd_shared "src/basic/random-util.c"
nm_copy_sd_shared "src/basic/random-util.h"
nm_copy_sd_shared "src/basic/ratelimit.c"
nm_copy_sd_shared "src/basic/ratelimit.h"
nm_copy_sd_shared "src/basic/set.h"
nm_copy_sd_shared "src/basic/signal-util.c"
nm_copy_sd_shared "src/basic/signal-util.h"
nm_copy_sd_shared "src/basic/siphash24.h"
nm_copy_sd_shared "src/basic/socket-util.c"
nm_copy_sd_shared "src/basic/socket-util.h"
nm_copy_sd_shared "src/basic/sort-util.h"
nm_copy_sd_shared "src/basic/sparse-endian.h"
nm_copy_sd_shared "src/basic/stat-util.c"
nm_copy_sd_shared "src/basic/stat-util.h"
nm_copy_sd_shared "src/basic/stdio-util.h"
nm_copy_sd_shared "src/basic/string-table.c"
nm_copy_sd_shared "src/basic/string-table.h"
nm_copy_sd_shared "src/basic/string-util.c"
nm_copy_sd_shared "src/basic/string-util.h"
nm_copy_sd_shared "src/basic/strv.c"
nm_copy_sd_shared "src/basic/strv.h"
nm_copy_sd_shared "src/basic/strxcpyx.c"
nm_copy_sd_shared "src/basic/strxcpyx.h"
nm_copy_sd_shared "src/basic/time-util.c"
nm_copy_sd_shared "src/basic/time-util.h"
nm_copy_sd_shared "src/basic/tmpfile-util.c"
nm_copy_sd_shared "src/basic/tmpfile-util.h"
nm_copy_sd_shared "src/basic/umask-util.h"
nm_copy_sd_shared "src/basic/user-util.h"
nm_copy_sd_shared "src/basic/utf8.c"
nm_copy_sd_shared "src/basic/utf8.h"
nm_copy_sd_shared "src/fundamental/logarithm.h"
nm_copy_sd_shared "src/fundamental/macro-fundamental.h"
nm_copy_sd_shared "src/fundamental/memory-util-fundamental.h"
nm_copy_sd_shared "src/fundamental/sha256.c"
nm_copy_sd_shared "src/fundamental/sha256.h"
nm_copy_sd_shared "src/fundamental/string-util-fundamental.c"
nm_copy_sd_shared "src/fundamental/string-util-fundamental.h"
nm_copy_sd_shared "src/shared/dns-domain.c"
nm_copy_sd_shared "src/shared/dns-domain.h"
nm_copy_sd_shared "src/shared/log-link.h"
nm_copy_sd_shared "src/shared/web-util.c"
nm_copy_sd_shared "src/shared/web-util.h"
nm_copy_sd_stdaux "src/basic/unaligned.h"
nm_copy_sd_stdaux "src/fundamental/unaligned-fundamental.h"
This commit is contained in:
Fernando Fernandez Mancera 2023-06-19 22:26:12 -04:00
parent bee8609c15
commit cd87004dfb
37 changed files with 512 additions and 633 deletions

View File

@ -214,7 +214,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
/* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
* things are not arranged as kobjects in kernel, and hence don't necessarily have
* kobject/attribute structure. */
r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS");
r = secure_getenv_bool("SYSTEMD_DEVICE_VERIFY_SYSFS");
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
if (r != 0) {
@ -728,7 +728,7 @@ int device_read_uevent_file(sd_device *device) {
_cleanup_free_ char *uevent = NULL;
const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL;
char *path;
size_t uevent_len;
size_t uevent_len = 0;
int r;
enum {
@ -1679,8 +1679,8 @@ int device_get_device_id(sd_device *device, const char **ret) {
int device_read_db_internal_filename(sd_device *device, const char *filename) {
_cleanup_free_ char *db = NULL;
const char *value;
size_t db_len;
const char *value = NULL;
size_t db_len = 0;
char key = '\0'; /* Unnecessary initialization to appease gcc-12.0.0-0.4.fc36 */
int r;

View File

@ -1574,7 +1574,7 @@ static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *us
static bool shall_use_pidfd(void) {
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
return secure_getenv_bool("SYSTEMD_PIDFD") != 0;
}
_public_ int sd_event_add_child(
@ -4915,13 +4915,13 @@ _public_ int sd_event_get_state(sd_event *e) {
_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
assert_return(code, -EINVAL);
assert_return(!event_origin_changed(e), -ECHILD);
if (!e->exit_requested)
return -ENODATA;
*code = e->exit_code;
if (code)
*code = e->exit_code;
return 0;
}

View File

@ -139,7 +139,7 @@ int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
fd = xopenat(dir_fd, path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return fd;
@ -185,7 +185,7 @@ int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
fd = xopenat(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
fd = xopenat_full(dir_fd, path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, /* xopen_flags = */ 0, 0444);
if (fd < 0)
return fd;

View File

@ -3,7 +3,6 @@
#define foosddhcpduidhfoo
/***
Copyright © 2013 Intel Corporation. All rights reserved.
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or

View File

@ -26,35 +26,14 @@
#include <sys/types.h>
#include "sd-event.h"
#include "sd-ndisc-protocol.h"
#include "sd-ndisc-router.h"
#include "_sd-common.h"
_SD_BEGIN_DECLARATIONS;
/* Neighbor Discovery Options, RFC 4861, Section 4.6 and
* https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */
enum {
SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1,
SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2,
SD_NDISC_OPTION_PREFIX_INFORMATION = 3,
SD_NDISC_OPTION_MTU = 5,
SD_NDISC_OPTION_ROUTE_INFORMATION = 24,
SD_NDISC_OPTION_RDNSS = 25,
SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
SD_NDISC_OPTION_DNSSL = 31,
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
SD_NDISC_OPTION_PREF64 = 38
};
/* Route preference, RFC 4191, Section 2.1 */
enum {
SD_NDISC_PREFERENCE_LOW = 3U,
SD_NDISC_PREFERENCE_MEDIUM = 0U,
SD_NDISC_PREFERENCE_HIGH = 1U
};
typedef struct sd_ndisc sd_ndisc;
typedef struct sd_ndisc_router sd_ndisc_router;
__extension__ typedef enum sd_ndisc_event_t {
SD_NDISC_EVENT_TIMEOUT,
@ -64,14 +43,16 @@ __extension__ typedef enum sd_ndisc_event_t {
_SD_ENUM_FORCE_S64(NDISC_EVENT)
} sd_ndisc_event_t;
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata);
typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, void *message, void *userdata);
int sd_ndisc_new(sd_ndisc **ret);
sd_ndisc *sd_ndisc_ref(sd_ndisc *nd);
sd_ndisc *sd_ndisc_unref(sd_ndisc *nd);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
int sd_ndisc_start(sd_ndisc *nd);
int sd_ndisc_stop(sd_ndisc *nd);
int sd_ndisc_is_running(sd_ndisc *nd);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
@ -81,69 +62,9 @@ int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata);
int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index);
int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name);
int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret);
int sd_ndisc_set_link_local_address(sd_ndisc *nd, const struct in6_addr *addr);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
/* Generic option access */
int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
int sd_ndisc_router_option_next(sd_ndisc_router *rt);
int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
/* Specific option access: SD_NDISC_OPTION_RDNSS */
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
/* Specific option access: SD_NDISC_OPTION_DNSSL */
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
/* Specific option access: SD_NDISC_OPTION_PREF64 */
int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
_SD_END_DECLARATIONS;
#endif

View File

@ -18,6 +18,7 @@
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
#include "utf8.h"
/* We follow bash for the character set. Different shells have different rules. */
@ -309,19 +310,17 @@ char **strv_env_delete(char **x, size_t n_lists, ...) {
return TAKE_PTR(t);
}
char **strv_env_unset(char **l, const char *p) {
char **f, **t;
char** strv_env_unset(char **l, const char *p) {
assert(p);
if (!l)
return NULL;
assert(p);
/* Drops every occurrence of the env var setting p in the
* string list. Edits in-place. */
char **f, **t;
for (f = t = l; *f; f++) {
if (env_match(*f, p)) {
free(*f);
continue;
@ -334,14 +333,13 @@ char **strv_env_unset(char **l, const char *p) {
return l;
}
char **strv_env_unset_many(char **l, ...) {
char **f, **t;
char** strv_env_unset_many_internal(char **l, ...) {
if (!l)
return NULL;
/* Like strv_env_unset() but applies many at once. Edits in-place. */
char **f, **t;
for (f = t = l; *f; f++) {
bool found = false;
const char *p;
@ -349,12 +347,11 @@ char **strv_env_unset_many(char **l, ...) {
va_start(ap, l);
while ((p = va_arg(ap, const char*))) {
while ((p = va_arg(ap, const char*)))
if (env_match(*f, p)) {
found = true;
break;
}
}
va_end(ap);
@ -966,7 +963,7 @@ int getenv_bool(const char *p) {
return parse_boolean(e);
}
int getenv_bool_secure(const char *p) {
int secure_getenv_bool(const char *p) {
const char *e;
e = secure_getenv(p);
@ -976,7 +973,7 @@ int getenv_bool_secure(const char *p) {
return parse_boolean(e);
}
int getenv_uint64_secure(const char *p, uint64_t *ret) {
int secure_getenv_uint64(const char *p, uint64_t *ret) {
const char *e;
assert(p);
@ -1030,6 +1027,17 @@ int setenv_systemd_exec_pid(bool update_only) {
return 1;
}
int setenv_systemd_log_level(void) {
_cleanup_free_ char *val = NULL;
int r;
r = log_level_to_string_alloc(log_get_max_level(), &val);
if (r < 0)
return r;
return RET_NERRNO(setenv("SYSTEMD_LOG_LEVEL", val, /* overwrite= */ true));
}
int getenv_path_list(const char *name, char ***ret_paths) {
_cleanup_strv_free_ char **l = NULL;
const char *e;

View File

@ -43,8 +43,9 @@ char** _strv_env_merge(char **first, ...);
#define strv_env_merge(first, ...) _strv_env_merge(first, __VA_ARGS__, POINTER_MAX)
char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */
char **strv_env_unset(char **l, const char *p); /* In place ... */
char **strv_env_unset_many(char **l, ...) _sentinel_;
char** strv_env_unset(char **l, const char *p); /* In place ... */
char** strv_env_unset_many_internal(char **l, ...) _sentinel_;
#define strv_env_unset_many(l, ...) strv_env_unset_many_internal(l, __VA_ARGS__, NULL)
int strv_env_replace_consume(char ***l, char *p); /* In place ... */
int strv_env_replace_strdup(char ***l, const char *assignment);
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment);
@ -61,9 +62,9 @@ static inline char* strv_env_get(char * const *x, const char *n) {
char *strv_env_pairs_get(char **l, const char *name) _pure_;
int getenv_bool(const char *p);
int getenv_bool_secure(const char *p);
int secure_getenv_bool(const char *p);
int getenv_uint64_secure(const char *p, uint64_t *ret);
int secure_getenv_uint64(const char *p, uint64_t *ret);
/* Like setenv, but calls unsetenv if value == NULL. */
int set_unset_env(const char *name, const char *value, bool overwrite);
@ -72,6 +73,7 @@ int set_unset_env(const char *name, const char *value, bool overwrite);
int putenv_dup(const char *assignment, bool override);
int setenv_systemd_exec_pid(bool update_only);
int setenv_systemd_log_level(void);
/* Parses and does sanity checks on an environment variable containing
* PATH-like colon-separated absolute paths */

View File

@ -244,52 +244,43 @@ int extract_first_word_and_warn(
* Let's make sure that ExtractFlags fits into an unsigned int. */
assert_cc(sizeof(enum ExtractFlags) <= sizeof(unsigned));
int extract_many_words(const char **p, const char *separators, unsigned flags, ...) {
int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) {
va_list ap;
char **l;
int n = 0, i, c, r;
unsigned n = 0;
int r;
/* Parses a number of words from a string, stripping any
* quotes if necessary. */
/* Parses a number of words from a string, stripping any quotes if necessary. */
assert(p);
/* Count how many words are expected */
va_start(ap, flags);
for (;;) {
if (!va_arg(ap, char **))
break;
while (va_arg(ap, char**))
n++;
}
va_end(ap);
if (n <= 0)
if (n == 0)
return 0;
/* Read all words into a temporary array */
l = newa0(char*, n);
for (c = 0; c < n; c++) {
char **l = newa0(char*, n);
unsigned c;
for (c = 0; c < n; c++) {
r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) {
free_many_charp(l, c);
return r;
}
if (r == 0)
break;
}
/* If we managed to parse all words, return them in the passed
* in parameters */
/* If we managed to parse all words, return them in the passed in parameters */
va_start(ap, flags);
for (i = 0; i < n; i++) {
char **v;
v = va_arg(ap, char **);
assert(v);
*v = l[i];
FOREACH_ARRAY(i, l, n) {
char **v = ASSERT_PTR(va_arg(ap, char**));
*v = *i;
}
va_end(ap);

View File

@ -19,4 +19,7 @@ typedef enum ExtractFlags {
int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags);
int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
int extract_many_words(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
int extract_many_words_internal(const char **p, const char *separators, unsigned flags, ...) _sentinel_;
#define extract_many_words(p, separators, flags, ...) \
extract_many_words_internal(p, separators, flags, ##__VA_ARGS__, NULL)

View File

@ -308,7 +308,7 @@ static int close_all_fds_special_case(const int except[], size_t n_except) {
case 0:
/* Close everything. Yay! */
if (close_range(3, -1, 0) >= 0)
if (close_range(3, INT_MAX, 0) >= 0)
return 1;
if (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)) {
@ -419,7 +419,7 @@ int close_all_fds(const int except[], size_t n_except) {
if (sorted[n_sorted-1] >= INT_MAX) /* Dont let the addition below overflow */
return 0;
if (close_range(sorted[n_sorted-1] + 1, -1, 0) >= 0)
if (close_range(sorted[n_sorted-1] + 1, INT_MAX, 0) >= 0)
return 0;
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno))
@ -464,6 +464,53 @@ int close_all_fds(const int except[], size_t n_except) {
return r;
}
int pack_fds(int fds[], size_t n_fds) {
if (n_fds <= 0)
return 0;
/* Shifts around the fds in the provided array such that they
* all end up packed next to each-other, in order, starting
* from SD_LISTEN_FDS_START. This must be called after close_all_fds();
* it is likely to freeze up otherwise. You should probably use safe_fork_full
* with FORK_CLOSE_ALL_FDS|FORK_PACK_FDS set, to ensure that this is done correctly.
* The fds array is modified in place with the new FD numbers. */
assert(fds);
for (int start = 0;;) {
int restart_from = -1;
for (int i = start; i < (int) n_fds; i++) {
int nfd;
/* Already at right index? */
if (fds[i] == i + 3)
continue;
nfd = fcntl(fds[i], F_DUPFD, i + 3);
if (nfd < 0)
return -errno;
safe_close(fds[i]);
fds[i] = nfd;
/* Hmm, the fd we wanted isn't free? Then
* let's remember that and try again from here */
if (nfd != i + 3 && restart_from < 0)
restart_from = i;
}
if (restart_from < 0)
break;
start = restart_from;
}
assert(fds[0] == 3);
return 0;
}
int same_fd(int a, int b) {
struct stat sta, stb;
pid_t pid;
@ -866,6 +913,38 @@ int fd_is_opath(int fd) {
return FLAGS_SET(r, O_PATH);
}
int fd_verify_safe_flags(int fd) {
int flags, unexpected_flags;
/* Check if an extrinsic fd is safe to work on (by a privileged service). This ensures that clients
* can't trick a privileged service into giving access to a file the client doesn't already have
* access to (especially via something like O_PATH).
*
* O_NOFOLLOW: For some reason the kernel will return this flag from fcntl; it doesn't go away
* immediately after open(). It should have no effect whatsoever to an already-opened FD,
* and since we refuse O_PATH it should be safe.
*
* RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
* See comment in missing_fcntl.h for more details about this.
*
* O_DIRECTORY: this is set for directories, which are totally fine
*/
assert(fd >= 0);
flags = fcntl(fd, F_GETFL);
if (flags < 0)
return -errno;
unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|O_DIRECTORY);
if (unexpected_flags != 0)
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
"Unexpected flags set for extrinsic fd: 0%o",
(unsigned) unexpected_flags);
return 0;
}
int read_nr_open(void) {
_cleanup_free_ char *nr_open = NULL;
int r;

View File

@ -8,6 +8,7 @@
#include <sys/socket.h>
#include "macro.h"
#include "missing_fcntl.h"
#include "stdio-util.h"
/* maximum length of fdname */
@ -77,6 +78,8 @@ int get_max_fd(void);
int close_all_fds(const int except[], size_t n_except);
int close_all_fds_without_malloc(const int except[], size_t n_except);
int pack_fds(int fds[], size_t n);
int same_fd(int a, int b);
void cmsg_close_all(struct msghdr *mh);
@ -109,7 +112,10 @@ static inline int make_null_stdio(void) {
int fd_reopen(int fd, int flags);
int fd_reopen_condition(int fd, int flags, int mask, int *ret_new_fd);
int fd_is_opath(int fd);
int fd_verify_safe_flags(int fd);
int read_nr_open(void);
int fd_get_diskseq(int fd, uint64_t *ret);

View File

@ -18,6 +18,14 @@ assert_cc(sizeof(uid_t) == sizeof(uint32_t));
assert_cc(sizeof(gid_t) == sizeof(uint32_t));
#define GID_FMT "%" PRIu32
/* Note: the lifetime of the compound literal is the immediately surrounding block,
* see C11 §6.5.2.5, and
* https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */
#define FORMAT_UID(uid) \
snprintf_ok((char[DECIMAL_STR_MAX(uid_t)]){}, DECIMAL_STR_MAX(uid_t), UID_FMT, uid)
#define FORMAT_GID(gid) \
snprintf_ok((char[DECIMAL_STR_MAX(gid_t)]){}, DECIMAL_STR_MAX(gid_t), GID_FMT, gid)
#if SIZEOF_TIME_T == 8
# define PRI_TIME PRIi64
#elif SIZEOF_TIME_T == 4

View File

@ -116,7 +116,11 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
int readlinkat_malloc(int fd, const char *p, char **ret) {
size_t l = PATH_MAX;
assert(p);
assert(fd >= 0 || fd == AT_FDCWD);
if (fd < 0 && isempty(p))
return -EISDIR; /* In this case, the fd points to the current working directory, and is
* definitely not a symlink. Let's return earlier. */
for (;;) {
_cleanup_free_ char *c = NULL;
@ -126,7 +130,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret) {
if (!c)
return -ENOMEM;
n = readlinkat(fd, p, c, l);
n = readlinkat(fd, strempty(p), c, l);
if (n < 0)
return -errno;
@ -1050,7 +1054,7 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode) {
path = fname;
}
fd = xopenat(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
fd = xopenat_full(dirfd, path, flags|O_CREAT|O_DIRECTORY|O_NOFOLLOW, /* xopen_flags = */ 0, mode);
if (IN_SET(fd, -ELOOP, -ENOTDIR))
return -EEXIST;
if (fd < 0)
@ -1106,7 +1110,7 @@ int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, b
}
}
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode) {
_cleanup_close_ int fd = -EBADF;
bool made = false;
int r;
@ -1187,7 +1191,7 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
return TAKE_FD(fd);
}
int xopenat_lock(
int xopenat_lock_full(
int dir_fd,
const char *path,
int open_flags,
@ -1210,7 +1214,7 @@ int xopenat_lock(
for (;;) {
struct stat st;
fd = xopenat(dir_fd, path, open_flags, xopen_flags, mode);
fd = xopenat_full(dir_fd, path, open_flags, xopen_flags, mode);
if (fd < 0)
return fd;

View File

@ -137,6 +137,12 @@ typedef enum XOpenFlags {
XO_SUBVOLUME = 1 << 1,
} XOpenFlags;
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
static inline int xopenat(int dir_fd, const char *path, int open_flags) {
return xopenat_full(dir_fd, path, open_flags, 0, 0);
}
int xopenat_lock(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
int xopenat_lock_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode, LockType locktype, int operation);
static inline int xopenat_lock(int dir_fd, const char *path, int open_flags, LockType locktype, int operation) {
return xopenat_lock_full(dir_fd, path, open_flags, 0, 0, locktype, operation);
}

View File

@ -41,6 +41,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_TREE_SPACE] = " ",
[SPECIAL_GLYPH_TREE_TOP] = ",-",
[SPECIAL_GLYPH_VERTICAL_DOTTED] = ":",
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = "-",
[SPECIAL_GLYPH_HORIZONTAL_FAT] = "=",
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
[SPECIAL_GLYPH_WHITE_CIRCLE] = "*",
@ -74,6 +76,10 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_SPARKLES] = "*",
[SPECIAL_GLYPH_LOW_BATTERY] = "!",
[SPECIAL_GLYPH_WARNING_SIGN] = "!",
[SPECIAL_GLYPH_RED_CIRCLE] = "o",
[SPECIAL_GLYPH_YELLOW_CIRCLE] = "o",
[SPECIAL_GLYPH_BLUE_CIRCLE] = "o",
[SPECIAL_GLYPH_GREEN_CIRCLE] = "o",
},
/* UTF-8 */
@ -87,6 +93,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
/* Single glyphs in both cases */
[SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"",
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = u8"",
[SPECIAL_GLYPH_HORIZONTAL_FAT] = u8"",
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"",
[SPECIAL_GLYPH_BLACK_CIRCLE] = u8"",
[SPECIAL_GLYPH_WHITE_CIRCLE] = u8"",
@ -136,6 +144,11 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
[SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
[SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽",
[SPECIAL_GLYPH_WORLD] = u8"🌍",
[SPECIAL_GLYPH_RED_CIRCLE] = u8"🔴",
[SPECIAL_GLYPH_YELLOW_CIRCLE] = u8"🟡",
[SPECIAL_GLYPH_BLUE_CIRCLE] = u8"🔵",
[SPECIAL_GLYPH_GREEN_CIRCLE] = u8"🟢",
},
};

View File

@ -13,6 +13,8 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_TREE_SPACE,
SPECIAL_GLYPH_TREE_TOP,
SPECIAL_GLYPH_VERTICAL_DOTTED,
SPECIAL_GLYPH_HORIZONTAL_DOTTED,
SPECIAL_GLYPH_HORIZONTAL_FAT,
SPECIAL_GLYPH_TRIANGULAR_BULLET,
SPECIAL_GLYPH_BLACK_CIRCLE,
SPECIAL_GLYPH_WHITE_CIRCLE,
@ -49,6 +51,10 @@ typedef enum SpecialGlyph {
SPECIAL_GLYPH_WARNING_SIGN,
SPECIAL_GLYPH_COMPUTER_DISK,
SPECIAL_GLYPH_WORLD,
SPECIAL_GLYPH_RED_CIRCLE,
SPECIAL_GLYPH_YELLOW_CIRCLE,
SPECIAL_GLYPH_BLUE_CIRCLE,
SPECIAL_GLYPH_GREEN_CIRCLE,
_SPECIAL_GLYPH_MAX,
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;

View File

@ -2120,24 +2120,27 @@ static int hashmap_entry_compare(
return compare((*a)->key, (*b)->key);
}
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
_cleanup_free_ struct hashmap_base_entry **entries = NULL;
static int _hashmap_dump_entries_sorted(
HashmapBase *h,
void ***ret,
size_t *ret_n) {
_cleanup_free_ void **entries = NULL;
Iterator iter;
unsigned idx;
size_t n = 0;
assert(ret);
assert(ret_n);
if (_hashmap_size(h) == 0) {
*ret = NULL;
if (ret_n)
*ret_n = 0;
*ret_n = 0;
return 0;
}
/* We append one more element than needed so that the resulting array can be used as a strv. We
* don't count this entry in the returned size. */
entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1);
entries = new(void*, _hashmap_size(h) + 1);
if (!entries)
return -ENOMEM;
@ -2147,13 +2150,47 @@ int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
assert(n == _hashmap_size(h));
entries[n] = NULL;
typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare);
typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
hashmap_entry_compare, h->hash_ops->compare);
*ret = TAKE_PTR(entries);
*ret_n = n;
return 0;
}
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
_cleanup_free_ void **entries = NULL;
size_t n;
int r;
r = _hashmap_dump_entries_sorted(h, &entries, &n);
if (r < 0)
return r;
/* Reuse the array. */
FOREACH_ARRAY(e, entries, n)
*e = entry_value(h, *e);
*e = (void*) (*(struct hashmap_base_entry**) e)->key;
*ret = (void**) TAKE_PTR(entries);
*ret = TAKE_PTR(entries);
if (ret_n)
*ret_n = n;
return 0;
}
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
_cleanup_free_ void **entries = NULL;
size_t n;
int r;
r = _hashmap_dump_entries_sorted(h, &entries, &n);
if (r < 0)
return r;
/* Reuse the array. */
FOREACH_ARRAY(e, entries, n)
*e = entry_value(h, *(struct hashmap_base_entry**) e);
*ret = TAKE_PTR(entries);
if (ret_n)
*ret_n = n;
return 0;

View File

@ -39,8 +39,8 @@ typedef struct IteratedCache IteratedCache; /* Caches the iterated order of on
* by hashmap users, so the definition has to be here. Do not use its fields
* directly. */
typedef struct {
unsigned idx; /* index of an entry to be iterated next */
const void *next_key; /* expected value of that entry's key pointer */
unsigned idx; /* index of an entry to be iterated next */
#if ENABLE_DEBUG_HASHMAP
unsigned put_count; /* hashmap's put_count recorded at start of iteration */
unsigned rem_count; /* hashmap's rem_count in previous iteration */
@ -409,6 +409,14 @@ static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
}
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
static inline int hashmap_dump_keys_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
}
static inline int ordered_hashmap_dump_keys_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
return _hashmap_dump_keys_sorted(HASHMAP_BASE(h), ret, ret_n);
}
/*
* Hashmaps are iterated in unpredictable order.
* OrderedHashmaps are an exception to this. They are iterated in the order

View File

@ -91,14 +91,26 @@ bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a) {
be32toh(a->s6_addr32[3]) == UINT32_C(0x00000001);
}
bool in4_addr_is_multicast(const struct in_addr *a) {
assert(a);
return IN_MULTICAST(be32toh(a->s_addr));
}
bool in6_addr_is_multicast(const struct in6_addr *a) {
assert(a);
return IN6_IS_ADDR_MULTICAST(a);
}
int in_addr_is_multicast(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
return IN_MULTICAST(be32toh(u->in.s_addr));
return in4_addr_is_multicast(&u->in);
if (family == AF_INET6)
return IN6_IS_ADDR_MULTICAST(&u->in6);
return in6_addr_is_multicast(&u->in6);
return -EAFNOSUPPORT;
}

View File

@ -40,6 +40,8 @@ static inline bool in_addr_data_is_set(const struct in_addr_data *a) {
return in_addr_data_is_null(a);
}
bool in4_addr_is_multicast(const struct in_addr *a);
bool in6_addr_is_multicast(const struct in6_addr *a);
int in_addr_is_multicast(int family, const union in_addr_union *u);
bool in4_addr_is_link_local(const struct in_addr *a);

View File

@ -260,7 +260,10 @@ bool locale_is_valid(const char *name) {
if (!filename_is_valid(name))
return false;
if (!string_is_safe(name))
/* Locales look like: ll_CC.ENC@variant, where ll and CC are alphabetic, ENC is alphanumeric with
* dashes, and variant seems to be alphabetic.
* See: https://www.gnu.org/software/gettext/manual/html_node/Locale-Names.html */
if (!in_charset(name, ALPHANUMERICAL "_.-@"))
return false;
return true;
@ -292,7 +295,7 @@ bool is_locale_utf8(void) {
if (cached_answer >= 0)
goto out;
r = getenv_bool_secure("SYSTEMD_UTF8");
r = secure_getenv_bool("SYSTEMD_UTF8");
if (r >= 0) {
cached_answer = r;
goto out;

View File

@ -383,7 +383,7 @@ typedef struct LogRateLimit {
RateLimit ratelimit;
} LogRateLimit;
#define log_ratelimit_internal(_level, _error, _ratelimit, _format, _file, _line, _func, ...) \
#define log_ratelimit_internal(_level, _error, _ratelimit, _file, _line, _func, _format, ...) \
({ \
int _log_ratelimit_error = (_error); \
int _log_ratelimit_level = (_level); \
@ -407,7 +407,7 @@ typedef struct LogRateLimit {
({ \
int _level = (level), _e = (error); \
_e = (log_get_max_level() >= LOG_PRI(_level)) \
? log_ratelimit_internal(_level, _e, _ratelimit, format, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__) \
? log_ratelimit_internal(_level, _e, _ratelimit, PROJECT_FILE, __LINE__, __func__, format, ##__VA_ARGS__) \
: -ERRNO_VALUE(_e); \
_e < 0 ? _e : -ESTRPIPE; \
})

View File

@ -69,9 +69,26 @@
/* So O_LARGEFILE is generally implied by glibc, and defined to zero hence, because we only build in LFS
* mode. However, when invoking fcntl(F_GETFL) the flag is ORed into the result anyway glibc does not mask
* it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves. */
* it away. Which sucks. Let's define the actual value here, so that we can mask it ourselves.
*
* The precise definition is arch specific, so we use the values defined in the kernel (note that some
* are hexa and others are octal; duplicated as-is from the kernel definitions):
* - alpha, arm, arm64, m68k, mips, parisc, powerpc, sparc: each has a specific value;
* - others: they use the "generic" value (defined in include/uapi/asm-generic/fcntl.h) */
#if O_LARGEFILE != 0
#define RAW_O_LARGEFILE O_LARGEFILE
#else
#define RAW_O_LARGEFILE 0100000
#if defined(__alpha__) || defined(__arm__) || defined(__aarch64__) || defined(__m68k__)
#define RAW_O_LARGEFILE 0400000
#elif defined(__mips__)
#define RAW_O_LARGEFILE 0x2000
#elif defined(__parisc__) || defined(__hppa__)
#define RAW_O_LARGEFILE 000004000
#elif defined(__powerpc__)
#define RAW_O_LARGEFILE 0200000
#elif defined(__sparc__)
#define RAW_O_LARGEFILE 0x40000
#else
#define RAW_O_LARGEFILE 00100000
#endif
#endif

View File

@ -412,23 +412,14 @@ static inline int missing_execveat(int dirfd, const char *pathname,
/* ======================================================================= */
#if !HAVE_CLOSE_RANGE
static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) {
static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) {
# ifdef __NR_close_range
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
* userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
* wrap this syscall, but let's assume it's going to be similar to what they do for close(),
* i.e. make the same unsigned signed type change from the raw kernel syscall compared to the
* userspace wrapper. There's only one caveat for this: unlike for close() there's the special
* UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
* any other negative values. */
if ((first_fd < 0) || (end_fd < 0 && end_fd != -1)) {
errno = -EBADF;
return -1;
}
* userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we
* do so here too, even if we end up passing signed fds to it most of the time. */
return syscall(__NR_close_range,
(unsigned) first_fd,
end_fd == -1 ? UINT_MAX : (unsigned) end_fd, /* Of course, the compiler should figure out that this is the identity mapping IRL */
first_fd,
end_fd,
flags);
# else
errno = ENOSYS;

View File

@ -53,3 +53,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
int userns_acquire(const char *uid_map, const char *gid_map);
int netns_acquire(void);
int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type);
int parse_userns_uid_range(const char *s, uid_t *ret_uid_shift, uid_t *ret_uid_range);

View File

@ -510,7 +510,7 @@ static int get_process_link_contents(pid_t pid, const char *proc_file, char **re
p = procfs_file_alloca(pid, proc_file);
r = readlink_malloc(p, ret);
return r == -ENOENT ? -ESRCH : r;
return (r == -ENOENT && proc_mounted() > 0) ? -ESRCH : r;
}
int get_process_exe(pid_t pid, char **ret) {
@ -1303,7 +1303,7 @@ int opinionated_personality(unsigned long *ret) {
if (current < 0)
return current;
if (((unsigned long) current & 0xffff) == PER_LINUX32)
if (((unsigned long) current & OPINIONATED_PERSONALITY_MASK) == PER_LINUX32)
*ret = PER_LINUX32;
else
*ret = PER_LINUX;
@ -1468,7 +1468,7 @@ static int fork_flags_to_signal(ForkFlags flags) {
int safe_fork_full(
const char *name,
const int stdio_fds[3],
const int except_fds[],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
pid_t *ret_pid) {
@ -1697,6 +1697,19 @@ int safe_fork_full(
}
}
if (flags & FORK_PACK_FDS) {
/* FORK_CLOSE_ALL_FDS ensures that except_fds are the only FDs >= 3 that are
* open, this is including the log. This is required by pack_fds, which will
* get stuck in an infinite loop of any FDs other than except_fds are open. */
assert(FLAGS_SET(flags, FORK_CLOSE_ALL_FDS));
r = pack_fds(except_fds, n_except_fds);
if (r < 0) {
log_full_errno(prio, r, "Failed to pack file descriptors: %m");
_exit(EXIT_FAILURE);
}
}
if (flags & FORK_CLOEXEC_OFF) {
r = fd_cloexec_many(except_fds, n_except_fds, false);
if (r < 0) {
@ -1736,7 +1749,7 @@ int safe_fork_full(
int pidref_safe_fork_full(
const char *name,
const int stdio_fds[3],
const int except_fds[],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
PidRef *ret_pid) {
@ -1760,7 +1773,7 @@ int pidref_safe_fork_full(
int namespace_fork(
const char *outer_name,
const char *inner_name,
const int except_fds[],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
int pidns_fd,

View File

@ -101,12 +101,17 @@ bool is_main_thread(void);
bool oom_score_adjust_is_valid(int oa);
#ifndef PERSONALITY_INVALID
/* personality(7) documents that 0xffffffffUL is used for querying the
/* personality(2) documents that 0xFFFFFFFFUL is used for querying the
* current personality, hence let's use that here as error
* indicator. */
#define PERSONALITY_INVALID 0xffffffffLU
#define PERSONALITY_INVALID 0xFFFFFFFFUL
#endif
/* The personality() syscall returns a 32-bit value where the top three bytes are reserved for flags that
* emulate historical or architectural quirks, and only the least significant byte reflects the actual
* personality we're interested in. */
#define OPINIONATED_PERSONALITY_MASK 0xFFUL
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
@ -180,12 +185,13 @@ typedef enum ForkFlags {
FORK_KEEP_NOTIFY_SOCKET = 1 << 17, /* Unless this specified, $NOTIFY_SOCKET will be unset. */
FORK_DETACH = 1 << 18, /* Double fork if needed to ensure PID1/subreaper is parent */
FORK_NEW_NETNS = 1 << 19, /* Run child in its own network namespace 💣 DO NOT USE IN THREADED PROGRAMS! 💣 */
FORK_PACK_FDS = 1 << 20, /* Rearrange the passed FDs to be FD 3,4,5,etc. Updates the array in place (combine with FORK_CLOSE_ALL_FDS!) */
} ForkFlags;
int safe_fork_full(
const char *name,
const int stdio_fds[3],
const int except_fds[],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
pid_t *ret_pid);
@ -197,7 +203,7 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
int pidref_safe_fork_full(
const char *name,
const int stdio_fds[3],
const int except_fds[],
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
PidRef *ret_pid);
@ -206,7 +212,18 @@ static inline int pidref_safe_fork(const char *name, ForkFlags flags, PidRef *re
return pidref_safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
}
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
int namespace_fork(
const char *outer_name,
const char *inner_name,
int except_fds[],
size_t n_except_fds,
ForkFlags flags,
int pidns_fd,
int mntns_fd,
int netns_fd,
int userns_fd,
int root_fd,
pid_t *ret_pid);
int set_oom_score_adjust(int value);
int get_oom_score_adjust(int *ret);

View File

@ -18,7 +18,7 @@ int reset_all_signal_handlers(void) {
.sa_handler = SIG_DFL,
.sa_flags = SA_RESTART,
};
int r = 0;
int ret = 0, r;
for (int sig = 1; sig < _NSIG; sig++) {
@ -26,14 +26,14 @@ int reset_all_signal_handlers(void) {
if (IN_SET(sig, SIGKILL, SIGSTOP))
continue;
/* On Linux the first two RT signals are reserved by
* glibc, and sigaction() will return EINVAL for them. */
if (sigaction(sig, &sa, NULL) < 0)
if (errno != EINVAL && r >= 0)
r = -errno;
/* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
* EINVAL for them. */
r = RET_NERRNO(sigaction(sig, &sa, NULL));
if (r != -EINVAL)
RET_GATHER(ret, r);
}
return r;
return ret;
}
int reset_signal_mask(void) {
@ -57,10 +57,7 @@ int sigaction_many_internal(const struct sigaction *sa, ...) {
if (sig == 0)
continue;
if (sigaction(sig, sa, NULL) < 0) {
if (r >= 0)
r = -errno;
}
RET_GATHER(r, RET_NERRNO(sigaction(sig, sa, NULL)));
}
va_end(ap);
@ -87,7 +84,7 @@ static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
return r;
}
int sigset_add_many(sigset_t *ss, ...) {
int sigset_add_many_internal(sigset_t *ss, ...) {
va_list ap;
int r;
@ -98,7 +95,7 @@ int sigset_add_many(sigset_t *ss, ...) {
return r;
}
int sigprocmask_many(int how, sigset_t *old, ...) {
int sigprocmask_many_internal(int how, sigset_t *old, ...) {
va_list ap;
sigset_t ss;
int r;
@ -113,10 +110,7 @@ int sigprocmask_many(int how, sigset_t *old, ...) {
if (r < 0)
return r;
if (sigprocmask(how, &ss, old) < 0)
return -errno;
return 0;
return RET_NERRNO(sigprocmask(how, &ss, old));
}
static const char *const static_signal_table[] = {

View File

@ -31,8 +31,11 @@ int sigaction_many_internal(const struct sigaction *sa, ...);
#define sigaction_many(sa, ...) \
sigaction_many_internal(sa, __VA_ARGS__, -1)
int sigset_add_many(sigset_t *ss, ...);
int sigprocmask_many(int how, sigset_t *old, ...);
int sigset_add_many_internal(sigset_t *ss, ...);
#define sigset_add_many(...) sigset_add_many_internal(__VA_ARGS__, -1)
int sigprocmask_many_internal(int how, sigset_t *old, ...);
#define sigprocmask_many(...) sigprocmask_many_internal(__VA_ARGS__, -1)
const char *signal_to_string(int i) _const_;
int signal_from_string(const char *s) _pure_;
@ -46,7 +49,7 @@ static inline void block_signals_reset(sigset_t *ss) {
#define BLOCK_SIGNALS(...) \
_cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
sigset_t _t; \
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \
assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__) >= 0); \
_t; \
})

View File

@ -25,43 +25,130 @@
#include "stat-util.h"
#include "string-util.h"
int is_symlink(const char *path) {
struct stat info;
static int verify_stat_at(
int fd,
const char *path,
bool follow,
int (*verify_func)(const struct stat *st),
bool verify) {
assert(path);
if (lstat(path, &info) < 0)
return -errno;
return !!S_ISLNK(info.st_mode);
}
int is_dir_full(int atfd, const char* path, bool follow) {
struct stat st;
int r;
assert(atfd >= 0 || atfd == AT_FDCWD);
assert(atfd >= 0 || path);
assert(fd >= 0 || fd == AT_FDCWD);
assert(!isempty(path) || !follow);
assert(verify_func);
if (path)
r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW);
else
r = fstat(atfd, &st);
if (r < 0)
if (fstatat(fd, strempty(path), &st,
(isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
return -errno;
return !!S_ISDIR(st.st_mode);
r = verify_func(&st);
return verify ? r : r >= 0;
}
int stat_verify_regular(const struct stat *st) {
assert(st);
/* Checks whether the specified stat() structure refers to a regular file. If not returns an
* appropriate error code. */
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISREG(st->st_mode))
return -EBADFD;
return 0;
}
int verify_regular_at(int fd, const char *path, bool follow) {
return verify_stat_at(fd, path, follow, stat_verify_regular, true);
}
int fd_verify_regular(int fd) {
assert(fd >= 0);
return verify_regular_at(fd, NULL, false);
}
int stat_verify_directory(const struct stat *st) {
assert(st);
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISDIR(st->st_mode))
return -ENOTDIR;
return 0;
}
int fd_verify_directory(int fd) {
assert(fd >= 0);
return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
}
int is_dir_at(int fd, const char *path, bool follow) {
return verify_stat_at(fd, path, follow, stat_verify_directory, false);
}
int is_dir(const char *path, bool follow) {
assert(!isempty(path));
return is_dir_at(AT_FDCWD, path, follow);
}
int stat_verify_symlink(const struct stat *st) {
assert(st);
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (!S_ISLNK(st->st_mode))
return -ENOLINK;
return 0;
}
int is_symlink(const char *path) {
assert(!isempty(path));
return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
}
int stat_verify_linked(const struct stat *st) {
assert(st);
if (st->st_nlink <= 0)
return -EIDRM; /* recognizable error. */
return 0;
}
int fd_verify_linked(int fd) {
assert(fd >= 0);
return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
}
int stat_verify_device_node(const struct stat *st) {
assert(st);
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
return -ENOTTY;
return 0;
}
int is_device_node(const char *path) {
struct stat info;
assert(path);
if (lstat(path, &info) < 0)
return -errno;
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
assert(!isempty(path));
return verify_stat_at(AT_FDCWD, path, false, stat_verify_device_node, false);
}
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
@ -260,70 +347,6 @@ int path_is_network_fs(const char *path) {
return is_network_fs(&s);
}
int stat_verify_regular(const struct stat *st) {
assert(st);
/* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
* code. */
if (S_ISDIR(st->st_mode))
return -EISDIR;
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISREG(st->st_mode))
return -EBADFD;
return 0;
}
int fd_verify_regular(int fd) {
struct stat st;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
return stat_verify_regular(&st);
}
int verify_regular_at(int dir_fd, const char *path, bool follow) {
struct stat st;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
if (fstatat(dir_fd, path, &st, (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
return -errno;
return stat_verify_regular(&st);
}
int stat_verify_directory(const struct stat *st) {
assert(st);
if (S_ISLNK(st->st_mode))
return -ELOOP;
if (!S_ISDIR(st->st_mode))
return -ENOTDIR;
return 0;
}
int fd_verify_directory(int fd) {
struct stat st;
assert(fd >= 0);
if (fstat(fd, &st) < 0)
return -errno;
return stat_verify_directory(&st);
}
int proc_mounted(void) {
int r;
@ -468,7 +491,7 @@ int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(ret);
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY, /* xopen_flags = */ 0, /* mode = */ 0);
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return fd;

View File

@ -14,14 +14,22 @@
#include "siphash24.h"
#include "time-util.h"
int stat_verify_regular(const struct stat *st);
int verify_regular_at(int fd, const char *path, bool follow);
int fd_verify_regular(int fd);
int stat_verify_directory(const struct stat *st);
int fd_verify_directory(int fd);
int is_dir_at(int fd, const char *path, bool follow);
int is_dir(const char *path, bool follow);
int stat_verify_symlink(const struct stat *st);
int is_symlink(const char *path);
int is_dir_full(int atfd, const char *fname, bool follow);
static inline int is_dir(const char *path, bool follow) {
return is_dir_full(AT_FDCWD, path, follow);
}
static inline int is_dir_fd(int fd) {
return is_dir_full(fd, NULL, false);
}
int stat_verify_linked(const struct stat *st);
int fd_verify_linked(int fd);
int stat_verify_device_node(const struct stat *st);
int is_device_node(const char *path);
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup);
@ -72,13 +80,6 @@ int path_is_network_fs(const char *path);
*/
#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b)
int stat_verify_regular(const struct stat *st);
int fd_verify_regular(int fd);
int verify_regular_at(int dir_fd, const char *path, bool follow);
int stat_verify_directory(const struct stat *st);
int fd_verify_directory(int fd);
int proc_mounted(void);
bool stat_inode_same(const struct stat *a, const struct stat *b);

View File

@ -620,6 +620,9 @@ char *cellescape(char *buf, size_t len, const char *s) {
char* strshorten(char *s, size_t l) {
assert(s);
if (l >= SIZE_MAX-1) /* Would not change anything */
return s;
if (strnlen(s, l+1) > l)
s[l] = 0;

View File

@ -358,7 +358,7 @@ int strv_split_colon_pairs(char ***t, const char *s) {
const char *p = tuple;
r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
&first, &second, NULL);
&first, &second);
if (r < 0)
return r;
if (r == 0)

View File

@ -1429,7 +1429,7 @@ static int get_timezones_from_zone1970_tab(char ***ret) {
/* Line format is:
* 'country codes' 'coordinates' 'timezone' 'comments' */
r = extract_many_words(&p, NULL, 0, &cc, &co, &tz, NULL);
r = extract_many_words(&p, NULL, 0, &cc, &co, &tz);
if (r < 0)
continue;
@ -1474,7 +1474,7 @@ static int get_timezones_from_tzdata_zi(char ***ret) {
* Link line format is:
* 'Link' 'target' 'alias'
* See 'man zic' for more detail. */
r = extract_many_words(&p, NULL, 0, &type, &f1, &f2, NULL);
r = extract_many_words(&p, NULL, 0, &type, &f1, &f2);
if (r < 0)
continue;
@ -1573,7 +1573,7 @@ int verify_timezone(const char *name, int log_level) {
r = fd_verify_regular(fd);
if (r < 0)
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
return log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t);
r = loop_read_exact(fd, buf, 4, false);
if (r < 0)

View File

@ -249,6 +249,30 @@
CONST_ISPOWEROF2(_x); \
}))
#define ADD_SAFE(ret, a, b) (!__builtin_add_overflow(a, b, ret))
#define INC_SAFE(a, b) __INC_SAFE(UNIQ, a, b)
#define __INC_SAFE(q, a, b) \
({ \
const typeof(a) UNIQ_T(A, q) = (a); \
ADD_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
})
#define SUB_SAFE(ret, a, b) (!__builtin_sub_overflow(a, b, ret))
#define DEC_SAFE(a, b) __DEC_SAFE(UNIQ, a, b)
#define __DEC_SAFE(q, a, b) \
({ \
const typeof(a) UNIQ_T(A, q) = (a); \
SUB_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
})
#define MUL_SAFE(ret, a, b) (!__builtin_mul_overflow(a, b, ret))
#define MUL_ASSIGN_SAFE(a, b) __MUL_ASSIGN_SAFE(UNIQ, a, b)
#define __MUL_ASSIGN_SAFE(q, a, b) \
({ \
const typeof(a) UNIQ_T(A, q) = (a); \
MUL_SAFE(UNIQ_T(A, q), *UNIQ_T(A, q), b); \
})
#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b))
#define __LESS_BY(aq, a, bq, b) \
({ \
@ -298,7 +322,7 @@
const typeof(y) UNIQ_T(A, q) = (y); \
const typeof(x) UNIQ_T(B, q) = DIV_ROUND_UP((x), UNIQ_T(A, q)); \
typeof(x) UNIQ_T(C, q); \
__builtin_mul_overflow(UNIQ_T(B, q), UNIQ_T(A, q), &UNIQ_T(C, q)) ? (typeof(x)) -1 : UNIQ_T(C, q); \
MUL_SAFE(&UNIQ_T(C, q), UNIQ_T(B, q), UNIQ_T(A, q)) ? UNIQ_T(C, q) : (typeof(x)) -1; \
})
#define ROUND_UP(x, y) __ROUND_UP(UNIQ, (x), (y))

View File

@ -1,278 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */
/* Functions to compute SHA256 message digest of files or memory blocks.
according to the definition of SHA256 in FIPS 180-2.
Copyright (C) 2007-2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <stdbool.h>
#if SD_BOOT
# include "efi-string.h"
#else
# include <string.h>
#endif
#include "macro-fundamental.h"
#include "sha256.h"
#include "unaligned-fundamental.h"
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define SWAP(n) \
__builtin_bswap32(n)
# define SWAP64(n) \
__builtin_bswap64(n)
#else
# define SWAP(n) (n)
# define SWAP64(n) (n)
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (FIPS 180-2:5.1.1) */
static const uint8_t fillbuf[64] = {
0x80, 0 /* , 0, 0, ... */
};
/* Constants for SHA256 from FIPS 180-2:4.2.2. */
static const uint32_t K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
static void sha256_process_block(const void *, size_t, struct sha256_ctx *);
/* Initialize structure containing state of computation.
(FIPS 180-2:5.3.2) */
void sha256_init_ctx(struct sha256_ctx *ctx) {
assert(ctx);
ctx->H[0] = 0x6a09e667;
ctx->H[1] = 0xbb67ae85;
ctx->H[2] = 0x3c6ef372;
ctx->H[3] = 0xa54ff53a;
ctx->H[4] = 0x510e527f;
ctx->H[5] = 0x9b05688c;
ctx->H[6] = 0x1f83d9ab;
ctx->H[7] = 0x5be0cd19;
ctx->total64 = 0;
ctx->buflen = 0;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF. */
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]) {
/* Take yet unprocessed bytes into account. */
uint32_t bytes = ctx->buflen;
size_t pad;
assert(ctx);
assert(resbuf);
/* Now count remaining bytes. */
ctx->total64 += bytes;
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
memcpy(&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3);
ctx->buffer32[(bytes + pad) / 4] = SWAP((ctx->total[TOTAL64_high] << 3)
| (ctx->total[TOTAL64_low] >> 29));
/* Process last bytes. */
sha256_process_block(ctx->buffer, bytes + pad + 8, ctx);
/* Put result from CTX in first 32 bytes following RESBUF. */
for (size_t i = 0; i < 8; ++i)
unaligned_write_ne32(resbuf + i * sizeof(uint32_t), SWAP(ctx->H[i]));
return resbuf;
}
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx) {
assert(buffer);
assert(ctx);
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0) {
size_t left_over = ctx->buflen;
size_t add = 128 - left_over > len ? len : 128 - left_over;
memcpy(&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64) {
sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64) {
if (IS_ALIGNED32(buffer)) {
sha256_process_block(buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
} else
while (len > 64) {
memcpy(ctx->buffer, buffer, 64);
sha256_process_block(ctx->buffer, 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
}
/* Move remaining bytes into internal buffer. */
if (len > 0) {
size_t left_over = ctx->buflen;
memcpy(&ctx->buffer[left_over], buffer, len);
left_over += len;
if (left_over >= 64) {
sha256_process_block(ctx->buffer, 64, ctx);
left_over -= 64;
memcpy(ctx->buffer, &ctx->buffer[64], left_over);
}
ctx->buflen = left_over;
}
}
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. */
static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) {
const uint32_t *words = ASSERT_PTR(buffer);
size_t nwords = len / sizeof(uint32_t);
assert(ctx);
uint32_t a = ctx->H[0];
uint32_t b = ctx->H[1];
uint32_t c = ctx->H[2];
uint32_t d = ctx->H[3];
uint32_t e = ctx->H[4];
uint32_t f = ctx->H[5];
uint32_t g = ctx->H[6];
uint32_t h = ctx->H[7];
/* First increment the byte count. FIPS 180-2 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. */
ctx->total64 += len;
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (nwords > 0) {
uint32_t W[64];
uint32_t a_save = a;
uint32_t b_save = b;
uint32_t c_save = c;
uint32_t d_save = d;
uint32_t e_save = e;
uint32_t f_save = f;
uint32_t g_save = g;
uint32_t h_save = h;
/* Operators defined in FIPS 180-2:4.1.2. */
#define Ch(x, y, z) ((x & y) ^ (~x & z))
#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
/* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
for (size_t t = 0; t < 16; ++t) {
W[t] = SWAP (*words);
++words;
}
for (size_t t = 16; t < 64; ++t)
W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
/* The actual computation according to FIPS 180-2:6.2.2 step 3. */
for (size_t t = 0; t < 64; ++t) {
uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
uint32_t T2 = S0 (a) + Maj (a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
/* Add the starting values of the context according to FIPS 180-2:6.2.2
step 4. */
a += a_save;
b += b_save;
c += c_save;
d += d_save;
e += e_save;
f += f_save;
g += g_save;
h += h_save;
/* Prepare for the next round. */
nwords -= 16;
}
/* Put checksum in context given as argument. */
ctx->H[0] = a;
ctx->H[1] = b;
ctx->H[2] = c;
ctx->H[3] = d;
ctx->H[4] = e;
ctx->H[5] = f;
ctx->H[6] = g;
ctx->H[7] = h;
}
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]) {
struct sha256_ctx ctx;
sha256_init_ctx(&ctx);
sha256_process_bytes(buffer, sz, &ctx);
return sha256_finish_ctx(&ctx, result);
}

View File

@ -1,39 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stddef.h>
#include <stdint.h>
#define SHA256_DIGEST_SIZE 32
struct sha256_ctx {
uint32_t H[8];
union {
uint64_t total64;
#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
uint32_t total[2];
};
uint32_t buflen;
union {
uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */
uint32_t buffer32[32];
uint64_t buffer64[16];
};
};
void sha256_init_ctx(struct sha256_ctx *ctx);
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]);
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
static inline void sha256_process_bytes_and_size(const void *buffer, size_t len, struct sha256_ctx *ctx) {
sha256_process_bytes(&len, sizeof(len), ctx);
sha256_process_bytes(buffer, len, ctx);
}
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]);
#define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {})