summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyze/analyze.c6
-rw-r--r--src/basic/memfd-util.c11
-rw-r--r--src/basic/missing_fcntl.h8
-rw-r--r--src/basic/unit-file.c5
-rw-r--r--src/boot/bootctl.c6
-rw-r--r--src/busctl/busctl.c2
-rw-r--r--src/core/dbus.c22
-rw-r--r--src/core/load-dropin.c6
-rw-r--r--src/core/load-fragment-gperf.gperf.in1
-rw-r--r--src/core/namespace.c7
-rw-r--r--src/coredump/coredumpctl.c2
-rw-r--r--src/firstboot/firstboot.c6
-rw-r--r--src/journal/journalctl.c6
-rw-r--r--src/libsystemd/meson.build4
-rw-r--r--src/libsystemd/sd-bus/bus-control.c78
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h2
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c60
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c156
-rw-r--r--src/libsystemd/sd-bus/test-bus-peersockaddr.c127
-rw-r--r--src/libsystemd/sd-bus/test-bus-server.c7
-rw-r--r--src/machine-id-setup/machine-id-setup-main.c6
-rw-r--r--src/partition/repart.c2
-rw-r--r--src/shared/base-filesystem.c5
-rw-r--r--src/shared/dissect-image.c32
-rw-r--r--src/shared/install.c21
-rw-r--r--src/shared/install.h1
-rw-r--r--src/shared/mount-setup.c43
-rw-r--r--src/shared/mount-util.h8
-rw-r--r--src/shared/watchdog.c15
-rw-r--r--src/systemctl/systemctl-enable.c6
-rw-r--r--src/systemctl/systemctl.c2
-rw-r--r--src/sysupdate/sysupdate.c2
-rw-r--r--src/sysusers/sysusers.c6
-rw-r--r--src/test/meson.build1
-rw-r--r--src/test/test-install-root.c12
-rw-r--r--src/test/test-memfd-util.c30
-rw-r--r--src/tmpfiles/tmpfiles.c6
37 files changed, 525 insertions, 195 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 09a38e7930..b555c713fc 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -599,7 +599,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, help },
@@ -660,13 +660,13 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_READ_ONLY,
- &unlink_dir,
+ &mounted_dir,
/* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
}
diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c
index 285abd41d3..8e6946642b 100644
--- a/src/basic/memfd-util.c
+++ b/src/basic/memfd-util.c
@@ -92,9 +92,15 @@ int memfd_map(int fd, uint64_t offset, size_t size, void **p) {
}
int memfd_set_sealed(int fd) {
+ int r;
+
assert(fd >= 0);
- return RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL));
+ r = RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_EXEC | F_SEAL_SEAL));
+ if (r == -EINVAL) /* old kernel ? */
+ r = RET_NERRNO(fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL));
+
+ return r;
}
int memfd_get_sealed(int fd) {
@@ -106,7 +112,8 @@ int memfd_get_sealed(int fd) {
if (r < 0)
return -errno;
- return r == (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
+ /* We ignore F_SEAL_EXEC here to support older kernels. */
+ return FLAGS_SET(r, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL);
}
int memfd_get_size(int fd, uint64_t *sz) {
diff --git a/src/basic/missing_fcntl.h b/src/basic/missing_fcntl.h
index 79e95a8f6f..24b2dc3119 100644
--- a/src/basic/missing_fcntl.h
+++ b/src/basic/missing_fcntl.h
@@ -25,6 +25,14 @@
#define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif
+#ifndef F_SEAL_FUTURE_WRITE
+#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */
+#endif
+
+#ifndef F_SEAL_EXEC
+#define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */
+#endif
+
#ifndef F_OFD_GETLK
#define F_OFD_GETLK 36
#define F_OFD_SETLK 37
diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c
index 41422579d6..54f2137a36 100644
--- a/src/basic/unit-file.c
+++ b/src/basic/unit-file.c
@@ -250,9 +250,10 @@ bool lookup_paths_timestamp_hash_same(const LookupPaths *lp, uint64_t timestamp_
static int directory_name_is_valid(const char *name) {
- /* Accept a directory whose name is a valid unit file name ending in .wants/, .requires/ or .d/ */
+ /* Accept a directory whose name is a valid unit file name ending in .wants/, .requires/,
+ * .upholds/ or .d/ */
- FOREACH_STRING(suffix, ".wants", ".requires", ".d") {
+ FOREACH_STRING(suffix, ".wants", ".requires", ".upholds", ".d") {
_cleanup_free_ char *chopped = NULL;
const char *e;
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index 0480e320c0..65608f5e83 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -445,7 +445,7 @@ static int bootctl_main(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
int r;
log_setup();
@@ -493,13 +493,13 @@ static int run(int argc, char *argv[]) {
arg_image_policy,
DISSECT_IMAGE_GENERIC_ROOT |
DISSECT_IMAGE_RELAX_VAR_CHECK,
- &unlink_dir,
+ &mounted_dir,
/* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
}
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 90f20c05a1..820d27da20 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -77,6 +77,8 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) {
if (r < 0)
return log_error_errno(r, "Failed to allocate bus: %m");
+ (void) sd_bus_set_description(bus, "busctl");
+
if (set_monitor) {
r = sd_bus_set_monitor(bus, true);
if (r < 0)
diff --git a/src/core/dbus.c b/src/core/dbus.c
index c41e1a6c74..7277696196 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -684,7 +684,7 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
- nfd = -EBADF;
+ TAKE_FD(nfd);
r = bus_check_peercred(bus);
if (r < 0) {
@@ -703,7 +703,8 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
r = sd_bus_negotiate_creds(bus, 1,
SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
- SD_BUS_CREDS_SELINUX_CONTEXT);
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION);
if (r < 0) {
log_warning_errno(r, "Failed to enable credentials for new connection: %m");
return 0;
@@ -721,6 +722,23 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
+ if (DEBUG_LOGGING) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
+ const char *comm = NULL, *description = NULL;
+ pid_t pid = 0;
+
+ r = sd_bus_get_owner_creds(bus, SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION, &c);
+ if (r < 0)
+ log_warning_errno(r, "Failed to get peer creds, ignoring: %m");
+ else {
+ (void) sd_bus_creds_get_pid(c, &pid);
+ (void) sd_bus_creds_get_comm(c, &comm);
+ (void) sd_bus_creds_get_description(c, &description);
+ }
+
+ log_debug("Accepting direct incoming connection from " PID_FMT " (%s) [%s]", pid, strna(comm), strna(description));
+ }
+
r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0) {
log_warning_errno(r, "Failed to attach new connection bus to event loop: %m");
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 53d2a3daa1..fd45744261 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -88,7 +88,7 @@ int unit_load_dropin(Unit *u) {
assert(u);
- /* Load dependencies from .wants and .requires directories */
+ /* Load dependencies from .wants, .requires and .upholds directories */
r = process_deps(u, UNIT_WANTS, ".wants");
if (r < 0)
return r;
@@ -97,6 +97,10 @@ int unit_load_dropin(Unit *u) {
if (r < 0)
return r;
+ r = process_deps(u, UNIT_UPHOLDS, ".upholds");
+ if (r < 0)
+ return r;
+
/* Load .conf dropins */
r = unit_find_dropin_paths(u, &l);
if (r <= 0)
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 110bccb7ad..2a3c2c2cb8 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -580,5 +580,6 @@ Scope.OOMPolicy, config_parse_oom_policy,
Install.Alias, NULL, 0, 0
Install.WantedBy, NULL, 0, 0
Install.RequiredBy, NULL, 0, 0
+Install.UpheldBy, NULL, 0, 0
Install.Also, NULL, 0, 0
Install.DefaultInstance, NULL, 0, 0
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 2fcc096217..1116ece59d 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -2166,10 +2166,11 @@ int setup_namespace(
* in the root. The temporary directory prevents any mounts from being potentially obscured
* my other mounts we already applied. We use the same mount point for all images, which is
* safe, since they all live in their own namespaces after all, and hence won't see each
- * other. */
+ * other. (Note: this directory is also created by PID 1 early on, we create it here for
+ * similar reasons as /run/systemd/ first.) */
+ root = "/run/systemd/mount-rootfs";
+ (void) mkdir_label(root, 0555);
- root = "/run/systemd/unit-root";
- (void) mkdir_label(root, 0700);
require_prefix = true;
}
diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c
index bc52cc0b06..e34d74765e 100644
--- a/src/coredump/coredumpctl.c
+++ b/src/coredump/coredumpctl.c
@@ -1350,7 +1350,7 @@ static int coredumpctl_main(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
int r, units_active;
setlocale(LC_ALL, "");
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 71b1e25c9d..6d50054baf 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -1506,7 +1506,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
_cleanup_close_ int rfd = -EBADF;
int r;
@@ -1546,13 +1546,13 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
- &unlink_dir,
+ &mounted_dir,
&rfd,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
} else {
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 12119b302c..62f74551ad 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2112,7 +2112,7 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false, since_seeked = false;
bool use_cursor = false, after_cursor = false;
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
@@ -2143,13 +2143,13 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_VALIDATE_OS |
DISSECT_IMAGE_RELAX_VAR_CHECK |
(arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS : DISSECT_IMAGE_READ_ONLY),
- &unlink_dir,
+ &mounted_dir,
/* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
}
diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build
index aa42497080..ee24240cd1 100644
--- a/src/libsystemd/meson.build
+++ b/src/libsystemd/meson.build
@@ -211,6 +211,10 @@ tests += [
'dependencies' : threads,
},
{
+ 'sources' : files('sd-bus/test-bus-peersockaddr.c'),
+ 'dependencies' : threads,
+ },
+ {
'sources' : files('sd-bus/test-bus-queue-ref-cycle.c'),
'dependencies' : threads,
},
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 864acd73ac..287cde6d41 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -722,9 +722,51 @@ _public_ int sd_bus_get_name_creds(
return 0;
}
+static int parse_sockaddr_string(const char *t, char **ret_comm, char **ret_description) {
+ _cleanup_free_ char *comm = NULL, *description = NULL;
+ const char *e, *sl;
+
+ assert(t);
+ assert(ret_comm);
+ assert(ret_description);
+
+ e = strstrafter(t, "/bus/");
+ if (!e) {
+ log_debug("Didn't find /bus/ substring in peer socket address, ignoring.");
+ goto not_found;
+ }
+
+ sl = strchr(e, '/');
+ if (!sl) {
+ log_debug("Didn't find / substring after /bus/ in peer socket address, ignoring.");
+ goto not_found;
+ }
+
+ if (sl - e > 0) {
+ comm = strndup(e, sl - e);
+ if (!comm)
+ return -ENOMEM;
+ }
+
+ sl++;
+ if (!isempty(sl)) {
+ description = strdup(sl);
+ if (!description)
+ return -ENOMEM;
+ }
+
+ *ret_comm = TAKE_PTR(comm);
+ *ret_description = TAKE_PTR(description);
+ return 0;
+
+not_found:
+ *ret_comm = *ret_description = NULL;
+ return 0;
+}
+
_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- bool do_label, do_groups;
+ bool do_label, do_groups, do_sockaddr_peer;
pid_t pid = 0;
int r;
@@ -742,9 +784,12 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT);
do_groups = bus->n_groups != SIZE_MAX && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS);
+ do_sockaddr_peer = bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1 &&
+ bus->sockaddr_peer.sa.sa_family == AF_UNIX &&
+ bus->sockaddr_peer.un.sun_path[0] == 0;
/* Avoid allocating anything if we have no chance of returning useful data */
- if (!bus->ucred_valid && !do_label && !do_groups)
+ if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer)
return -ENODATA;
c = bus_creds_new();
@@ -786,6 +831,35 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
}
+ if (do_sockaddr_peer) {
+ _cleanup_free_ char *t = NULL;
+
+ assert(bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1);
+ assert(bus->sockaddr_peer.sa.sa_family == AF_UNIX);
+ assert(bus->sockaddr_peer.un.sun_path[0] == 0);
+
+ /* So this is an abstract namespace socket, good. Now let's find the data we are interested in */
+ r = make_cstring(bus->sockaddr_peer.un.sun_path + 1,
+ bus->sockaddr_size_peer - offsetof(struct sockaddr_un, sun_path) - 1,
+ MAKE_CSTRING_ALLOW_TRAILING_NUL,
+ &t);
+ if (r == -ENOMEM)
+ return r;
+ if (r < 0)
+ log_debug_errno(r, "Can't extract string from peer socket address, ignoring: %m");
+ else {
+ r = parse_sockaddr_string(t, &c->comm, &c->description);
+ if (r < 0)
+ return r;
+
+ if (c->comm)
+ c->mask |= SD_BUS_CREDS_COMM & mask;
+
+ if (c->description)
+ c->mask |= SD_BUS_CREDS_DESCRIPTION & mask;
+ }
+ }
+
r = bus_creds_add_more(c, mask, pid, 0);
if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
return r;
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 0e44897e0e..1cf6974bff 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -267,6 +267,8 @@ struct sd_bus {
char *label;
gid_t *groups;
size_t n_groups;
+ union sockaddr_union sockaddr_peer;
+ socklen_t sockaddr_size_peer;
uint64_t creds_mask;
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index ceda20f289..741d54cabd 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -22,6 +22,7 @@
#include "memory-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "random-util.h"
#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -651,6 +652,17 @@ static void bus_get_peercred(sd_bus *b) {
b->n_groups = (size_t) r;
else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
log_debug_errno(r, "Failed to determine peer's group list: %m");
+
+ /* Let's query the peers socket address, it might carry information such as the peer's comm or
+ * description string */
+ zero(b->sockaddr_peer);
+ b->sockaddr_size_peer = 0;
+
+ socklen_t l = sizeof(b->sockaddr_peer) - 1; /* Leave space for a NUL */
+ if (getpeername(b->input_fd, &b->sockaddr_peer.sa, &l) < 0)
+ log_debug_errno(errno, "Failed to get peer's socket address, ignoring: %m");
+ else
+ b->sockaddr_size_peer = l;
}
static int bus_socket_start_auth_client(sd_bus *b) {
@@ -889,6 +901,50 @@ fail:
return r;
}
+static int bind_description(sd_bus *b, int fd, int family) {
+ _cleanup_free_ char *bind_name = NULL, *comm = NULL;
+ union sockaddr_union bsa;
+ const char *d = NULL;
+ int r;
+
+ assert(b);
+ assert(fd >= 0);
+
+ /* If this is an AF_UNIX socket, let's set our client's socket address to carry the description
+ * string for this bus connection. This is useful for debugging things, as the connection name is
+ * visible in various socket-related tools, and can even be queried by the server side. */
+
+ if (family != AF_UNIX)
+ return 0;
+
+ (void) sd_bus_get_description(b, &d);
+
+ /* Generate a recognizable source address in the abstract namespace. We'll include:
+ * - a random 64bit value (to avoid collisions)
+ * - our "comm" process name (suppressed if contains "/" to avoid parsing issues)
+ * - the description string of the bus connection. */
+ (void) get_process_comm(0, &comm);
+ if (comm && strchr(comm, '/'))
+ comm = mfree(comm);
+
+ if (!d && !comm) /* skip if we don't have either field, rely on kernel autobind instead */
+ return 0;
+
+ if (asprintf(&bind_name, "@%" PRIx64 "/bus/%s/%s", random_u64(), strempty(comm), strempty(d)) < 0)
+ return -ENOMEM;
+
+ strshorten(bind_name, sizeof_field(struct sockaddr_un, sun_path));
+
+ r = sockaddr_un_set_path(&bsa.un, bind_name);
+ if (r < 0)
+ return r;
+
+ if (bind(fd, &bsa.sa, r) < 0)
+ return -errno;
+
+ return 0;
+}
+
int bus_socket_connect(sd_bus *b) {
bool inotify_done = false;
int r;
@@ -911,6 +967,10 @@ int bus_socket_connect(sd_bus *b) {
if (b->input_fd < 0)
return -errno;
+ r = bind_description(b, b->input_fd, b->sockaddr.sa.sa_family);
+ if (r < 0)
+ return r;
+
b->input_fd = fd_move_above_stdio(b->input_fd);
b->output_fd = b->input_fd;
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index 8e66919b46..7abe129186 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -46,31 +46,25 @@ static int object_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_
return 0;
}
-static int server_init(sd_bus **_bus) {
- sd_bus *bus = NULL;
+static int server_init(sd_bus **ret_bus) {
+ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+ const char *unique, *desc;
sd_id128_t id;
int r;
- const char *unique, *desc;
- assert_se(_bus);
+ assert_se(ret_bus);
r = sd_bus_open_user_with_description(&bus, "my bus!");
- if (r < 0) {
- log_error_errno(r, "Failed to connect to user bus: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to user bus: %m");
r = sd_bus_get_bus_id(bus, &id);
- if (r < 0) {
- log_error_errno(r, "Failed to get server ID: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get server ID: %m");
r = sd_bus_get_unique_name(bus, &unique);
- if (r < 0) {
- log_error_errno(r, "Failed to get unique name: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unique name: %m");
assert_se(sd_bus_get_description(bus, &desc) >= 0);
assert_se(streq(desc, "my bus!"));
@@ -80,48 +74,35 @@ static int server_init(sd_bus **_bus) {
log_info("Can send file handles: %i", sd_bus_can_send(bus, 'h'));
r = sd_bus_request_name(bus, "org.freedesktop.systemd.test", 0);
- if (r < 0) {
- log_error_errno(r, "Failed to acquire name: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire name: %m");
r = sd_bus_add_fallback(bus, NULL, "/foo/bar", object_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to add object: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add object: %m");
r = sd_bus_match_signal(bus, NULL, NULL, NULL, "foo.bar", "Notify", match_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to request match: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to request match: %m");
r = sd_bus_match_signal(bus, NULL, NULL, NULL, "foo.bar", "NotifyTo", match_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to request match: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to request match: %m");
r = sd_bus_add_match(bus, NULL, "type='signal',interface='org.freedesktop.DBus',member='NameOwnerChanged'", match_callback, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to add match: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
bus_match_dump(stdout, &bus->match_callbacks, 0);
- *_bus = bus;
+ *ret_bus = TAKE_PTR(bus);
return 0;
-
-fail:
- sd_bus_unref(bus);
- return r;
}
-static int server(sd_bus *bus) {
- int r;
+static int server(sd_bus *_bus) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = ASSERT_PTR(_bus);
bool client1_gone = false, client2_gone = false;
+ int r;
while (!client1_gone || !client2_gone) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
@@ -129,30 +110,26 @@ static int server(sd_bus *bus) {
const char *label = NULL;
r = sd_bus_process(bus, &m);
- if (r < 0) {
- log_error_errno(r, "Failed to process requests: %m");
- goto fail;
- }
-
+ if (r < 0)
+ return log_error_errno(r, "Failed to process requests: %m");
if (r == 0) {
r = sd_bus_wait(bus, UINT64_MAX);
- if (r < 0) {
- log_error_errno(r, "Failed to wait: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to wait: %m");
continue;
}
-
if (!m)
continue;
- sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
- sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
+ (void) sd_bus_creds_get_pid(sd_bus_message_get_creds(m), &pid);
+ (void) sd_bus_creds_get_selinux_context(sd_bus_message_get_creds(m), &label);
+
log_info("Got message! member=%s pid="PID_FMT" label=%s",
strna(sd_bus_message_get_member(m)),
pid,
strna(label));
+
/* sd_bus_message_dump(m); */
/* sd_bus_message_rewind(m, true); */
@@ -161,40 +138,31 @@ static int server(sd_bus *bus) {
_cleanup_free_ char *lowercase = NULL;
r = sd_bus_message_read(m, "s", &hello);
- if (r < 0) {
- log_error_errno(r, "Failed to get parameter: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get parameter: %m");
lowercase = strdup(hello);
- if (!lowercase) {
- r = log_oom();
- goto fail;
- }
+ if (!lowercase)
+ return log_oom();
ascii_strlower(lowercase);
r = sd_bus_reply_method_return(m, "s", lowercase);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
+
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient1")) {
r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
client1_gone = true;
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "ExitClient2")) {
r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
client2_gone = true;
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Slow")) {
@@ -202,56 +170,40 @@ static int server(sd_bus *bus) {
sleep(1);
r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
} else if (sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "FileDescriptor")) {
int fd;
static const char x = 'X';
r = sd_bus_message_read(m, "h", &fd);
- if (r < 0) {
- log_error_errno(r, "Failed to get parameter: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get parameter: %m");
log_info("Received fd=%d", fd);
if (write(fd, &x, 1) < 0) {
- log_error_errno(errno, "Failed to write to fd: %m");
+ r = log_error_errno(errno, "Failed to write to fd: %m");
safe_close(fd);
- goto fail;
+ return r;
}
r = sd_bus_reply_method_return(m, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
} else if (sd_bus_message_is_method_call(m, NULL, NULL)) {
r = sd_bus_reply_method_error(
m,
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method."));
- if (r < 0) {
- log_error_errno(r, "Failed to send reply: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to send reply: %m");
}
}
- r = 0;
-
-fail:
- if (bus) {
- sd_bus_flush(bus);
- sd_bus_unref(bus);
- }
-
- return r;
+ return 0;
}
static void* client1(void *p) {
diff --git a/src/libsystemd/sd-bus/test-bus-peersockaddr.c b/src/libsystemd/sd-bus/test-bus-peersockaddr.c
new file mode 100644
index 0000000000..8bab429624
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-bus-peersockaddr.c
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <pthread.h>
+#include <unistd.h>
+
+#include "sd-bus.h"
+
+#include "fd-util.h"
+#include "process-util.h"
+#include "socket-util.h"
+#include "tests.h"
+
+static void *server(void *p) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_close_ int listen_fd = PTR_TO_INT(p), fd = -EBADF;
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
+ _cleanup_free_ char *our_comm = NULL;
+ sd_id128_t id;
+ int r;
+
+ assert_se(sd_id128_randomize(&id) >= 0);
+
+ fd = accept4(listen_fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
+ assert_se(fd >= 0);
+
+ assert_se(sd_bus_new(&bus) >= 0);
+ assert_se(sd_bus_set_fd(bus, fd, fd) >= 0);
+ TAKE_FD(fd);
+ assert_se(sd_bus_set_server(bus, true, id) >= 0);
+ assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION) >= 0);
+
+ assert_se(sd_bus_start(bus) >= 0);
+
+ assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION, &c) >= 0);
+
+ uid_t u;
+ assert_se(sd_bus_creds_get_euid(c, &u) >= 0);
+ assert_se(u == getuid());
+
+ gid_t g;
+ assert_se(sd_bus_creds_get_egid(c, &g) >= 0);
+ assert_se(g == getgid());
+
+ pid_t pid;
+ assert_se(sd_bus_creds_get_pid(c, &pid) >= 0);
+ assert_se(pid == getpid_cached());
+
+ const char *comm;
+ assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
+ assert_se(get_process_comm(0, &our_comm) >= 0);
+ assert_se(streq_ptr(comm, our_comm));
+
+ const char *description;
+ assert_se(sd_bus_creds_get_description(c, &description) >= 0);
+ assert_se(streq_ptr(description, "wuffwuff"));
+
+ for (;;) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+ r = sd_bus_process(bus, &m);
+ assert_se(r >= 0);
+
+ if (r == 0) {
+ assert_se(sd_bus_wait(bus, UINT64_MAX) >= 0);
+ continue;
+ }
+
+ if (sd_bus_message_is_method_call(m, "foo.foo", "Foo") > 0) {
+ assert_se(sd_bus_reply_method_return(m, "s", "bar") >= 0);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static void* client(void *p) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ const char *z;
+
+ assert_se(sd_bus_new(&bus) >= 0);
+ assert_se(sd_bus_set_description(bus, "wuffwuff") >= 0);
+ assert_se(sd_bus_set_address(bus, p) >= 0);
+ assert_se(sd_bus_start(bus) >= 0);
+
+ assert_se(sd_bus_call_method(bus, "foo.foo", "/foo", "foo.foo", "Foo", NULL, &reply, "s", "foo") >= 0);
+
+ assert_se(sd_bus_message_read(reply, "s", &z) >= 0);
+ assert_se(streq_ptr(z, "bar"));
+
+ return NULL;
+}
+
+TEST(description) {
+ _cleanup_free_ char *a = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ };
+ socklen_t salen;
+ pthread_t s, c;
+
+ fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
+ assert_se(fd >= 0);
+
+ assert_se(bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path)) >= 0); /* force auto-bind */
+
+ assert_se(listen(fd, 1) >= 0);
+
+ salen = sizeof(sa);
+ assert_se(getsockname(fd, &sa.sa, &salen) >= 0);
+ assert_se(salen >= offsetof(struct sockaddr_un, sun_path));
+ assert_se(sa.un.sun_path[0] == 0);
+
+ assert_se(asprintf(&a, "unix:abstract=%s", sa.un.sun_path + 1) >= 0);
+
+ assert_se(pthread_create(&s, NULL, server, INT_TO_PTR(fd)) == 0);
+ TAKE_FD(fd);
+
+ assert_se(pthread_create(&c, NULL, client, a) == 0);
+
+ assert_se(pthread_join(s, NULL) == 0);
+ assert_se(pthread_join(c, NULL) == 0);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c
index ab4045ee15..5024c1d4f5 100644
--- a/src/libsystemd/sd-bus/test-bus-server.c
+++ b/src/libsystemd/sd-bus/test-bus-server.c
@@ -22,8 +22,8 @@ struct context {
};
static void *server(void *p) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
struct context *c = p;
- sd_bus *bus = NULL;
sd_id128_t id;
bool quit = false;
int r;
@@ -97,11 +97,6 @@ static void *server(void *p) {
r = 0;
fail:
- if (bus) {
- sd_bus_flush(bus);
- sd_bus_unref(bus);
- }
-
return INT_TO_PTR(r);
}
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index 38d66def06..59aad985f8 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -136,7 +136,7 @@ static int parse_argv(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
int r;
log_parse_environment();
@@ -157,13 +157,13 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
- &unlink_dir,
+ &mounted_dir,
/* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
}
diff --git a/src/partition/repart.c b/src/partition/repart.c
index 1f3e78a84e..995a40655d 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -6669,7 +6669,7 @@ static int determine_auto_size(Context *c) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
_cleanup_(context_freep) Context* context = NULL;
bool node_is_our_loop = false;
int r;
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index 8a50cc6ebb..0244c92c79 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -40,6 +40,11 @@ static const BaseFilesystem table[] = {
{ "proc", 0555, NULL, NULL, true },
{ "sys", 0555, NULL, NULL, true },
{ "dev", 0555, NULL, NULL, true },
+ { "run", 0555, NULL, NULL, true },
+ /* We don't add /tmp/ here for now (even though it's necessary for regular operation), because we
+ * want to support both cases where /tmp/ is a mount of its own (in which case we probably should set
+ * the mode to 1555, to indicate that noone should write to it, not even root) and when it's part of
+ * the rootfs (in which case we should set mode 1777), and we simply don't know what's right. */
/* Various architecture ABIs define the path to the dynamic loader via the /lib64/ subdirectory of
* the root directory. When booting from an otherwise empty root file system (where only /usr/ has
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index b84ef46442..39f75dd0dd 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -3667,8 +3667,7 @@ int mount_image_privately_interactively(
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
- _cleanup_(rmdir_and_freep) char *created_dir = NULL;
- _cleanup_free_ char *temp = NULL;
+ _cleanup_free_ char *dir = NULL;
int r;
/* Mounts an OS image at a temporary place, inside a newly created mount namespace of our own. This
@@ -3676,7 +3675,6 @@ int mount_image_privately_interactively(
* easily. */
assert(image);
- assert(ret_directory);
assert(ret_loop_device);
/* We intend to mount this right-away, hence add the partitions if needed and pin them. */
@@ -3687,10 +3685,6 @@ int mount_image_privately_interactively(
if (r < 0)
return log_error_errno(r, "Failed to load root hash data: %m");
- r = tempfn_random_child(NULL, program_invocation_short_name, &temp);
- if (r < 0)
- return log_error_errno(r, "Failed to generate temporary mount directory: %m");
-
r = loop_device_make_by_path(
image,
FLAGS_SET(flags, DISSECT_IMAGE_DEVICE_READ_ONLY) ? O_RDONLY : O_RDWR,
@@ -3723,13 +3717,16 @@ int mount_image_privately_interactively(
if (r < 0)
return log_error_errno(r, "Failed to detach mount namespace: %m");
- r = mkdir_p(temp, 0700);
+ r = mkdir_p("/run/systemd/mount-rootfs", 0555);
if (r < 0)
return log_error_errno(r, "Failed to create mount point: %m");
- created_dir = TAKE_PTR(temp);
-
- r = dissected_image_mount_and_warn(dissected_image, created_dir, UID_INVALID, UID_INVALID, flags);
+ r = dissected_image_mount_and_warn(
+ dissected_image,
+ "/run/systemd/mount-rootfs",
+ /* uid_shift= */ UID_INVALID,
+ /* uid_range= */ UID_INVALID,
+ flags);
if (r < 0)
return r;
@@ -3741,19 +3738,26 @@ int mount_image_privately_interactively(
if (r < 0)
return log_error_errno(r, "Failed to relinquish DM and loopback block devices: %m");
+ if (ret_directory) {
+ dir = strdup("/run/systemd/mount-rootfs");
+ if (!dir)
+ return log_oom();
+ }
+
if (ret_dir_fd) {
_cleanup_close_ int dir_fd = -EBADF;
- dir_fd = open(created_dir, O_CLOEXEC|O_DIRECTORY);
+ dir_fd = open("/run/systemd/mount-rootfs", O_CLOEXEC|O_DIRECTORY);
if (dir_fd < 0)
return log_error_errno(errno, "Failed to open mount point directory: %m");
*ret_dir_fd = TAKE_FD(dir_fd);
}
- *ret_directory = TAKE_PTR(created_dir);
- *ret_loop_device = TAKE_PTR(d);
+ if (ret_directory)
+ *ret_directory = TAKE_PTR(dir);
+ *ret_loop_device = TAKE_PTR(d);
return 0;
}
diff --git a/src/shared/install.c b/src/shared/install.c
index 152e517ebc..7903de17b1 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -73,7 +73,8 @@ static bool install_info_has_rules(const InstallInfo *i) {
return !strv_isempty(i->aliases) ||
!strv_isempty(i->wanted_by) ||
- !strv_isempty(i->required_by);
+ !strv_isempty(i->required_by) ||
+ !strv_isempty(i->upheld_by);
}
static bool install_info_has_also(const InstallInfo *i) {
@@ -942,7 +943,7 @@ static int find_symlinks(
continue;
suffix = strrchr(de->d_name, '.');
- if (!STRPTR_IN_SET(suffix, ".wants", ".requires"))
+ if (!STRPTR_IN_SET(suffix, ".wants", ".requires", ".upholds"))
continue;
path = path_join(config_path, de->d_name);
@@ -967,7 +968,8 @@ static int find_symlinks(
log_debug_errno(r, "Failed to look up symlinks in \"%s\": %m", path);
}
- /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */
+ /* We didn't find any suitable symlinks in .wants, .requires or .upholds directories,
+ * let's look for linked unit files in this directory. */
rewinddir(config_dir);
return find_symlinks_in_directory(config_dir, config_path, root_dir, i,
/* ignore_destination= */ false,
@@ -1081,6 +1083,7 @@ static void install_info_clear(InstallInfo *i) {
i->aliases = strv_free(i->aliases);
i->wanted_by = strv_free(i->wanted_by);
i->required_by = strv_free(i->required_by);
+ i->upheld_by = strv_free(i->upheld_by);
i->also = strv_free(i->also);
i->default_instance = mfree(i->default_instance);
i->symlink_target = mfree(i->symlink_target);
@@ -1337,6 +1340,7 @@ static int unit_file_load(
{ "Install", "Alias", config_parse_alias, 0, &info->aliases },
{ "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
{ "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
+ { "Install", "UpheldBy", config_parse_strv, 0, &info->upheld_by },
{ "Install", "DefaultInstance", config_parse_default_instance, 0, info },
{ "Install", "Also", config_parse_also, 0, ctx },
{}
@@ -1440,7 +1444,8 @@ static int unit_file_load(
return
(int) strv_length(info->aliases) +
(int) strv_length(info->wanted_by) +
- (int) strv_length(info->required_by);
+ (int) strv_length(info->required_by) +
+ (int) strv_length(info->upheld_by);
}
static int unit_file_load_or_readlink(
@@ -2113,6 +2118,10 @@ static int install_info_apply(
if (r == 0)
r = q;
+ q = install_info_symlink_wants(scope, file_flags, info, lp, config_path, info->upheld_by, ".upholds/", changes, n_changes);
+ if (r == 0)
+ r = q;
+
return r;
}
@@ -2733,8 +2742,10 @@ int unit_file_add_dependency(
if (dep == UNIT_WANTS)
l = &info->wanted_by;
- else
+ else if (dep == UNIT_REQUIRES)
l = &info->required_by;
+ else
+ l = &info->upheld_by;
strv_free(*l);
*l = strv_new(target_info->name);
diff --git a/src/shared/install.h b/src/shared/install.h
index 30b07a725f..bc0c6db828 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -92,6 +92,7 @@ struct InstallInfo {
char **aliases;
char **wanted_by;
char **required_by;
+ char **upheld_by;
char **also;
char *default_instance;
diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
index a920e8a92a..6162a58d9a 100644
--- a/src/shared/mount-setup.c
+++ b/src/shared/mount-setup.c
@@ -114,6 +114,8 @@ static const MountPoint mount_table[] = {
NULL, MNT_NONE, },
};
+assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
+
bool mount_point_is_api(const char *path) {
/* Checks if this mount point is considered "API", and hence
* should be ignored */
@@ -186,13 +188,11 @@ static int mount_one(const MountPoint *p, bool relabel) {
strna(p->options));
if (FLAGS_SET(p->mode, MNT_FOLLOW_SYMLINK))
- r = RET_NERRNO(mount(p->what, p->where, p->type, p->flags, p->options));
+ r = mount_follow_verbose(priority, p->what, p->where, p->type, p->flags, p->options);
else
- r = mount_nofollow(p->what, p->where, p->type, p->flags, p->options);
- if (r < 0) {
- log_full_errno(priority, r, "Failed to mount %s at %s: %m", p->type, p->where);
+ r = mount_nofollow_verbose(priority, p->what, p->where, p->type, p->flags, p->options);
+ if (r < 0)
return (p->mode & MNT_FATAL) ? r : 0;
- }
/* Relabel again, since we now mounted something fresh here */
if (relabel)
@@ -205,7 +205,7 @@ static int mount_one(const MountPoint *p, bool relabel) {
(void) umount2(p->where, UMOUNT_NOFOLLOW);
(void) rmdir(p->where);
- log_full_errno(priority, r, "Mount point %s not writable after mounting: %m", p->where);
+ log_full_errno(priority, r, "Mount point %s not writable after mounting, undoing: %m", p->where);
return (p->mode & MNT_FATAL) ? r : 0;
}
}
@@ -213,27 +213,23 @@ static int mount_one(const MountPoint *p, bool relabel) {
return 1;
}
-static int mount_points_setup(unsigned n, bool loaded_policy) {
- unsigned i;
- int r = 0;
+static int mount_points_setup(size_t n, bool loaded_policy) {
+ int ret = 0, r;
- for (i = 0; i < n; i ++) {
- int j;
+ assert(n <= ELEMENTSOF(mount_table));
- j = mount_one(mount_table + i, loaded_policy);
- if (j != 0 && r >= 0)
- r = j;
+ FOREACH_ARRAY(mp, mount_table, n) {
+ r = mount_one(mp, loaded_policy);
+ if (r != 0 && ret >= 0)
+ ret = r;
}
- return r;
+ return ret;
}
int mount_setup_early(void) {
- assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
-
- /* Do a minimal mount of /proc and friends to enable the most
- * basic stuff, such as SELinux */
- return mount_points_setup(N_EARLY_MOUNT, false);
+ /* Do a minimal mount of /proc and friends to enable the most basic stuff, such as SELinux */
+ return mount_points_setup(N_EARLY_MOUNT, /* loaded_policy= */ false);
}
static const char *join_with(const char *controller) {
@@ -279,7 +275,7 @@ static int symlink_controller(const char *target, const char *alias) {
p = strjoina("/sys/fs/cgroup/", target);
r = mac_smack_copy(a, p);
- if (r < 0 && r != -EOPNOTSUPP)
+ if (r < 0 && !ERRNO_IS_NOT_SUPPORTED(r))
return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", p, a);
#endif
@@ -554,6 +550,11 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
(void) mkdir_label("/run/systemd", 0755);
(void) mkdir_label("/run/systemd/system", 0755);
+ /* Make sure there's always a place where sandboxed environments can mount root file systems they are
+ * about to move into, even when unprivileged, without having to create a temporary one in /tmp/
+ * (which they then have to keep track of and clean) */
+ (void) mkdir_label("/run/systemd/mount-rootfs", 0555);
+
/* Make sure we have a mount point to hide in sandboxes */
(void) mkdir_label("/run/credentials", 0755);
diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h
index d63fddeb10..8a84d61622 100644
--- a/src/shared/mount-util.h
+++ b/src/shared/mount-util.h
@@ -83,6 +83,14 @@ static inline char* umount_and_rmdir_and_free(char *p) {
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, umount_and_rmdir_and_free);
+static inline char *umount_and_free(char *p) {
+ PROTECT_ERRNO;
+ if (p)
+ (void) umount_recursive(p, 0);
+ return mfree(p);
+}
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, umount_and_free);
+
int bind_mount_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory);
int mount_image_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory, const MountOptions *options, const ImagePolicy *image_policy);
diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c
index 4445efb125..4c1a968718 100644
--- a/src/shared/watchdog.c
+++ b/src/shared/watchdog.c
@@ -318,9 +318,10 @@ static int open_watchdog(void) {
STRV_FOREACH(wd, try_order) {
watchdog_fd = open(*wd, O_WRONLY|O_CLOEXEC);
if (watchdog_fd >= 0) {
- r = free_and_strdup(&watchdog_device, *wd);
- if (r < 0)
- return log_oom_debug();
+ if (free_and_strdup(&watchdog_device, *wd) < 0) {
+ r = log_oom_debug();
+ goto close_and_fail;
+ }
break;
}
@@ -342,8 +343,12 @@ static int open_watchdog(void) {
r = update_timeout();
if (r < 0)
- watchdog_close(true);
+ goto close_and_fail;
+
+ return 0;
+close_and_fail:
+ watchdog_close(/* disarm= */ true);
return r;
}
@@ -356,7 +361,7 @@ int watchdog_set_device(const char *path) {
r = free_and_strdup(&watchdog_device, path);
if (r > 0) /* watchdog_device changed */
- watchdog_fd = safe_close(watchdog_fd);
+ watchdog_close(/* disarm= */ true);
return r;
}
diff --git a/src/systemctl/systemctl-enable.c b/src/systemctl/systemctl-enable.c
index 6d3709705e..940f54607f 100644
--- a/src/systemctl/systemctl-enable.c
+++ b/src/systemctl/systemctl-enable.c
@@ -248,9 +248,9 @@ int verb_enable(int argc, char *argv[], void *userdata) {
}
if (carries_install_info == 0 && !ignore_carries_install_info)
- log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, Also=,\n"
- "Alias= settings in the [Install] section, and DefaultInstance= for template\n"
- "units). This means they are not meant to be enabled or disabled using systemctl.\n"
+ log_notice("The unit files have no installation config (WantedBy=, RequiredBy=, UpheldBy=,\n"
+ "Also=, or Alias= settings in the [Install] section, and DefaultInstance= for\n"
+ "template units). This means they are not meant to be enabled or disabled using systemctl.\n"
" \n" /* trick: the space is needed so that the line does not get stripped from output */
"Possible reasons for having this kind of units are:\n"
"%1$s A unit may be statically enabled by being symlinked from another unit's\n"
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 71c068b09e..b31a59785b 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -1224,7 +1224,7 @@ static int systemctl_main(int argc, char *argv[]) {
static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
int r;
setlocale(LC_ALL, "");
diff --git a/src/sysupdate/sysupdate.c b/src/sysupdate/sysupdate.c
index 29cd552ea8..76777dc08e 100644
--- a/src/sysupdate/sysupdate.c
+++ b/src/sysupdate/sysupdate.c
@@ -861,7 +861,7 @@ static int process_image(
LoopDevice **ret_loop_device) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *mounted_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
int r;
assert(ret_mounted_dir);
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 58246b5d85..aa1f1356dc 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -2157,7 +2157,7 @@ static int read_credential_lines(void) {
static int run(int argc, char *argv[]) {
#ifndef STANDALONE
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
#endif
_cleanup_close_ int lock = -EBADF;
Item *i;
@@ -2191,13 +2191,13 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
- &unlink_dir,
+ &mounted_dir,
/* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
}
diff --git a/src/test/meson.build b/src/test/meson.build
index 8e76df624d..7f8de2a2ce 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -112,6 +112,7 @@ simple_tests += files(
'test-log.c',
'test-logarithm.c',
'test-macro.c',
+ 'test-memfd-util.c',
'test-memory-util.c',
'test-mempool.c',
'test-mkdir.c',
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
index 55b8894ecc..80166b17c6 100644
--- a/src/test/test-install-root.c
+++ b/src/test/test-install-root.c
@@ -1135,6 +1135,9 @@ TEST(verify_alias) {
verify_one(&plain_service, "alias.socket", -EXDEV, NULL);
verify_one(&plain_service, "alias@.service", -EXDEV, NULL);
verify_one(&plain_service, "alias@inst.service", -EXDEV, NULL);
+
+ /* Setting WantedBy= and RequiredBy= through Alias= is supported for the sake of backwards
+ * compatibility. */
verify_one(&plain_service, "foo.target.wants/plain.service", 0, NULL);
verify_one(&plain_service, "foo.target.wants/plain.socket", -EXDEV, NULL);
verify_one(&plain_service, "foo.target.wants/plain@.service", -EXDEV, NULL);
@@ -1143,9 +1146,14 @@ TEST(verify_alias) {
verify_one(&plain_service, "foo.target.requires/plain.socket", -EXDEV, NULL);
verify_one(&plain_service, "foo.target.requires/plain@.service", -EXDEV, NULL);
verify_one(&plain_service, "foo.target.requires/service", -EXDEV, NULL);
- verify_one(&plain_service, "foo.target.conf/plain.service", -EXDEV, NULL);
- verify_one(&plain_service, "foo.service/plain.service", -EXDEV, NULL); /* missing dir suffix */
verify_one(&plain_service, "asdf.requires/plain.service", -EXDEV, NULL); /* invalid unit name component */
+ /* The newly-added UpheldBy= (.upholds/) and other suffixes should be rejected */
+ verify_one(&plain_service, "foo.target.upholds/plain.service", -EXDEV, NULL);
+ verify_one(&plain_service, "foo.target.upholds/plain.socket", -EXDEV, NULL);
+ verify_one(&plain_service, "foo.target.upholds/plain@.service", -EXDEV, NULL);
+ verify_one(&plain_service, "foo.target.upholds/service", -EXDEV, NULL);
+ verify_one(&plain_service, "foo.service/plain.service", -EXDEV, NULL); /* missing dir suffix */
+ verify_one(&plain_service, "foo.target.conf/plain.service", -EXDEV, NULL);
verify_one(&bare_template, "alias.service", -EXDEV, NULL);
verify_one(&bare_template, "alias.socket", -EXDEV, NULL);
diff --git a/src/test/test-memfd-util.c b/src/test/test-memfd-util.c
new file mode 100644
index 0000000000..f8e1b46075
--- /dev/null
+++ b/src/test/test-memfd-util.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <unistd.h>
+
+#include "errno-util.h"
+#include "fd-util.h"
+#include "memfd-util.h"
+#include "string-util.h"
+#include "tests.h"
+
+TEST(memfd_get_sealed) {
+#define TEST_TEXT "this is some random test text we are going to write to a memfd"
+ _cleanup_close_ int fd = -EBADF;
+
+ fd = memfd_new("test-memfd-get-sealed");
+ if (fd < 0) {
+ assert_se(ERRNO_IS_NOT_SUPPORTED(fd));
+ return;
+ }
+
+ assert_se(write(fd, TEST_TEXT, strlen(TEST_TEXT)) == strlen(TEST_TEXT));
+ /* we'll leave the read offset at the end of the memfd, the fdopen_independent() descriptors should
+ * start at the beginning anyway */
+
+ assert_se(memfd_get_sealed(fd) == 0);
+ assert_se(memfd_set_sealed(fd) >= 0);
+ assert_se(memfd_get_sealed(fd) > 0);
+}
+
+DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 382fa8b56a..be04b25653 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -4223,7 +4223,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_array_hash_ops, char, string_
static int run(int argc, char *argv[]) {
#ifndef STANDALONE
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
- _cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
+ _cleanup_(umount_and_freep) char *mounted_dir = NULL;
#endif
_cleanup_strv_free_ char **config_dirs = NULL;
bool invalid_config = false;
@@ -4314,13 +4314,13 @@ static int run(int argc, char *argv[]) {
DISSECT_IMAGE_RELAX_VAR_CHECK |
DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_GROWFS,
- &unlink_dir,
+ &mounted_dir,
/* ret_dir_fd= */ NULL,
&loop_device);
if (r < 0)
return r;
- arg_root = strdup(unlink_dir);
+ arg_root = strdup(mounted_dir);
if (!arg_root)
return log_oom();
}