summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/systemctl.xml11
-rw-r--r--man/systemd.unit.xml39
-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/libsystemd/sd-netlink/netlink-util.c89
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h5
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c6
-rw-r--r--src/machine-id-setup/machine-id-setup-main.c6
-rw-r--r--src/nspawn/nspawn-oci.c33
-rw-r--r--src/nspawn/nspawn-settings.c26
-rw-r--r--src/nspawn/nspawn.c1
-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/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
-rw-r--r--src/udev/net/link-config.c41
-rw-r--r--src/udev/net/link-config.h1
-rw-r--r--src/udev/udev-builtin-blkid.c3
-rw-r--r--src/udev/udev-builtin-btrfs.c3
-rw-r--r--src/udev/udev-builtin-hwdb.c3
-rw-r--r--src/udev/udev-builtin-input_id.c6
-rw-r--r--src/udev/udev-builtin-keyboard.c3
-rw-r--r--src/udev/udev-builtin-kmod.c5
-rw-r--r--src/udev/udev-builtin-net_id.c3
-rw-r--r--src/udev/udev-builtin-net_setup_link.c9
-rw-r--r--src/udev/udev-builtin-path_id.c5
-rw-r--r--src/udev/udev-builtin-uaccess.c3
-rw-r--r--src/udev/udev-builtin-usb_id.c5
-rw-r--r--src/udev/udev-builtin.c7
-rw-r--r--src/udev/udev-builtin.h5
-rw-r--r--src/udev/udev-event.c47
-rw-r--r--src/udev/udev-event.h1
-rw-r--r--src/udev/udev-rules.c2
-rw-r--r--src/udev/udevadm-test-builtin.c13
-rw-r--r--test/fuzz/fuzz-nspawn-oci/basic.json247
-rw-r--r--test/fuzz/fuzz-unit-file/directives-all.service2
-rw-r--r--test/testsuite-23.units/testsuite-23-upheldby-install.service9
-rwxr-xr-xtest/units/testsuite-13.nspawn-oci.sh383
-rwxr-xr-xtest/units/testsuite-13.nspawn.sh21
-rwxr-xr-xtest/units/testsuite-17.12.sh86
-rwxr-xr-xtest/units/testsuite-23.Upholds.sh5
70 files changed, 1460 insertions, 373 deletions
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 009aabacb9..e3776fb277 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -367,10 +367,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<listitem>
<para>Shows units required and wanted by the specified
units. This recursively lists units following the
- <varname>Requires=</varname>,
- <varname>Requisite=</varname>,
- <varname>ConsistsOf=</varname>,
- <varname>Wants=</varname>, <varname>BindsTo=</varname>
+ <varname>Requires=</varname>, <varname>Requisite=</varname>,
+ <varname>Wants=</varname>, <varname>ConsistsOf=</varname>,
+ <varname>BindsTo=</varname>, and <varname>Upholds=</varname>
dependencies. If no units are specified,
<filename>default.target</filename> is implied.</para>
@@ -1181,7 +1180,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
</listitem>
</varlistentry>
<varlistentry>
- <term><command>cancel <replaceable>JOB</replaceable>…</command></term>
+ <term><command>cancel <optional><replaceable>JOB</replaceable>…</optional></command></term>
<listitem>
<para>Cancel one or more jobs specified on the command line
@@ -1791,7 +1790,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<para>Show reverse dependencies between units with
<command>list-dependencies</command>, i.e. follow
dependencies of type <varname>WantedBy=</varname>,
- <varname>RequiredBy=</varname>,
+ <varname>RequiredBy=</varname>, <varname>UpheldBy=</varname>,
<varname>PartOf=</varname>, <varname>BoundBy=</varname>,
instead of <varname>Wants=</varname> and similar.
</para>
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index c618e403f7..e28bfe845e 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -749,8 +749,7 @@
<para>When <varname>Upholds=b.service</varname> is used on <filename>a.service</filename>, this
dependency will show as <varname>UpheldBy=a.service</varname> in the property listing of
- <filename>b.service</filename>. The <varname>UpheldBy=</varname> dependency cannot be specified
- directly.</para>
+ <filename>b.service</filename>.</para>
</listitem>
</varlistentry>
@@ -1849,6 +1848,12 @@
<entry>[Install] section</entry>
</row>
<row>
+ <entry><varname>Upholds=</varname></entry>
+ <entry><varname>UpheldBy=</varname></entry>
+ <entry>[Unit] section</entry>
+ <entry>[Install] section</entry>
+ </row>
+ <row>
<entry><varname>PartOf=</varname></entry>
<entry><varname>ConsistsOf=</varname></entry>
<entry>[Unit] section</entry>
@@ -1895,10 +1900,10 @@
</tgroup>
</table>
- <para>Note: <varname>WantedBy=</varname> and <varname>RequiredBy=</varname> are
- used in the [Install] section to create symlinks in <filename>.wants/</filename>
- and <filename>.requires/</filename> directories. They cannot be used directly as a
- unit configuration setting.</para>
+ <para>Note: <varname>WantedBy=</varname>, <varname>RequiredBy=</varname>, and <varname>UpheldBy=</varname>
+ are used in the [Install] section to create symlinks in <filename>.wants/</filename>,
+ <filename>.requires/</filename>, and <filename>.upholds/</filename> directories. They cannot be used
+ directly as a unit configuration setting.</para>
<para>Note: <varname>ConsistsOf=</varname>, <varname>BoundBy=</varname>,
<varname>RequisiteOf=</varname>, <varname>ConflictedBy=</varname> are created
@@ -1947,23 +1952,23 @@
<varlistentry>
<term><varname>WantedBy=</varname></term>
<term><varname>RequiredBy=</varname></term>
+ <term><varname>UpheldBy=</varname></term>
<listitem><para>This option may be used more than once, or a space-separated list of unit names may
- be given. A symbolic link is created in the <filename>.wants/</filename> or
- <filename>.requires/</filename> directory of each of the listed units when this unit is installed by
- <command>systemctl enable</command>. This has the effect of a dependency of type
- <varname>Wants=</varname> or <varname>Requires=</varname> being added from the listed unit to the
- current unit. The primary result is that the current unit will be started when the listed unit is
- started, see the description of <varname>Wants=</varname> and <varname>Requires=</varname> in the
- [Unit] section for details.</para>
+ be given. A symbolic link is created in the <filename>.wants/</filename>, <filename>.requires/</filename>,
+ or <filename>.upholds/</filename> directory of each of the listed units when this unit is installed
+ by <command>systemctl enable</command>. This has the effect of a dependency of type
+ <varname>Wants=</varname>, <varname>Requires=</varname>, or <varname>Upholds=</varname> being added
+ from the listed unit to the current unit. See the description of the mentioned dependency types
+ in the [Unit] section for details.</para>
<para>In case of template units listing non template units, the listing unit must have
<varname>DefaultInstance=</varname> set, or <command>systemctl enable</command> must be called with
an instance name. The instance (default or specified) will be added to the
- <filename>.wants/</filename> or <filename>.requires/</filename> list of the listed unit. For example,
- <command>WantedBy=getty.target</command> in a service <filename>getty@.service</filename> will result
- in <command>systemctl enable getty@tty2.service</command> creating a
- <filename>getty.target.wants/getty@tty2.service</filename> link to
+ <filename>.wants/</filename>, <filename>.requires/</filename>, or <filename>.upholds/</filename>
+ list of the listed unit. For example, <command>WantedBy=getty.target</command> in a service
+ <filename>getty@.service</filename> will result in <command>systemctl enable getty@tty2.service</command>
+ creating a <filename>getty.target.wants/getty@tty2.service</filename> link to
<filename>getty@.service</filename>. This also applies to listing specific instances of templated
units: this specific instance will gain the dependency. A template unit may also list a template
unit, in which case a generic dependency will be added where each instance of the listing unit will
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/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 6cd916a209..6ded66b935 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -11,44 +11,93 @@
#include "process-util.h"
#include "strv.h"
-int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
+static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
- _cleanup_strv_free_ char **alternative_names = NULL;
- bool altname_deleted = false;
int r;
assert(rtnl);
assert(ifindex > 0);
assert(name);
- if (!ifname_valid(name))
+ /* Assign the requested name. */
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
+ if (r < 0)
+ return r;
+
+ return sd_netlink_call(*rtnl, message, 0, NULL);
+}
+
+int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const *alternative_names) {
+ _cleanup_strv_free_ char **original_altnames = NULL, **new_altnames = NULL;
+ bool altname_deleted = false;
+ int r;
+
+ assert(rtnl);
+ assert(ifindex > 0);
+
+ if (isempty(name) && strv_isempty(alternative_names))
+ return 0;
+
+ if (name && !ifname_valid(name))
return -EINVAL;
- r = rtnl_get_link_alternative_names(rtnl, ifindex, &alternative_names);
+ /* If the requested name is already assigned as an alternative name, then first drop it. */
+ r = rtnl_get_link_alternative_names(rtnl, ifindex, &original_altnames);
if (r < 0)
log_debug_errno(r, "Failed to get alternative names on network interface %i, ignoring: %m",
ifindex);
- if (strv_contains(alternative_names, name)) {
- r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
- if (r < 0)
- return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
- name, ifindex);
+ if (name) {
+ if (strv_contains(original_altnames, name)) {
+ r = rtnl_delete_link_alternative_names(rtnl, ifindex, STRV_MAKE(name));
+ if (r < 0)
+ return log_debug_errno(r, "Failed to remove '%s' from alternative names on network interface %i: %m",
+ name, ifindex);
+
+ altname_deleted = true;
+ }
- altname_deleted = true;
+ r = set_link_name(rtnl, ifindex, name);
+ if (r < 0)
+ goto fail;
}
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
- if (r < 0)
- goto fail;
+ /* Filter out already assigned names from requested alternative names. Also, dedup the request. */
+ STRV_FOREACH(a, alternative_names) {
+ if (streq_ptr(name, *a))
+ continue;
- r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
- if (r < 0)
- goto fail;
+ if (strv_contains(original_altnames, *a))
+ continue;
- r = sd_netlink_call(*rtnl, message, 0, NULL);
- if (r < 0)
- goto fail;
+ if (strv_contains(new_altnames, *a))
+ continue;
+
+ if (!ifname_valid_full(*a, IFNAME_VALID_ALTERNATIVE))
+ continue;
+
+ r = strv_extend(&new_altnames, *a);
+ if (r < 0)
+ return r;
+ }
+
+ strv_sort(new_altnames);
+
+ /* Finally, assign alternative names. */
+ r = rtnl_set_link_alternative_names(rtnl, ifindex, new_altnames);
+ if (r == -EEXIST) /* Already assigned to another interface? */
+ STRV_FOREACH(a, new_altnames) {
+ r = rtnl_set_link_alternative_names(rtnl, ifindex, STRV_MAKE(*a));
+ if (r < 0)
+ log_debug_errno(r, "Failed to assign '%s' as an alternative name on network interface %i, ignoring: %m",
+ *a, ifindex);
+ }
+ else if (r < 0)
+ log_debug_errno(r, "Failed to assign alternative names on network interface %i, ignoring: %m", ifindex);
return 0;
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index 72d16fa9a9..2f9f7e9676 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -28,7 +28,10 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
-int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name);
+int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const* alternative_names);
+static inline int rtnl_append_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names) {
+ return rtnl_set_link_name(rtnl, ifindex, NULL, alternative_names);
+}
int rtnl_set_link_properties(
sd_netlink **rtnl,
int ifindex,
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 9ad8ecf320..43124b99ae 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -662,12 +662,13 @@ TEST(rtnl_set_link_name) {
assert_se(strv_contains(alternative_names, "testlongalternativename"));
assert_se(strv_contains(alternative_names, "test-shortname"));
- assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename") == -EINVAL);
- assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname") >= 0);
+ assert_se(rtnl_set_link_name(&rtnl, ifindex, "testlongalternativename", NULL) == -EINVAL);
+ assert_se(rtnl_set_link_name(&rtnl, ifindex, "test-shortname", STRV_MAKE("testlongalternativename", "test-shortname", "test-additional-name")) >= 0);
alternative_names = strv_free(alternative_names);
assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
assert_se(strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(strv_contains(alternative_names, "test-additional-name"));
assert_se(!strv_contains(alternative_names, "test-shortname"));
assert_se(rtnl_delete_link_alternative_names(&rtnl, ifindex, STRV_MAKE("testlongalternativename")) >= 0);
@@ -675,6 +676,7 @@ TEST(rtnl_set_link_name) {
alternative_names = strv_free(alternative_names);
assert_se(rtnl_get_link_alternative_names(&rtnl, ifindex, &alternative_names) >= 0);
assert_se(!strv_contains(alternative_names, "testlongalternativename"));
+ assert_se(strv_contains(alternative_names, "test-additional-name"));
assert_se(!strv_contains(alternative_names, "test-shortname"));
}
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/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c
index 3c6bfd3eaf..5e21538597 100644
--- a/src/nspawn/nspawn-oci.c
+++ b/src/nspawn/nspawn-oci.c
@@ -605,7 +605,7 @@ static int oci_namespace_type(const char *name, JsonVariant *v, JsonDispatchFlag
*nsflags = CLONE_NEWCGROUP;
else
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
- "Unknown cgroup type, refusing: %s", n);
+ "Unknown namespace type, refusing: %s", n);
return 0;
}
@@ -663,7 +663,7 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl
if (!FLAGS_SET(n, CLONE_NEWNS))
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
- "Containers without file system namespace aren't supported.");
+ "Containers without a mount namespace aren't supported.");
s->private_network = FLAGS_SET(n, CLONE_NEWNET);
s->userns_mode = FLAGS_SET(n, CLONE_NEWUSER) ? USER_NAMESPACE_FIXED : USER_NAMESPACE_NO;
@@ -819,7 +819,7 @@ static int oci_device_file_mode(const char *name, JsonVariant *v, JsonDispatchFl
return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
"fileMode out of range, refusing.");
- *mode = m;
+ *mode = (*mode & ~07777) | m;
return 0;
}
@@ -874,7 +874,7 @@ static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags
/* Suppress a couple of implicit device nodes */
r = devname_from_devnum(node->mode, makedev(node->major, node->minor), &path);
if (r < 0)
- json_log(e, flags|JSON_DEBUG, 0, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor);
+ json_log(e, flags|JSON_DEBUG, r, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor);
else {
if (PATH_IN_SET(path,
"/dev/null",
@@ -1177,13 +1177,13 @@ static int oci_cgroup_memory(const char *name, JsonVariant *v, JsonDispatchFlags
};
static const JsonDispatch table[] = {
- { "limit", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, limit), 0 },
- { "reservation", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, reservation), 0 },
- { "swap", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, swap), 0 },
- { "kernel", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
- { "kernelTCP", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
- { "swapiness", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
- { "disableOOMKiller", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
+ { "limit", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, limit), 0 },
+ { "reservation", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, reservation), 0 },
+ { "swap", JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, swap), 0 },
+ { "kernel", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
+ { "kernelTCP", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
+ { "swapiness", JSON_VARIANT_NUMBER, oci_unsupported, 0, JSON_PERMISSIVE },
+ { "disableOOMKiller", JSON_VARIANT_BOOLEAN, oci_unsupported, 0, JSON_PERMISSIVE },
{}
};
@@ -1589,7 +1589,7 @@ static int oci_sysctl(const char *name, JsonVariant *v, JsonDispatchFlags flags,
assert_se(m = json_variant_string(w));
- if (sysctl_key_valid(k))
+ if (!sysctl_key_valid(k))
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
"sysctl key invalid, refusing: %s", k);
@@ -1829,6 +1829,7 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl
{ "names", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(struct syscall_rule, names), JSON_MANDATORY },
{ "action", JSON_VARIANT_STRING, oci_seccomp_action, offsetof(struct syscall_rule, action), JSON_MANDATORY },
{ "args", JSON_VARIANT_ARRAY, oci_seccomp_args, 0, 0 },
+ {}
};
struct syscall_rule rule = {
.action = UINT32_MAX,
@@ -2083,7 +2084,7 @@ static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags f
.timeout = USEC_INFINITY,
};
- r = json_dispatch(e, table, oci_unexpected, flags, userdata);
+ r = json_dispatch(e, table, oci_unexpected, flags, new_item);
if (r < 0) {
free(new_item->path);
strv_free(new_item->args);
@@ -2100,9 +2101,9 @@ static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags f
static int oci_hooks(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
static const JsonDispatch table[] = {
- { "prestart", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 },
- { "poststart", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 },
- { "poststop", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 },
+ { "prestart", JSON_VARIANT_ARRAY, oci_hooks_array, 0, 0 },
+ { "poststart", JSON_VARIANT_ARRAY, oci_hooks_array, 0, 0 },
+ { "poststop", JSON_VARIANT_ARRAY, oci_hooks_array, 0, 0 },
{}
};
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 7500eabd18..161b1c1c70 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -97,27 +97,25 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
return 0;
}
-static void free_oci_hooks(OciHook *h, size_t n) {
- size_t i;
+static void free_oci_hooks(OciHook *hooks, size_t n) {
+ assert(hooks || n == 0);
- assert(h || n == 0);
-
- for (i = 0; i < n; i++) {
- free(h[i].path);
- strv_free(h[i].args);
- strv_free(h[i].env);
+ FOREACH_ARRAY(hook, hooks, n) {
+ free(hook->path);
+ strv_free(hook->args);
+ strv_free(hook->env);
}
- free(h);
+ free(hooks);
}
-void device_node_array_free(DeviceNode *node, size_t n) {
- size_t i;
+void device_node_array_free(DeviceNode *nodes, size_t n) {
+ assert(nodes || n == 0);
- for (i = 0; i < n; i++)
- free(node[i].path);
+ FOREACH_ARRAY(node, nodes, n)
+ free(node->path);
- free(node);
+ free(nodes);
}
Settings* settings_free(Settings *s) {
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 49802d6fdf..5d49e05064 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -4651,6 +4651,7 @@ static int merge_settings(Settings *settings, const char *path) {
device_node_array_free(arg_extra_nodes, arg_n_extra_nodes);
arg_extra_nodes = TAKE_PTR(settings->extra_nodes);
arg_n_extra_nodes = settings->n_extra_nodes;
+ settings->n_extra_nodes = 0;
return 0;
}
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/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();
}
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 4c83eede7a..b554a6827d 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -365,6 +365,7 @@ Link *link_free(Link *link) {
sd_device_unref(link->device);
free(link->kind);
free(link->driver);
+ strv_free(link->altnames);
return mfree(link);
}
@@ -724,7 +725,7 @@ static int link_generate_new_name(Link *link) {
config = link->config;
device = link->device;
- if (link->action == SD_DEVICE_MOVE) {
+ if (link->action != SD_DEVICE_ADD) {
log_link_debug(link, "Skipping to apply Name= and NamePolicy= on '%s' uevent.",
device_action_to_string(link->action));
goto no_rename;
@@ -793,19 +794,22 @@ no_rename:
return 0;
}
-static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
- _cleanup_strv_free_ char **altnames = NULL, **current_altnames = NULL;
+static int link_generate_alternative_names(Link *link) {
+ _cleanup_strv_free_ char **altnames = NULL;
LinkConfig *config;
sd_device *device;
int r;
assert(link);
- assert(link->config);
- assert(link->device);
- assert(rtnl);
+ config = ASSERT_PTR(link->config);
+ device = ASSERT_PTR(link->device);
+ assert(!link->altnames);
- config = link->config;
- device = link->device;
+ if (link->action != SD_DEVICE_ADD) {
+ log_link_debug(link, "Skipping to apply AlternativeNames= and AlternativeNamesPolicy= on '%s' uevent.",
+ device_action_to_string(link->action));
+ return 0;
+ }
if (config->alternative_names) {
altnames = strv_copy(config->alternative_names);
@@ -836,29 +840,14 @@ static int link_apply_alternative_names(Link *link, sd_netlink **rtnl) {
default:
assert_not_reached();
}
- if (!isempty(n)) {
+ if (ifname_valid_full(n, IFNAME_VALID_ALTERNATIVE)) {
r = strv_extend(&altnames, n);
if (r < 0)
return log_oom();
}
}
- strv_remove(altnames, link->ifname);
-
- r = rtnl_get_link_alternative_names(rtnl, link->ifindex, &current_altnames);
- if (r < 0)
- log_link_debug_errno(link, r, "Failed to get alternative names, ignoring: %m");
-
- STRV_FOREACH(p, current_altnames)
- strv_remove(altnames, *p);
-
- strv_uniq(altnames);
- strv_sort(altnames);
- r = rtnl_set_link_alternative_names(rtnl, link->ifindex, altnames);
- if (r < 0)
- log_link_full_errno(link, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
- "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
-
+ link->altnames = TAKE_PTR(altnames);
return 0;
}
@@ -960,7 +949,7 @@ int link_apply_config(LinkConfigContext *ctx, sd_netlink **rtnl, Link *link) {
if (r < 0)
return r;
- r = link_apply_alternative_names(link, rtnl);
+ r = link_generate_alternative_names(link);
if (r < 0)
return r;
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index ed0896e9de..713d41040a 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -27,6 +27,7 @@ typedef struct Link {
int ifindex;
const char *ifname;
const char *new_name;
+ char **altnames;
LinkConfig *config;
sd_device *device;
diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c
index 2b2205513b..11419a3e61 100644
--- a/src/udev/udev-builtin-blkid.c
+++ b/src/udev/udev-builtin-blkid.c
@@ -315,7 +315,8 @@ notloop:
return 0;
}
-static int builtin_blkid(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_blkid(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *devnode, *root_partition = NULL, *data, *name;
_cleanup_(blkid_free_probep) blkid_probe pr = NULL;
_cleanup_free_ char *backing_fname = NULL;
diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c
index 79f91ea2ae..9b12aebb3a 100644
--- a/src/udev/udev-builtin-btrfs.c
+++ b/src/udev/udev-builtin-btrfs.c
@@ -12,7 +12,8 @@
#include "strxcpyx.h"
#include "udev-builtin.h"
-static int builtin_btrfs(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_btrfs(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
struct btrfs_ioctl_vol_args args = {};
_cleanup_close_ int fd = -EBADF;
int r;
diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c
index 8d652e46fe..19e07e734f 100644
--- a/src/udev/udev-builtin-hwdb.c
+++ b/src/udev/udev-builtin-hwdb.c
@@ -118,7 +118,7 @@ next:
return r;
}
-static int builtin_hwdb(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_hwdb(UdevEvent *event, int argc, char *argv[], bool test) {
static const struct option options[] = {
{ "filter", required_argument, NULL, 'f' },
{ "device", required_argument, NULL, 'd' },
@@ -131,6 +131,7 @@ static int builtin_hwdb(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[
const char *subsystem = NULL;
const char *prefix = NULL;
_cleanup_(sd_device_unrefp) sd_device *srcdev = NULL;
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
int r;
if (!hwdb)
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index 540f390530..295e8d2159 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -369,8 +369,8 @@ static bool test_key(sd_device *dev,
return found;
}
-static int builtin_input_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
- sd_device *pdev;
+static int builtin_input_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *pdev, *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
unsigned long bitmask_ev[NBITS(EV_MAX)];
unsigned long bitmask_abs[NBITS(ABS_MAX)];
unsigned long bitmask_key[NBITS(KEY_MAX)];
@@ -380,8 +380,6 @@ static int builtin_input_id(sd_device *dev, sd_netlink **rtnl, int argc, char *a
bool is_pointer;
bool is_key;
- assert(dev);
-
/* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */
for (pdev = dev; pdev; ) {
diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c
index 80cfdee0c1..da67c2be1c 100644
--- a/src/udev/udev-builtin-keyboard.c
+++ b/src/udev/udev-builtin-keyboard.c
@@ -159,7 +159,8 @@ static int set_trackpoint_sensitivity(sd_device *dev, const char *value) {
return 0;
}
-static int builtin_keyboard(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_keyboard(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
unsigned release[1024];
unsigned release_count = 0;
_cleanup_close_ int fd = -EBADF;
diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c
index eade042f35..3ab5c485f8 100644
--- a/src/udev/udev-builtin-kmod.c
+++ b/src/udev/udev-builtin-kmod.c
@@ -22,11 +22,10 @@ _printf_(6,0) static void udev_kmod_log(void *data, int priority, const char *fi
log_internalv(priority, 0, file, line, fn, format, args);
}
-static int builtin_kmod(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_kmod(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
int r;
- assert(dev);
-
if (!ctx)
return 0;
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 5e2b69d6f7..998478ec4e 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -1096,7 +1096,8 @@ static int get_link_info(sd_device *dev, LinkInfo *info) {
return 0;
}
-static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_net_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *prefix;
NetNames names = {};
LinkInfo info = {};
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index 18450536b5..5bc965f6d8 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -12,7 +12,8 @@
static LinkConfigContext *ctx = NULL;
-static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, char **argv, bool test) {
+static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
_cleanup_(link_freep) Link *link = NULL;
_cleanup_free_ char *joined = NULL;
int r;
@@ -20,7 +21,7 @@ static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, c
if (argc > 1)
return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
- r = link_new(ctx, rtnl, dev, &link);
+ r = link_new(ctx, &event->rtnl, dev, &link);
if (r == -ENODEV) {
log_device_debug_errno(dev, r, "Link vanished while getting information, ignoring.");
return 0;
@@ -41,7 +42,7 @@ static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, c
return log_device_error_errno(dev, r, "Failed to get link config: %m");
}
- r = link_apply_config(ctx, rtnl, link);
+ r = link_apply_config(ctx, &event->rtnl, link);
if (r == -ENODEV)
log_device_debug_errno(dev, r, "Link vanished while applying configuration, ignoring.");
else if (r < 0)
@@ -51,6 +52,8 @@ static int builtin_net_setup_link(sd_device *dev, sd_netlink **rtnl, int argc, c
if (link->new_name)
udev_builtin_add_property(dev, test, "ID_NET_NAME", link->new_name);
+ event->altnames = TAKE_PTR(link->altnames);
+
STRV_FOREACH(d, link->config->dropins) {
_cleanup_free_ char *escaped = NULL;
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index ff6682cad9..404196f409 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -589,15 +589,14 @@ static int find_real_nvme_parent(sd_device *dev, sd_device **ret) {
return 0;
}
-static int builtin_path_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_path_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
_cleanup_(sd_device_unrefp) sd_device *dev_other_branch = NULL;
_cleanup_free_ char *path = NULL, *compat_path = NULL;
bool supported_transport = false, supported_parent = false;
const char *subsystem;
int r;
- assert(dev);
-
/* walk up the chain of devices and compose path */
for (sd_device *parent = dev; parent; ) {
const char *subsys, *sysname;
diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c
index 6e73d99375..36c993cbb0 100644
--- a/src/udev/udev-builtin-uaccess.c
+++ b/src/udev/udev-builtin-uaccess.c
@@ -16,7 +16,8 @@
#include "log.h"
#include "udev-builtin.h"
-static int builtin_uaccess(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_uaccess(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
const char *path = NULL, *seat;
bool changed_acl = false;
uid_t uid;
diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c
index 91deb64292..8e83c9c342 100644
--- a/src/udev/udev-builtin-usb_id.c
+++ b/src/udev/udev-builtin-usb_id.c
@@ -224,7 +224,8 @@ static int dev_if_packed_info(sd_device *dev, char *ifs_str, size_t len) {
* 6.) If the device supplies a serial number, this number
* is concatenated with the identification with an underscore '_'.
*/
-static int builtin_usb_id(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test) {
+static int builtin_usb_id(UdevEvent *event, int argc, char *argv[], bool test) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
char vendor_str[64] = "";
char vendor_str_enc[256];
const char *vendor_id;
@@ -250,8 +251,6 @@ static int builtin_usb_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
const char *syspath, *sysname, *devtype, *interface_syspath;
int r;
- assert(dev);
-
r = sd_device_get_syspath(dev, &syspath);
if (r < 0)
return r;
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index 566641e400..a8dd656b00 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -98,11 +98,12 @@ UdevBuiltinCommand udev_builtin_lookup(const char *command) {
return _UDEV_BUILTIN_INVALID;
}
-int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd, const char *command, bool test) {
+int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command, bool test) {
_cleanup_strv_free_ char **argv = NULL;
int r;
- assert(dev);
+ assert(event);
+ assert(event->dev);
assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX);
assert(command);
@@ -115,7 +116,7 @@ int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd,
/* we need '0' here to reset the internal state */
optind = 0;
- return builtins[cmd]->cmd(dev, rtnl, strv_length(argv), argv, test);
+ return builtins[cmd]->cmd(event, strv_length(argv), argv, test);
}
int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val) {
diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h
index 490b2dbe96..b2cf81ad31 100644
--- a/src/udev/udev-builtin.h
+++ b/src/udev/udev-builtin.h
@@ -7,6 +7,7 @@
#include "sd-netlink.h"
#include "macro.h"
+#include "udev-event.h"
typedef enum UdevBuiltinCommand {
#if HAVE_BLKID
@@ -32,7 +33,7 @@ typedef enum UdevBuiltinCommand {
typedef struct UdevBuiltin {
const char *name;
- int (*cmd)(sd_device *dev, sd_netlink **rtnl, int argc, char *argv[], bool test);
+ int (*cmd)(UdevEvent *event, int argc, char *argv[], bool test);
const char *help;
int (*init)(void);
void (*exit)(void);
@@ -76,7 +77,7 @@ void udev_builtin_exit(void);
UdevBuiltinCommand udev_builtin_lookup(const char *command);
const char *udev_builtin_name(UdevBuiltinCommand cmd);
bool udev_builtin_run_once(UdevBuiltinCommand cmd);
-int udev_builtin_run(sd_device *dev, sd_netlink **rtnl, UdevBuiltinCommand cmd, const char *command, bool test);
+int udev_builtin_run(UdevEvent *event, UdevBuiltinCommand cmd, const char *command, bool test);
void udev_builtin_list(void);
bool udev_builtin_should_reload(void);
int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const char *val);
diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
index a8d7db40b4..b3cdb32a63 100644
--- a/src/udev/udev-event.c
+++ b/src/udev/udev-event.c
@@ -87,6 +87,7 @@ UdevEvent *udev_event_free(UdevEvent *event) {
ordered_hashmap_free_free_free(event->seclabel_list);
free(event->program_result);
free(event->name);
+ strv_free(event->altnames);
return mfree(event);
}
@@ -914,9 +915,6 @@ static int rename_netif(UdevEvent *event) {
dev = ASSERT_PTR(event->dev);
- if (!device_for_action(dev, SD_DEVICE_ADD))
- return 0; /* Rename the interface only when it is added. */
-
r = sd_device_get_ifindex(dev, &ifindex);
if (r == -ENOENT)
return 0; /* Device is not a network interface. */
@@ -976,7 +974,7 @@ static int rename_netif(UdevEvent *event) {
goto revert;
}
- r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
+ r = rtnl_set_link_name(&event->rtnl, ifindex, event->name, event->altnames);
if (r < 0) {
if (r == -EBUSY) {
log_device_info(dev, "Network interface '%s' is already up, cannot rename to '%s'.",
@@ -1007,6 +1005,35 @@ revert:
return r;
}
+static int assign_altnames(UdevEvent *event) {
+ sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
+ int ifindex, r;
+ const char *s;
+
+ if (strv_isempty(event->altnames))
+ return 0;
+
+ r = sd_device_get_ifindex(dev, &ifindex);
+ if (r == -ENOENT)
+ return 0; /* Device is not a network interface. */
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to get ifindex: %m");
+
+ r = sd_device_get_sysname(dev, &s);
+ if (r < 0)
+ return log_device_warning_errno(dev, r, "Failed to get sysname: %m");
+
+ /* Filter out the current interface name. */
+ strv_remove(event->altnames, s);
+
+ r = rtnl_append_link_alternative_names(&event->rtnl, ifindex, event->altnames);
+ if (r < 0)
+ log_device_full_errno(dev, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, r,
+ "Could not set AlternativeName= or apply AlternativeNamesPolicy=, ignoring: %m");
+
+ return 0;
+}
+
static int update_devnode(UdevEvent *event) {
sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
int r;
@@ -1148,9 +1175,13 @@ int udev_event_execute_rules(
DEVICE_TRACE_POINT(rules_finished, dev);
- r = rename_netif(event);
- if (r < 0)
- return r;
+ if (action == SD_DEVICE_ADD) {
+ r = rename_netif(event);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ (void) assign_altnames(event);
+ }
r = update_devnode(event);
if (r < 0)
@@ -1185,7 +1216,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s
if (builtin_cmd != _UDEV_BUILTIN_INVALID) {
log_device_debug(event->dev, "Running built-in command \"%s\"", command);
- r = udev_builtin_run(event->dev, &event->rtnl, builtin_cmd, command, false);
+ r = udev_builtin_run(event, builtin_cmd, command, false);
if (r < 0)
log_device_debug_errno(event->dev, r, "Failed to run built-in command \"%s\", ignoring: %m", command);
} else {
diff --git a/src/udev/udev-event.h b/src/udev/udev-event.h
index c54c7891b6..b99559ca2e 100644
--- a/src/udev/udev-event.h
+++ b/src/udev/udev-event.h
@@ -22,6 +22,7 @@ typedef struct UdevEvent {
sd_device *dev_parent;
sd_device *dev_db_clone;
char *name;
+ char **altnames;
char *program_result;
mode_t mode;
uid_t uid;
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index d6e701f3cc..fc1ef34964 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -2193,7 +2193,7 @@ static int udev_rule_apply_token_to_event(
log_event_debug(dev, token, "Importing properties from results of builtin command '%s'", buf);
- r = udev_builtin_run(dev, &event->rtnl, cmd, buf, false);
+ r = udev_builtin_run(event, cmd, buf, false);
if (r < 0) {
/* remember failure */
log_event_debug_errno(dev, token, r, "Failed to run builtin '%s': %m", buf);
diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c
index 81b633611e..5d1fafbd03 100644
--- a/src/udev/udevadm-test-builtin.c
+++ b/src/udev/udevadm-test-builtin.c
@@ -72,7 +72,7 @@ static int parse_argv(int argc, char *argv[]) {
}
int builtin_main(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(udev_event_freep) UdevEvent *event = NULL;
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
UdevBuiltinCommand cmd;
int r;
@@ -87,8 +87,7 @@ int builtin_main(int argc, char *argv[], void *userdata) {
cmd = udev_builtin_lookup(arg_command);
if (cmd < 0) {
- log_error("Unknown command '%s'", arg_command);
- r = -EINVAL;
+ r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown command '%s'", arg_command);
goto finish;
}
@@ -98,7 +97,13 @@ int builtin_main(int argc, char *argv[], void *userdata) {
goto finish;
}
- r = udev_builtin_run(dev, &rtnl, cmd, arg_command, true);
+ event = udev_event_new(dev, 0, NULL, LOG_DEBUG);
+ if (!event) {
+ r = log_oom();
+ goto finish;
+ }
+
+ r = udev_builtin_run(event, cmd, arg_command, true);
if (r < 0)
log_debug_errno(r, "Builtin command '%s' fails: %m", arg_command);
diff --git a/test/fuzz/fuzz-nspawn-oci/basic.json b/test/fuzz/fuzz-nspawn-oci/basic.json
index f42739e03a..24bacf39c1 100644
--- a/test/fuzz/fuzz-nspawn-oci/basic.json
+++ b/test/fuzz/fuzz-nspawn-oci/basic.json
@@ -1,6 +1,8 @@
{
"ociVersion": "1.0.0",
+ "hostname" : "foo",
+
"root": {
"path": "rootfs",
"readonly": true
@@ -33,11 +35,42 @@
"cwd": "/tmp/src",
- "rlimits": [
+ "noNewPrivileges" : true,
+ "oomScoreAdj" : 20,
+ "capabilities" : {
+ "bounding" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE"
+ ],
+ "permitted" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE"
+ ],
+ "inheritable" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE"
+ ],
+ "effective" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL"
+ ],
+ "ambient" : [
+ "CAP_NET_BIND_SERVICE"
+ ]
+ },
+ "rlimits" : [
{
- "type": "RLIMIT_NOFILE",
- "hard": 1020,
- "soft": 1020
+ "type" : "RLIMIT_NOFILE",
+ "soft" : 1024,
+ "hard" : 1024
+ },
+ {
+ "type" : "RLIMIT_RTPRIO",
+ "soft" : 5,
+ "hard" : 10
}
]
},
@@ -110,32 +143,206 @@
}
],
- "hooks": {},
-
- "linux": {
- "resources": {
- "devices": [
+ "linux" : {
+ "namespaces" : [
+ {
+ "type" : "mount"
+ },
+ {
+ "type" : "network",
+ "path" : "$NETNS"
+ },
+ {
+ "type" : "pid"
+ },
+ {
+ "type" : "uts"
+ }
+ ],
+ "uidMappings" : [
+ {
+ "containerID" : 0,
+ "hostID" : 1000,
+ "size" : 100
+ }
+ ],
+ "gidMappings" : [
+ {
+ "containerID" : 0,
+ "hostID" : 1000,
+ "size" : 100
+ }
+ ],
+ "devices" : [
+ {
+ "type" : "c",
+ "path" : "/dev/zero",
+ "major" : 1,
+ "minor" : 5,
+ "fileMode" : 444
+ },
+ {
+ "type" : "b",
+ "path" : "$DEV",
+ "major" : 4,
+ "minor" : 2,
+ "fileMode" : 666,
+ "uid" : 0,
+ "gid" : 0
+ }
+ ],
+ "resources" : {
+ "devices" : [
+ {
+ "allow" : false,
+ "access" : "m"
+ },
+ {
+ "allow" : true,
+ "type" : "b",
+ "major" : 4,
+ "minor" : 2,
+ "access" : "rwm"
+ }
+ ],
+ "memory" : {
+ "limit" : 134217728,
+ "reservation" : 33554432,
+ "swap" : 268435456
+ },
+ "cpu" : {
+ "shares" : 1024,
+ "quota" : 1000000,
+ "period" : 500000,
+ "cpus" : "0-7"
+ },
+ "blockIO" : {
+ "weight" : 10,
+ "weightDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "weight" : 500
+ }
+ ],
+ "throttleReadBpsDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ],
+ "throttleWriteBpsDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ],
+ "throttleReadIOPSDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ],
+ "throttleWriteIOPSDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ]
+ },
+ "pids" : {
+ "limit" : 1024
+ }
+ },
+ "sysctl" : {
+ "kernel.domainname" : "foo.bar",
+ "vm.swappiness" : "60"
+ },
+ "seccomp" : {
+ "defaultAction" : "SCMP_ACT_ALLOW",
+ "architectures" : [
+ "SCMP_ARCH_ARM",
+ "SCMP_ARCH_X86_64"
+ ],
+ "syscalls" : [
{
- "allow": false,
- "access": "rwm"
+ "names" : [
+ "lchown",
+ "chmod"
+ ],
+ "action" : "SCMP_ACT_ERRNO",
+ "args" : [
+ {
+ "index" : 0,
+ "value" : 1,
+ "op" : "SCMP_CMP_NE"
+ },
+ {
+ "index" : 1,
+ "value" : 2,
+ "valueTwo" : 3,
+ "op" : "SCMP_CMP_MASKED_EQ"
+ }
+ ]
}
]
},
- "namespaces": [
+ "rootfsPropagation" : "shared",
+ "maskedPaths" : [
+ "/proc/kcore",
+ "/root/nonexistent"
+ ],
+ "readonlyPaths" : [
+ "/proc/sys",
+ "/opt/readonly"
+ ]
+ },
+ "hooks" : {
+ "prestart" : [
{
- "type": "pid"
+ "path" : "/bin/sh",
+ "args" : [
+ "-xec",
+ "echo $PRESTART_FOO >/prestart"
+ ],
+ "env" : [
+ "PRESTART_FOO=prestart_bar",
+ "ALSO_FOO=also_bar"
+ ],
+ "timeout" : 666
},
{
- "type": "ipc"
- },
+ "path" : "/bin/touch",
+ "args" : [
+ "/tmp/also-prestart"
+ ]
+ }
+ ],
+ "poststart" : [
{
- "type": "mount"
+ "path" : "/bin/sh",
+ "args" : [
+ "touch",
+ "/poststart"
+ ]
+ }
+ ],
+ "poststop" : [
+ {
+ "path" : "/bin/sh",
+ "args" : [
+ "touch",
+ "/poststop"
+ ]
}
]
},
-
- "annotations": {
- "com.example.key1": "value1",
- "com.example.key2": "value2"
+ "annotations" : {
+ "hello.world" : "1",
+ "foo" : "bar"
}
}
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
index 8450d024e6..818fb28dbf 100644
--- a/test/fuzz/fuzz-unit-file/directives-all.service
+++ b/test/fuzz/fuzz-unit-file/directives-all.service
@@ -269,6 +269,8 @@ Type=
USBFunctionDescriptors=
USBFunctionStrings=
Unit=
+UpheldBy=
+Upholds=
User=
WakeSystem=
WantedBy=
diff --git a/test/testsuite-23.units/testsuite-23-upheldby-install.service b/test/testsuite-23.units/testsuite-23-upheldby-install.service
new file mode 100644
index 0000000000..a4562077db
--- /dev/null
+++ b/test/testsuite-23.units/testsuite-23-upheldby-install.service
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+[Unit]
+Description=Unit that sets UpheldBy= through [Install]
+
+[Service]
+ExecStart=/bin/sleep infinity
+
+[Install]
+UpheldBy=testsuite-23-retry-uphold.service
diff --git a/test/units/testsuite-13.nspawn-oci.sh b/test/units/testsuite-13.nspawn-oci.sh
new file mode 100755
index 0000000000..cbfdb18290
--- /dev/null
+++ b/test/units/testsuite-13.nspawn-oci.sh
@@ -0,0 +1,383 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# shellcheck disable=SC2016
+set -eux
+set -o pipefail
+
+export SYSTEMD_LOG_LEVEL=debug
+export SYSTEMD_LOG_TARGET=journal
+CREATE_BB_CONTAINER="/usr/lib/systemd/tests/testdata/create-busybox-container"
+
+# shellcheck disable=SC2317
+at_exit() {
+ set +e
+
+ mountpoint -q /var/lib/machines && umount /var/lib/machines
+ [[ -n "${DEV:-}" ]] && rm -f "$DEV"
+ [[ -n "${NETNS:-}" ]] && umount "$NETNS" && rm -f "$NETNS"
+ [[ -n "${TMPDIR:-}" ]] && rm -fr "$TMPDIR"
+}
+
+trap at_exit EXIT
+
+# Mount tmpfs over /var/lib/machines to not pollute the image
+mkdir -p /var/lib/machines
+mount -t tmpfs tmpfs /var/lib/machines
+
+# Setup a couple of dirs/devices for the OCI containers
+DEV="$(mktemp -u /dev/oci-dev-XXX)"
+mknod -m 666 "$DEV" b 42 42
+NETNS="$(mktemp /var/tmp/netns.XXX)"
+mount --bind /proc/self/ns/net "$NETNS"
+TMPDIR="$(mktemp -d)"
+touch "$TMPDIR/hello"
+OCI="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)"
+"$CREATE_BB_CONTAINER" "$OCI/rootfs"
+mkdir -p "$OCI/rootfs/opt/var"
+mkdir -p "$OCI/rootfs/opt/readonly"
+
+# Let's start with a simple config
+cat >"$OCI/config.json" <<EOF
+{
+ "ociVersion" : "1.0.0",
+ "root" : {
+ "path" : "rootfs"
+ },
+ "mounts" : [
+ {
+ "destination" : "/root",
+ "type" : "tmpfs",
+ "source" : "tmpfs"
+ }
+ ]
+}
+EOF
+systemd-nspawn --oci-bundle="$OCI" sh -xec 'mountpoint /root'
+
+# And now for something a bit more involved
+# Notes:
+# - the hooks are parsed & processed, but never executed
+# - set sysctl's are parsed but never used?
+# - same goes for arg_sysctl in nspawn.c
+cat >"$OCI/config.json" <<EOF
+{
+ "ociVersion" : "1.0.0",
+ "hostname" : "my-oci-container",
+ "root" : {
+ "path" : "rootfs",
+ "readonly" : false
+ },
+ "mounts" : [
+ {
+ "destination" : "/root",
+ "type" : "tmpfs",
+ "source" : "tmpfs"
+ },
+ {
+ "destination" : "/var",
+ "type" : "none",
+ "source" : "$TMPDIR",
+ "options" : ["rbind", "rw"]
+ }
+ ],
+ "process" : {
+ "terminal" : false,
+ "consoleSize" : {
+ "height" : 25,
+ "width" : 80
+ },
+ "user" : {
+ "uid" : 0,
+ "gid" : 0,
+ "additionalGids" : [5, 6]
+ },
+ "env" : [
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "FOO=bar"
+ ],
+ "cwd" : "/root",
+ "args" : [
+ "sh",
+ "-xe",
+ "/entrypoint.sh"
+ ],
+ "noNewPrivileges" : true,
+ "oomScoreAdj" : 20,
+ "capabilities" : {
+ "bounding" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE"
+ ],
+ "permitted" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE"
+ ],
+ "inheritable" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL",
+ "CAP_NET_BIND_SERVICE"
+ ],
+ "effective" : [
+ "CAP_AUDIT_WRITE",
+ "CAP_KILL"
+ ],
+ "ambient" : [
+ "CAP_NET_BIND_SERVICE"
+ ]
+ },
+ "rlimits" : [
+ {
+ "type" : "RLIMIT_NOFILE",
+ "soft" : 1024,
+ "hard" : 1024
+ },
+ {
+ "type" : "RLIMIT_RTPRIO",
+ "soft" : 5,
+ "hard" : 10
+ }
+ ]
+ },
+ "linux" : {
+ "namespaces" : [
+ {
+ "type" : "mount"
+ },
+ {
+ "type" : "network",
+ "path" : "$NETNS"
+ },
+ {
+ "type" : "pid"
+ },
+ {
+ "type" : "uts"
+ }
+ ],
+ "uidMappings" : [
+ {
+ "containerID" : 0,
+ "hostID" : 1000,
+ "size" : 100
+ }
+ ],
+ "gidMappings" : [
+ {
+ "containerID" : 0,
+ "hostID" : 1000,
+ "size" : 100
+ }
+ ],
+ "devices" : [
+ {
+ "type" : "c",
+ "path" : "/dev/zero",
+ "major" : 1,
+ "minor" : 5,
+ "fileMode" : 444
+ },
+ {
+ "type" : "b",
+ "path" : "$DEV",
+ "major" : 4,
+ "minor" : 2,
+ "fileMode" : 666,
+ "uid" : 0,
+ "gid" : 0
+ }
+ ],
+ "resources" : {
+ "devices" : [
+ {
+ "allow" : false,
+ "access" : "m"
+ },
+ {
+ "allow" : true,
+ "type" : "b",
+ "major" : 4,
+ "minor" : 2,
+ "access" : "rwm"
+ }
+ ],
+ "memory" : {
+ "limit" : 134217728,
+ "reservation" : 33554432,
+ "swap" : 268435456
+ },
+ "cpu" : {
+ "shares" : 1024,
+ "quota" : 1000000,
+ "period" : 500000,
+ "cpus" : "0-7"
+ },
+ "blockIO" : {
+ "weight" : 10,
+ "weightDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "weight" : 500
+ }
+ ],
+ "throttleReadBpsDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ],
+ "throttleWriteBpsDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ],
+ "throttleReadIOPSDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ],
+ "throttleWriteIOPSDevice" : [
+ {
+ "major" : 4,
+ "minor" : 2,
+ "rate" : 500
+ }
+ ]
+ },
+ "pids" : {
+ "limit" : 1024
+ }
+ },
+ "sysctl" : {
+ "kernel.domainname" : "foo.bar",
+ "vm.swappiness" : "60"
+ },
+ "seccomp" : {
+ "defaultAction" : "SCMP_ACT_ALLOW",
+ "architectures" : [
+ "SCMP_ARCH_ARM",
+ "SCMP_ARCH_X86_64"
+ ],
+ "syscalls" : [
+ {
+ "names" : [
+ "lchown",
+ "chmod"
+ ],
+ "action" : "SCMP_ACT_ERRNO",
+ "args" : [
+ {
+ "index" : 0,
+ "value" : 1,
+ "op" : "SCMP_CMP_NE"
+ },
+ {
+ "index" : 1,
+ "value" : 2,
+ "valueTwo" : 3,
+ "op" : "SCMP_CMP_MASKED_EQ"
+ }
+ ]
+ }
+ ]
+ },
+ "rootfsPropagation" : "shared",
+ "maskedPaths" : [
+ "/proc/kcore",
+ "/root/nonexistent"
+ ],
+ "readonlyPaths" : [
+ "/proc/sys",
+ "/opt/readonly"
+ ]
+ },
+ "hooks" : {
+ "prestart" : [
+ {
+ "path" : "/bin/sh",
+ "args" : [
+ "-xec",
+ "echo \$PRESTART_FOO >/prestart"
+ ],
+ "env" : [
+ "PRESTART_FOO=prestart_bar",
+ "ALSO_FOO=also_bar"
+ ],
+ "timeout" : 666
+ },
+ {
+ "path" : "/bin/touch",
+ "args" : [
+ "/tmp/also-prestart"
+ ]
+ }
+ ],
+ "poststart" : [
+ {
+ "path" : "/bin/sh",
+ "args" : [
+ "touch",
+ "/poststart"
+ ]
+ }
+ ],
+ "poststop" : [
+ {
+ "path" : "/bin/sh",
+ "args" : [
+ "touch",
+ "/poststop"
+ ]
+ }
+ ]
+ },
+ "annotations" : {
+ "hello.world" : "1",
+ "foo" : "bar"
+ }
+}
+EOF
+# Create a simple "entrypoint" script that validates that the container
+# is created correctly according to the OCI config
+cat >"$OCI/rootfs/entrypoint.sh" <<EOF
+#!/bin/sh -e
+
+# Mounts
+mountpoint /root
+mountpoint /var
+test -e /var/hello
+
+# Process
+[[ "\$PWD" == /root ]]
+[[ "\$FOO" == bar ]]
+
+# Process - rlimits
+[[ "\$(ulimit -S -n)" -eq 1024 ]]
+[[ "\$(ulimit -H -n)" -eq 1024 ]]
+[[ "\$(ulimit -S -r)" -eq 5 ]]
+[[ "\$(ulimit -H -r)" -eq 10 ]]
+[[ "\$(hostname)" == my-oci-container ]]
+
+# Linux - devices
+test -c /dev/zero
+test -b "$DEV"
+[[ "\$(stat -c '%t:%T' "$DEV")" == 4:2 ]]
+
+# Linux - maskedPaths
+test -e /proc/kcore
+cat /proc/kcore && exit 1
+test ! -e /root/nonexistent
+
+# Linux - readonlyPaths
+touch /opt/readonly/foo && exit 1
+
+exit 0
+EOF
+systemd-nspawn --oci-bundle="$OCI"
diff --git a/test/units/testsuite-13.nspawn.sh b/test/units/testsuite-13.nspawn.sh
index 76ba143751..8f8daf05cc 100755
--- a/test/units/testsuite-13.nspawn.sh
+++ b/test/units/testsuite-13.nspawn.sh
@@ -46,7 +46,7 @@ mkdir -p /var/lib/machines
mount -t tmpfs tmpfs /var/lib/machines
testcase_sanity_check() {
- local template root image oci uuid tmpdir
+ local template root image uuid tmpdir
tmpdir="$(mktemp -d)"
template="$(mktemp -d /tmp/nspawn-template.XXX)"
@@ -59,24 +59,6 @@ testcase_sanity_check() {
mount -o loop "$image" /mnt
cp -r "$template"/* /mnt/
umount /mnt
- # Create a simple OCI bundle
- oci="$(mktemp -d /var/lib/machines/testsuite-13.oci-bundle.XXX)"
- "$CREATE_BB_CONTAINER" "$oci/rootfs"
- cat >"$oci/config.json" <<EOF
-{
- "ociVersion" : "1.0.0",
- "root" : {
- "path" : "rootfs"
- },
- "mounts" : [
- {
- "destination" : "/root",
- "type" : "tmpfs",
- "source" : "tmpfs"
- }
- ]
-}
-EOF
systemd-nspawn --help --no-pager
systemd-nspawn --version
@@ -101,7 +83,6 @@ EOF
sh -xec 'touch /nope')
test ! -e "$root/nope"
systemd-nspawn --image="$image" sh -xec 'echo hello'
- systemd-nspawn --oci-bundle="$oci" sh -xec 'mountpoint /root'
# --volatile=
touch "$root/usr/has-usr"
diff --git a/test/units/testsuite-17.12.sh b/test/units/testsuite-17.12.sh
new file mode 100755
index 0000000000..df74d356ee
--- /dev/null
+++ b/test/units/testsuite-17.12.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -ex
+set -o pipefail
+
+# shellcheck source=test/units/assert.sh
+. "$(dirname "$0")"/assert.sh
+
+create_link_file() {
+ name=${1?}
+
+ mkdir -p /run/systemd/network/
+ cat >/run/systemd/network/10-test.link <<EOF
+[Match]
+Kind=dummy
+MACAddress=00:50:56:c0:00:18
+
+[Link]
+Name=$name
+AlternativeName=test1 test2 test3 test4
+EOF
+ udevadm control --reload
+}
+
+udevadm control --log-level=debug
+
+create_link_file test1
+ip link add address 00:50:56:c0:00:18 type dummy
+udevadm wait --settle --timeout=30 /sys/class/net/test1
+output=$(ip link show dev test1)
+if ! [[ "$output" =~ altname ]]; then
+ echo "alternative name for network interface not supported, skipping test."
+ exit 0
+fi
+assert_not_in "altname test1" "$output"
+assert_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+
+# By triggering add event, Name= and AlternativeNames= are re-applied
+create_link_file test2
+udevadm trigger --action add --settle /sys/class/net/test1
+udevadm wait --settle --timeout=30 /sys/class/net/test2
+output=$(ip link show dev test2)
+assert_in "altname test1" "$output"
+assert_not_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+
+# Name= and AlternativeNames= are not applied on move event
+create_link_file test3
+udevadm trigger --action move --settle /sys/class/net/test2
+udevadm wait --settle --timeout=30 /sys/class/net/test2
+output=$(ip link show dev test2)
+assert_in "altname test1" "$output"
+assert_not_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+
+# Test move event triggered by manual renaming
+ip link set dev test2 name hoge
+udevadm wait --settle --timeout=30 /sys/class/net/hoge
+output=$(ip link show dev hoge)
+assert_in "altname test1" "$output"
+assert_not_in "altname test2" "$output"
+assert_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+assert_not_in "altname hoge" "$output"
+
+# Re-test add event
+udevadm trigger --action add --settle /sys/class/net/hoge
+udevadm wait --settle --timeout=30 /sys/class/net/test3
+output=$(ip link show dev test3)
+assert_in "altname test1" "$output"
+assert_in "altname test2" "$output"
+assert_not_in "altname test3" "$output"
+assert_in "altname test4" "$output"
+assert_not_in "altname hoge" "$output"
+
+# cleanup
+ip link del dev test3
+
+rm -f /run/systemd/network/10-test.link
+udevadm control --reload --log-level=info
+
+exit 0
diff --git a/test/units/testsuite-23.Upholds.sh b/test/units/testsuite-23.Upholds.sh
index 21db258e1d..bce4d7205b 100755
--- a/test/units/testsuite-23.Upholds.sh
+++ b/test/units/testsuite-23.Upholds.sh
@@ -30,6 +30,8 @@ done
systemctl stop testsuite-23-uphold.service
+systemctl enable testsuite-23-upheldby-install.service
+
# Idea is this:
# 1. we start testsuite-23-retry-uphold.service
# 2. which through Uphold= starts testsuite-23-retry-upheld.service
@@ -42,12 +44,13 @@ systemctl stop testsuite-23-uphold.service
rm -f /tmp/testsuite-23-retry-fail
systemctl start testsuite-23-retry-uphold.service
+systemctl is-active testsuite-23-upheldby-install.service
while ! systemctl is-failed testsuite-23-retry-fail.service ; do
sleep .5
done
-systemctl is-active testsuite-23-retry-upheld.service && { echo 'unexpected success'; exit 1; }
+(! systemctl is-active testsuite-23-retry-upheld.service)
touch /tmp/testsuite-23-retry-fail