diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/string-util.c | 11 | ||||
-rw-r--r-- | src/basic/string-util.h | 5 | ||||
-rw-r--r-- | src/cgls/cgls.c | 6 | ||||
-rw-r--r-- | src/core/dbus-manager.c | 63 | ||||
-rw-r--r-- | src/core/dbus-manager.h | 2 | ||||
-rw-r--r-- | src/core/execute.c | 10 | ||||
-rw-r--r-- | src/core/manager.c | 24 | ||||
-rw-r--r-- | src/core/timer.c | 2 | ||||
-rw-r--r-- | src/journal/journalctl.c | 4 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-common-errors.c | 1 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/bus-common-errors.h | 1 | ||||
-rw-r--r-- | src/mount/mount-tool.c | 3 | ||||
-rw-r--r-- | src/reply-password/reply-password.c | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-stub.c | 2 | ||||
-rw-r--r-- | src/shared/ask-password-api.c | 10 | ||||
-rw-r--r-- | src/shared/dissect-image.c | 39 | ||||
-rw-r--r-- | src/shared/gpt.h | 2 | ||||
-rw-r--r-- | src/shared/install.c | 150 | ||||
-rw-r--r-- | src/shared/seccomp-util.c | 7 | ||||
-rw-r--r-- | src/shared/seccomp-util.h | 8 | ||||
-rw-r--r-- | src/test/test-install-root.c | 23 | ||||
-rw-r--r-- | src/test/test-seccomp.c | 16 | ||||
-rw-r--r-- | src/test/test-string-util.c | 35 | ||||
-rw-r--r-- | src/tty-ask-password-agent/tty-ask-password-agent.c | 4 |
24 files changed, 320 insertions, 110 deletions
diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 2ba3604ba0..9d2f4bc8f9 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -821,6 +821,7 @@ int free_and_strdup(char **p, const char *s) { return 1; } +#if !HAVE_DECL_EXPLICIT_BZERO /* * Pointer to memset is volatile so that compiler must de-reference * the pointer and can't assume that it points to any function in @@ -831,19 +832,19 @@ typedef void *(*memset_t)(void *,int,size_t); static volatile memset_t memset_func = memset; -void* memory_erase(void *p, size_t l) { - return memset_func(p, 'x', l); +void explicit_bzero(void *p, size_t l) { + memset_func(p, '\0', l); } +#endif char* string_erase(char *x) { - if (!x) return NULL; /* A delicious drop of snake-oil! To be called on memory where * we stored passphrases or so, after we used them. */ - - return memory_erase(x, strlen(x)); + explicit_bzero(x, strlen(x)); + return x; } char *string_free_erase(char *s) { diff --git a/src/basic/string-util.h b/src/basic/string-util.h index e99f7964be..be44dedff4 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -189,7 +189,10 @@ static inline void *memmem_safe(const void *haystack, size_t haystacklen, const return memmem(haystack, haystacklen, needle, needlelen); } -void* memory_erase(void *p, size_t l); +#if !HAVE_DECL_EXPLICIT_BZERO +void explicit_bzero(void *p, size_t l); +#endif + char *string_erase(char *x); char *string_free_erase(char *s); diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index ea79b9185e..5574c14555 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -241,9 +241,9 @@ int main(int argc, char *argv[]) { goto finish; } - r = cg_split_spec(*name, &c, &p); - if (r < 0) { - log_error_errno(r, "Failed to split argument %s: %m", *name); + q = cg_split_spec(*name, &c, &p); + if (q < 0) { + log_error_errno(q, "Failed to split argument %s: %m", *name); goto failed; } diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 9876251438..0136d38833 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -19,6 +19,7 @@ #include <errno.h> #include <sys/prctl.h> +#include <sys/statvfs.h> #include <unistd.h> #include "alloc-util.h" @@ -38,6 +39,7 @@ #include "fs-util.h" #include "install.h" #include "log.h" +#include "parse-util.h" #include "path-util.h" #include "selinux-access.h" #include "stat-util.h" @@ -48,6 +50,10 @@ #include "virt.h" #include "watchdog.h" +/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state there, and if + * we can't we'll fail badly. */ +#define RELOAD_DISK_SPACE_MIN (UINT64_C(16) * UINT64_C(1024) * UINT64_C(1024)) + static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) { return (runtime ? UNIT_FILE_RUNTIME : 0) | (force ? UNIT_FILE_FORCE : 0); @@ -1312,6 +1318,40 @@ static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bu return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed."); } +static int verify_run_space(const char *message, sd_bus_error *error) { + struct statvfs svfs; + uint64_t available; + + if (statvfs("/run/systemd", &svfs) < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to statvfs(/run/systemd): %m"); + + available = (uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize; + + if (available < RELOAD_DISK_SPACE_MIN) { + char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX]; + return sd_bus_error_setf(error, + BUS_ERROR_DISK_FULL, + "%s, not enough space available on /run/systemd. " + "Currently, %s are free, but a safety buffer of %s is enforced.", + message, + format_bytes(fb_available, sizeof(fb_available), available), + format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN)); + } + + return 0; +} + +int verify_run_space_and_log(const char *message) { + sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = verify_run_space(message, &error); + if (r < 0) + log_error_errno(r, "%s", bus_error_message(&error, r)); + + return r; +} + static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; int r; @@ -1319,6 +1359,10 @@ static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error * assert(message); assert(m); + r = verify_run_space("Refusing to reload", error); + if (r < 0) + return r; + r = mac_selinux_access_check(message, "reload", error); if (r < 0) return r; @@ -1351,6 +1395,10 @@ static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_erro assert(message); assert(m); + r = verify_run_space("Refusing to reexecute", error); + if (r < 0) + return r; + r = mac_selinux_access_check(message, "reload", error); if (r < 0) return r; @@ -1469,11 +1517,26 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er char *ri = NULL, *rt = NULL; const char *root, *init; Manager *m = userdata; + struct statvfs svfs; + uint64_t available; int r; assert(message); assert(m); + if (statvfs("/run/systemd", &svfs) < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to statvfs(/run/systemd): %m"); + + available = (uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize; + + if (available < RELOAD_DISK_SPACE_MIN) { + char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX]; + log_warning("Dangerously low amount of free space on /run/systemd, root switching operation might not complete successfuly. " + "Currently, %s are free, but %s are suggested. Proceeding anyway.", + format_bytes(fb_available, sizeof(fb_available), available), + format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN)); + } + r = mac_selinux_access_check(message, "reboot", error); if (r < 0) return r; diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h index 36a2e9481b..9f3222da28 100644 --- a/src/core/dbus-manager.h +++ b/src/core/dbus-manager.h @@ -26,3 +26,5 @@ extern const sd_bus_vtable bus_manager_vtable[]; void bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec); void bus_manager_send_reloading(Manager *m, bool active); void bus_manager_send_change_signal(Manager *m); + +int verify_run_space_and_log(const char *message); diff --git a/src/core/execute.c b/src/core/execute.c index 47cc4311c1..aa0ddb564e 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -815,13 +815,10 @@ static int get_fixed_user(const ExecContext *c, const char **user, assert(c); - if (!c->user) - return 0; - /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway * (i.e. are "/" or "/bin/nologin"). */ - name = c->user; + name = c->user ?: "root"; r = get_user_creds_clean(&name, uid, gid, home, shell); if (r < 0) return r; @@ -2439,11 +2436,12 @@ static int exec_child( } if (context->utmp_id) - utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path, + utmp_put_init_process(context->utmp_id, getpid(), getsid(0), + context->tty_path, context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS : context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS : USER_PROCESS, - username ? "root" : context->user); + username); if (context->user) { r = chown_terminal(STDIN_FILENO, uid); diff --git a/src/core/manager.c b/src/core/manager.c index d83c5ef5e2..e4da945777 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1984,7 +1984,9 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t if (MANAGER_IS_SYSTEM(m)) { /* This is for compatibility with the * original sysvinit */ - m->exit_code = MANAGER_REEXECUTE; + r = verify_run_space_and_log("Refusing to reexecute"); + if (r >= 0) + m->exit_code = MANAGER_REEXECUTE; break; } @@ -2061,7 +2063,9 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t } case SIGHUP: - m->exit_code = MANAGER_RELOAD; + r = verify_run_space_and_log("Refusing to reload"); + if (r >= 0) + m->exit_code = MANAGER_RELOAD; break; default: { @@ -2432,18 +2436,22 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) { } int manager_open_serialization(Manager *m, FILE **_f) { - const char *path; int fd = -1; FILE *f; assert(_f); - path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp"; - fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC); - if (fd < 0) - return -errno; + fd = memfd_create("systemd-serialization", MFD_CLOEXEC); + if (fd < 0) { + const char *path; - log_debug("Serializing state to %s", path); + path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp"; + fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC); + if (fd < 0) + return -errno; + log_debug("Serializing state to %s.", path); + } else + log_debug("Serializing state to memfd."); f = fdopen(fd, "w+"); if (!f) { diff --git a/src/core/timer.c b/src/core/timer.c index d7441d638f..af67b7591a 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -350,7 +350,7 @@ static void add_random(Timer *t, usec_t *v) { else *v += add; - log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); + log_unit_debug(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); } static void timer_enter_waiting(Timer *t, bool initial) { diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 2639fd6cf5..9ad6f115a1 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -686,7 +686,9 @@ static int parse_argv(int argc, char *argv[]) { r = free_and_strdup(&arg_verify_key, optarg); if (r < 0) return r; - string_erase(optarg); + /* Use memset not string_erase so this doesn't look confusing + * in ps or htop output. */ + memset(optarg, 'x', strlen(optarg)); arg_merge = false; break; diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index c9fd79e3b4..b40ba2520c 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -47,6 +47,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING, EHOSTDOWN), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DYNAMIC_USER, ESRCH), SD_BUS_ERROR_MAP(BUS_ERROR_NOT_REFERENCED, EUNATCH), + SD_BUS_ERROR_MAP(BUS_ERROR_DISK_FULL, ENOSPC), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE, ENOENT), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 525b79fa77..4523be05ce 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -43,6 +43,7 @@ #define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning" #define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser" #define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced" +#define BUS_ERROR_DISK_FULL "org.freedesktop.systemd1.DiskFull" #define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" #define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage" diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index e66c2fe5f3..4b3cac8a22 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -100,7 +100,7 @@ static void help(void) { " Set automount unit property\n" " --bind-device Bind automount unit to device\n" " --list List mountable block devices\n" - " -u --umount Unmount a mount point\n" + " -u --umount Unmount mount points\n" , program_invocation_short_name); } @@ -139,6 +139,7 @@ static int parse_argv(int argc, char *argv[]) { { "discover", no_argument, NULL, ARG_DISCOVER }, { "type", required_argument, NULL, 't' }, { "options", required_argument, NULL, 'o' }, + { "fsck", required_argument, NULL, ARG_FSCK }, { "description", required_argument, NULL, ARG_DESCRIPTION }, { "property", required_argument, NULL, 'p' }, { "automount", required_argument, NULL, ARG_AUTOMOUNT }, diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c index 17eab9772e..a17c8a62b8 100644 --- a/src/reply-password/reply-password.c +++ b/src/reply-password/reply-password.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) { r = send_on_socket(fd, argv[2], packet, length); finish: - memory_erase(packet, sizeof(packet)); + explicit_bzero(packet, sizeof(packet)); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index e76de6c06a..4a3c5f612f 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -328,7 +328,7 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) { goto fail; } - log_info("Processing query..."); + log_debug("Processing query..."); return; fail: diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 3e877920da..e3b29e390c 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -95,7 +95,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) { if (n < m) break; - memory_erase(p, n); + explicit_bzero(p, n); free(p); m *= 2; } @@ -104,7 +104,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) { if (!l) return -ENOMEM; - memory_erase(p, n); + explicit_bzero(p, n); *ret = l; return 0; @@ -140,7 +140,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa return r; serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING); - memory_erase(p, n); + explicit_bzero(p, n); if (serial == -1) return -errno; @@ -390,7 +390,7 @@ int ask_password_tty( } x = strndup(passphrase, p); - memory_erase(passphrase, p); + explicit_bzero(passphrase, p); if (!x) { r = -ENOMEM; goto finish; @@ -647,7 +647,7 @@ int ask_password_agent( l = strv_new("", NULL); else l = strv_parse_nulstr(passphrase+1, n-1); - memory_erase(passphrase, n); + explicit_bzero(passphrase, n); if (!l) { r = -ENOMEM; goto finish; diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 878cb008aa..c17486cba2 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -347,9 +347,6 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI sd_id128_t type_id, id; bool rw = true; - if (pflags & GPT_FLAG_NO_AUTO) - continue; - sid = blkid_partition_get_uuid(pp); if (!sid) continue; @@ -363,18 +360,37 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI continue; if (sd_id128_equal(type_id, GPT_HOME)) { + + if (pflags & GPT_FLAG_NO_AUTO) + continue; + designator = PARTITION_HOME; rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_SRV)) { + + if (pflags & GPT_FLAG_NO_AUTO) + continue; + designator = PARTITION_SRV; rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ESP)) { + + /* Note that we don't check the GPT_FLAG_NO_AUTO flag for the ESP, as it is not defined + * there. We instead check the GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as recommended by the + * UEFI spec (See "12.3.3 Number and Location of System Partitions"). */ + + if (pflags & GPT_FLAG_NO_BLOCK_IO_PROTOCOL) + continue; + designator = PARTITION_ESP; fstype = "vfat"; } #ifdef GPT_ROOT_NATIVE else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) { + if (pflags & GPT_FLAG_NO_AUTO) + continue; + /* If a root ID is specified, ignore everything but the root id */ if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) continue; @@ -384,6 +400,9 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) { + if (pflags & GPT_FLAG_NO_AUTO) + continue; + m->can_verity = true; /* Ignore verity unless a root hash is specified */ @@ -399,6 +418,9 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI #ifdef GPT_ROOT_SECONDARY else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY)) { + if (pflags & GPT_FLAG_NO_AUTO) + continue; + /* If a root ID is specified, ignore everything but the root id */ if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) continue; @@ -407,6 +429,10 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI architecture = SECONDARY_ARCHITECTURE; rw = !(pflags & GPT_FLAG_READ_ONLY); } else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) { + + if (pflags & GPT_FLAG_NO_AUTO) + continue; + m->can_verity = true; /* Ignore verity unless root has is specified */ @@ -420,10 +446,17 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI } #endif else if (sd_id128_equal(type_id, GPT_SWAP)) { + + if (pflags & GPT_FLAG_NO_AUTO) + continue; + designator = PARTITION_SWAP; fstype = "swap"; } else if (sd_id128_equal(type_id, GPT_LINUX_GENERIC)) { + if (pflags & GPT_FLAG_NO_AUTO) + continue; + if (generic_node) multiple_generic = true; else { diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 13d80d611c..cc752006fa 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -71,6 +71,8 @@ # define GPT_ROOT_NATIVE_VERITY GPT_ROOT_ARM_VERITY #endif +#define GPT_FLAG_NO_BLOCK_IO_PROTOCOL (1ULL << 1) + /* Flags we recognize on the root, swap, home and srv partitions when * doing auto-discovery. These happen to be identical to what * Microsoft defines for its own Basic Data Partitions, but that's diff --git a/src/shared/install.c b/src/shared/install.c index 478abac8ab..f25ed685f6 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -208,7 +208,7 @@ static int path_is_control(const LookupPaths *p, const char *path) { path_equal_ptr(parent, p->runtime_control); } -static int path_is_config(const LookupPaths *p, const char *path) { +static int path_is_config(const LookupPaths *p, const char *path, bool check_parent) { _cleanup_free_ char *parent = NULL; assert(p); @@ -217,15 +217,19 @@ static int path_is_config(const LookupPaths *p, const char *path) { /* Note that we do *not* have generic checks for /etc or /run in place, since with * them we couldn't discern configuration from transient or generated units */ - parent = dirname_malloc(path); - if (!parent) - return -ENOMEM; + if (check_parent) { + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; - return path_equal_ptr(parent, p->persistent_config) || - path_equal_ptr(parent, p->runtime_config); + path = parent; + } + + return path_equal_ptr(path, p->persistent_config) || + path_equal_ptr(path, p->runtime_config); } -static int path_is_runtime(const LookupPaths *p, const char *path) { +static int path_is_runtime(const LookupPaths *p, const char *path, bool check_parent) { _cleanup_free_ char *parent = NULL; const char *rpath; @@ -239,16 +243,20 @@ static int path_is_runtime(const LookupPaths *p, const char *path) { if (rpath && path_startswith(rpath, "/run")) return true; - parent = dirname_malloc(path); - if (!parent) - return -ENOMEM; + if (check_parent) { + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; - return path_equal_ptr(parent, p->runtime_config) || - path_equal_ptr(parent, p->generator) || - path_equal_ptr(parent, p->generator_early) || - path_equal_ptr(parent, p->generator_late) || - path_equal_ptr(parent, p->transient) || - path_equal_ptr(parent, p->runtime_control); + path = parent; + } + + return path_equal_ptr(path, p->runtime_config) || + path_equal_ptr(path, p->generator) || + path_equal_ptr(path, p->generator_early) || + path_equal_ptr(path, p->generator_late) || + path_equal_ptr(path, p->transient) || + path_equal_ptr(path, p->runtime_control); } static int path_is_vendor(const LookupPaths *p, const char *path) { @@ -677,7 +685,6 @@ static int find_symlinks_fd( int fd, const char *path, const char *config_path, - const LookupPaths *lp, bool *same_name_link) { _cleanup_closedir_ DIR *d = NULL; @@ -688,7 +695,6 @@ static int find_symlinks_fd( assert(fd >= 0); assert(path); assert(config_path); - assert(lp); assert(same_name_link); d = fdopendir(fd); @@ -722,7 +728,7 @@ static int find_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link); + q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link); if (q > 0) return 1; if (r == 0) @@ -800,7 +806,6 @@ static int find_symlinks( const char *root_dir, const char *name, const char *config_path, - const LookupPaths *lp, bool *same_name_link) { int fd; @@ -817,44 +822,82 @@ static int find_symlinks( } /* This takes possession of fd and closes it */ - return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link); + return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link); } static int find_symlinks_in_scope( - UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *state) { - bool same_name_link_runtime = false, same_name_link = false; + bool same_name_link_runtime = false, same_name_link_config = false; + bool enabled_in_runtime = false, enabled_at_all = false; + char **p; int r; - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); assert(paths); assert(name); - /* First look in the persistent config path */ - r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link); - if (r < 0) - return r; - if (r > 0) { - *state = UNIT_FILE_ENABLED; - return r; + STRV_FOREACH(p, paths->search_path) { + bool same_name_link = false; + + r = find_symlinks(paths->root_dir, name, *p, &same_name_link); + if (r < 0) + return r; + if (r > 0) { + /* We found symlinks in this dir? Yay! Let's see where precisely it is enabled. */ + + r = path_is_config(paths, *p, false); + if (r < 0) + return r; + if (r > 0) { + /* This is the best outcome, let's return it immediately. */ + *state = UNIT_FILE_ENABLED; + return 1; + } + + r = path_is_runtime(paths, *p, false); + if (r < 0) + return r; + if (r > 0) + enabled_in_runtime = true; + else + enabled_at_all = true; + + } else if (same_name_link) { + + r = path_is_config(paths, *p, false); + if (r < 0) + return r; + if (r > 0) + same_name_link_config = true; + else { + r = path_is_runtime(paths, *p, false); + if (r < 0) + return r; + if (r > 0) + same_name_link_runtime = true; + } + } } - /* Then look in runtime config path */ - r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime); - if (r < 0) - return r; - if (r > 0) { + if (enabled_in_runtime) { *state = UNIT_FILE_ENABLED_RUNTIME; - return r; + return 1; + } + + /* Here's a special rule: if the unit we are looking for is an instance, and it symlinked in the search path + * outside of runtime and configuration directory, then we consider it statically enabled. Note we do that only + * for instance, not for regular names, as those are merely aliases, while instances explicitly instantiate + * something, and hence are a much stronger concept. */ + if (enabled_at_all && unit_name_is_valid(name, UNIT_NAME_INSTANCE)) { + *state = UNIT_FILE_STATIC; + return 1; } /* Hmm, we didn't find it, but maybe we found the same name * link? */ - if (same_name_link) { + if (same_name_link_config) { *state = UNIT_FILE_LINKED; return 1; } @@ -1354,7 +1397,8 @@ static int install_info_follow( InstallContext *c, UnitFileInstallInfo *i, const char *root_dir, - SearchFlags flags) { + SearchFlags flags, + bool ignore_different_name) { assert(c); assert(i); @@ -1367,7 +1411,7 @@ static int install_info_follow( /* If the basename doesn't match, the caller should add a * complete new entry for this. */ - if (!streq(basename(i->symlink_target), i->name)) + if (!ignore_different_name && !streq(basename(i->symlink_target), i->name)) return -EXDEV; free_and_replace(i->path, i->symlink_target); @@ -1408,14 +1452,14 @@ static int install_info_traverse( return -ELOOP; if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) { - r = path_is_config(paths, i->path); + r = path_is_config(paths, i->path, true); if (r < 0) return r; if (r > 0) return -ELOOP; } - r = install_info_follow(c, i, paths->root_dir, flags); + r = install_info_follow(c, i, paths->root_dir, flags, false); if (r == -EXDEV) { _cleanup_free_ char *buffer = NULL; const char *bn; @@ -1439,6 +1483,18 @@ static int install_info_traverse( if (r < 0) return r; + if (streq(buffer, i->name)) { + + /* We filled in the instance, and the target stayed the same? If so, then let's + * honour the link as it is. */ + + r = install_info_follow(c, i, paths->root_dir, flags, true); + if (r < 0) + return r; + + continue; + } + bn = buffer; } @@ -2027,7 +2083,7 @@ static int path_shall_revert(const LookupPaths *paths, const char *path) { /* Checks whether the path is one where the drop-in directories shall be removed. */ - r = path_is_config(paths, path); + r = path_is_config(paths, path, true); if (r != 0) return r; @@ -2135,7 +2191,7 @@ int unit_file_revert( if (errno != ENOENT) return -errno; } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { - r = path_is_config(&paths, path); + r = path_is_config(&paths, path, true); if (r < 0) return r; if (r > 0) { @@ -2481,7 +2537,7 @@ static int unit_file_lookup_state( switch (i->type) { case UNIT_FILE_TYPE_MASKED: - r = path_is_runtime(paths, i->path); + r = path_is_runtime(paths, i->path, true); if (r < 0) return r; @@ -2505,7 +2561,7 @@ static int unit_file_lookup_state( break; } - r = find_symlinks_in_scope(scope, paths, i->name, &state); + r = find_symlinks_in_scope(paths, i->name, &state); if (r < 0) return r; if (r == 0) { diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 2c73cb8fa4..609e0619af 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -171,11 +171,11 @@ int seccomp_init_for_arch(scmp_filter_ctx *ret, uint32_t arch, uint32_t default_ if (arch != SCMP_ARCH_NATIVE && arch != seccomp_arch_native()) { - r = seccomp_arch_add(seccomp, arch); + r = seccomp_arch_remove(seccomp, seccomp_arch_native()); if (r < 0) goto finish; - r = seccomp_arch_remove(seccomp, seccomp_arch_native()); + r = seccomp_arch_add(seccomp, arch); if (r < 0) goto finish; @@ -873,6 +873,8 @@ int seccomp_protect_sysctl(void) { } int seccomp_restrict_address_families(Set *address_families, bool whitelist) { + +#if !SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN uint32_t arch; int r; @@ -1001,6 +1003,7 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) { if (r < 0) log_debug_errno(r, "Failed to install socket family rules for architecture %s, skipping: %m", seccomp_arch_to_string(arch)); } +#endif return 0; } diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 4438e87fa6..2563fcd38a 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -76,6 +76,14 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist); int seccomp_restrict_realtime(void); int seccomp_memory_deny_write_execute(void); +#if defined(__i386__) || defined(__s390x__) || defined(__s390__) || defined(__powerpc64__) || defined(__powerpc__) || defined (__mips__) +/* On these archs, socket() is implemented via the socketcall() syscall multiplexer, and we can't restrict it hence via + * seccomp */ +#define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 1 +#else +#define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0 +#endif + extern const uint32_t seccomp_local_archs[]; #define SECCOMP_FOREACH_LOCAL_ARCH(arch) \ diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index d0bc8004f3..575401cb91 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -736,6 +736,28 @@ static void test_preset_order(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); } +static void test_static_instance(const char *root) { + UnitFileState state; + const char *p; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/static-instance@.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/static-instance@foo.service"); + assert_se(symlink("static-instance@.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_STATIC); +} + int main(int argc, char *argv[]) { char root[] = "/tmp/rootXXXXXX"; const char *p; @@ -766,6 +788,7 @@ int main(int argc, char *argv[]) { test_preset_and_list(root); test_preset_order(root); test_revert(root); + test_static_instance(root); assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 6f15879c45..54e7947c2f 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -283,8 +283,14 @@ static void test_restrict_address_families(void) { assert_se(fd >= 0); safe_close(fd); +#if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + assert_se(fd >= 0); + safe_close(fd); +#else assert_se(socket(AF_UNIX, SOCK_DGRAM, 0) < 0); assert_se(errno == EAFNOSUPPORT); +#endif fd = socket(AF_NETLINK, SOCK_DGRAM, 0); assert_se(fd >= 0); @@ -300,11 +306,21 @@ static void test_restrict_address_families(void) { assert_se(fd >= 0); safe_close(fd); +#if SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN + fd = socket(AF_UNIX, SOCK_DGRAM, 0); + assert_se(fd >= 0); + safe_close(fd); + + fd = socket(AF_NETLINK, SOCK_DGRAM, 0); + assert_se(fd >= 0); + safe_close(fd); +#else assert_se(socket(AF_UNIX, SOCK_DGRAM, 0) < 0); assert_se(errno == EAFNOSUPPORT); assert_se(socket(AF_NETLINK, SOCK_DGRAM, 0) < 0); assert_se(errno == EAFNOSUPPORT); +#endif _exit(EXIT_SUCCESS); } diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index e43373b0f5..4b3e924cfb 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -29,31 +29,20 @@ static void test_string_erase(void) { assert_se(streq(string_erase(x), "")); x = strdupa("1"); - assert_se(streq(string_erase(x), "x")); - - x = strdupa("12"); - assert_se(streq(string_erase(x), "xx")); - - x = strdupa("123"); - assert_se(streq(string_erase(x), "xxx")); - - x = strdupa("1234"); - assert_se(streq(string_erase(x), "xxxx")); - - x = strdupa("12345"); - assert_se(streq(string_erase(x), "xxxxx")); - - x = strdupa("123456"); - assert_se(streq(string_erase(x), "xxxxxx")); - - x = strdupa("1234567"); - assert_se(streq(string_erase(x), "xxxxxxx")); - - x = strdupa("12345678"); - assert_se(streq(string_erase(x), "xxxxxxxx")); + assert_se(streq(string_erase(x), "")); x = strdupa("123456789"); - assert_se(streq(string_erase(x), "xxxxxxxxx")); + assert_se(streq(string_erase(x), "")); + + assert_se(x[1] == '\0'); + assert_se(x[2] == '\0'); + assert_se(x[3] == '\0'); + assert_se(x[4] == '\0'); + assert_se(x[5] == '\0'); + assert_se(x[6] == '\0'); + assert_se(x[7] == '\0'); + assert_se(x[8] == '\0'); + assert_se(x[9] == '\0'); } static void test_ascii_strcasecmp_n(void) { diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index b45490be1a..a17c006d57 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -243,7 +243,7 @@ static int ask_password_plymouth( r = 0; finish: - memory_erase(buffer, sizeof(buffer)); + explicit_bzero(buffer, sizeof(buffer)); return r; } @@ -283,7 +283,7 @@ static int send_passwords(const char *socket_name, char **passwords) { r = log_debug_errno(errno, "sendto(): %m"); finish: - memory_erase(packet, packet_length); + explicit_bzero(packet, packet_length); return r; } |