diff options
31 files changed, 476 insertions, 41 deletions
diff --git a/Makefile.am b/Makefile.am index 7dd021b56a..bf853c8f90 100644 --- a/Makefile.am +++ b/Makefile.am @@ -574,7 +574,8 @@ dist_userunit_DATA = \ units/user/basic.target \ units/user/default.target \ units/user/exit.target \ - units/user/graphical-session.target + units/user/graphical-session.target \ + units/user/graphical-session-pre.target nodist_userunit_DATA = \ units/user/systemd-exit.service @@ -1628,6 +1629,9 @@ EXTRA_DIST += \ test/test-execute/exec-personality-x86-64.service \ test/test-execute/exec-personality-x86.service \ test/test-execute/exec-personality-s390.service \ + test/test-execute/exec-personality-ppc64.service \ + test/test-execute/exec-personality-ppc64le.service \ + test/test-execute/exec-personality-aarch64.service \ test/test-execute/exec-privatedevices-no.service \ test/test-execute/exec-privatedevices-yes.service \ test/test-execute/exec-privatetmp-no.service \ diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb index a5b39dc41e..b68c01066e 100644 --- a/hwdb/70-mouse.hwdb +++ b/hwdb/70-mouse.hwdb @@ -44,10 +44,18 @@ # udevadm info /dev/input/eventXX. # # Allowed properties are: +# ID_INPUT_TRACKBALL # MOUSE_DPI # MOUSE_WHEEL_CLICK_ANGLE # ######################################### +# ID_INPUT_TRACKBALL # +######################################### +# +# Specified *in additition* to ID_INPUT_MOUSE if the device is a trackball. +# Removing ID_INPUT_MOUSE will break backwards compatibility. +# +######################################### # MOUSE_DPI # ######################################### # @@ -102,6 +110,14 @@ # For mice with switchable resolution, sort by the starred entry. ########################################## +# Generic +########################################## +mouse:*:name:*Trackball*: +mouse:*:name:*trackball*: +mouse:*:name:*TrackBall*: + ID_INPUT_TRACKBALL=1 + +########################################## # Apple ########################################## @@ -231,6 +247,7 @@ mouse:usb:v04b3p310c:name:USB Optical Mouse: # Logitech M570 trackball mouse:usb:v046dp1028:name:Logitech M570: MOUSE_DPI=540@167 + ID_INPUT_TRACKBALL=1 # Logitech USB-PS/2 M-BZ96C mouse:usb:v046dpc045:name:Logitech USB-PS/2 Optical Mouse: diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb index ec166ead40..ff52f11e45 100644 --- a/hwdb/70-pointingstick.hwdb +++ b/hwdb/70-pointingstick.hwdb @@ -95,14 +95,12 @@ evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:pvr* evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX230:* # Lenovo Thinkpad X230 tablet evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX230Tablet:* -# Lenovo Thinkpad X240 -evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX240:* -# Lenovo Thinkpad T440s -evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT440s:* -# Lenovo Thinkpad T540p -evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT540p:* -# Lenovo Thinkpad T550 / W550s -evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadT550:* +# Lenovo Thinkpad *40 series +evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??40?:* +# Lenovo Thinkpad *50 series +evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??50?:* +# Lenovo Thinkpad *60 series +evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??60?:* # Lenovo Thinkpad X1 Carbon 3rd gen evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd:* # Lenovo Thinkpad X1 Carbon 4th gen diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml index 2b7f4e69ab..61a5f8937f 100644 --- a/man/systemd-detect-virt.xml +++ b/man/systemd-detect-virt.xml @@ -88,7 +88,7 @@ </thead> <tbody> <row> - <entry valign="top" morerows="9">VM</entry> + <entry valign="top" morerows="10">VM</entry> <entry><varname>qemu</varname></entry> <entry>QEMU software virtualization</entry> </row> @@ -138,6 +138,11 @@ <entry>Parallels Desktop, Parallels Server</entry> </row> + <row> + <entry><varname>bhyve</varname></entry> + <entry>bhyve, FreeBSD hypervisor</entry> + </row> + <row> <entry valign="top" morerows="5">Container</entry> <entry><varname>openvz</varname></entry> diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index bf44a68345..0e98ca78b8 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -99,9 +99,10 @@ <refsect1> <title>Unified and Legacy Control Group Hierarchies</title> - <para>The unified control group hierarchy is the new version of kernel control group interface. Depending on the - resource type, there are differences in resource control capabilities. Also, because of interface changes, some - resource types have a separate set of options on the unified hierarchy.</para> + <para>The unified control group hierarchy is the new version of kernel control group interface, see <ulink + url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>. Depending on the resource type, + there are differences in resource control capabilities. Also, because of interface changes, some resource types + have separate set of options on the unified hierarchy.</para> <para> <variablelist> @@ -126,6 +127,13 @@ settings of a unit for a given resource type are for the other hierarchy type, the settings are translated and applied. If there are any valid settings for the hierarchy in use, all translations are disabled for the resource type. Mixing the two types of settings on a unit can lead to confusing results.</para> + + <para>Legacy control group hierarchy (see <ulink + url="https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt">cgroups.txt</ulink>), also called cgroup-v1, + doesn't allow safe delegation of controllers to unprivileged processes. If the system uses the legacy control group + hierarchy, resource control is disabled for systemd user instance, see + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>. + </para> </refsect1> <refsect1> diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 5bf54d8ef3..26e5d3ce7b 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -443,6 +443,14 @@ </varlistentry> <varlistentry> + <term><varname>MaxConnectionsPerSource=</varname></term> + <listitem><para>The maximum number of connections for a service per source IP address. + This is is very similar to the <varname>MaxConnections=</varname> directive + above. Disabled by default.</para> + </listitem> + </varlistentry> + + <varlistentry> <term><varname>KeepAlive=</varname></term> <listitem><para>Takes a boolean argument. If true, the TCP/IP stack will send a keep alive message after 2h (depending on diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 18142598cb..d977298cd8 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -927,6 +927,19 @@ PartOf=graphical-session.target </programlisting> </example> </refsect2> + + <refsect2> + <title>graphical-session-pre.target</title> + + <para>This target contains services which set up the environment or + global configuration of a graphical session, such as SSH/GPG agents + (which need to export an environment variable into all desktop processes) + or migration of obsolete d-conf keys after an OS upgrade (which needs to + happen before starting any process that might use them). This target must + be started before starting a graphical session + like <filename>gnome-session.target</filename>.</para> + </refsect2> + </refsect1> <refsect1> diff --git a/src/basic/virt.c b/src/basic/virt.c index dace1f4328..10a2043746 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -49,6 +49,8 @@ static int detect_vm_cpuid(void) { { "VMwareVMware", VIRTUALIZATION_VMWARE }, /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ { "Microsoft Hv", VIRTUALIZATION_MICROSOFT }, + /* https://wiki.freebsd.org/bhyve */ + { "bhyve bhyve ", VIRTUALIZATION_BHYVE }, }; uint32_t eax, ecx; @@ -178,6 +180,8 @@ static int detect_vm_dmi(void) { { "Xen", VIRTUALIZATION_XEN }, { "Bochs", VIRTUALIZATION_BOCHS }, { "Parallels", VIRTUALIZATION_PARALLELS }, + /* https://wiki.freebsd.org/bhyve */ + { "BHYVE", VIRTUALIZATION_BHYVE }, }; unsigned i; int r; @@ -502,6 +506,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { [VIRTUALIZATION_MICROSOFT] = "microsoft", [VIRTUALIZATION_ZVM] = "zvm", [VIRTUALIZATION_PARALLELS] = "parallels", + [VIRTUALIZATION_BHYVE] = "bhyve", [VIRTUALIZATION_VM_OTHER] = "vm-other", [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn", diff --git a/src/basic/virt.h b/src/basic/virt.h index a538f07f6b..bc5b3ae94d 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -37,6 +37,7 @@ enum { VIRTUALIZATION_MICROSOFT, VIRTUALIZATION_ZVM, VIRTUALIZATION_PARALLELS, + VIRTUALIZATION_BHYVE, VIRTUALIZATION_VM_OTHER, VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER, diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 961340608d..9a071a1355 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -137,6 +137,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Symlinks", "as", NULL, offsetof(Socket, symlinks), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MaxConnectionsPerSource", "u", bus_property_get_unsigned, offsetof(Socket, max_connections_per_source), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ReusePort", "b", bus_property_get_bool, offsetof(Socket, reuse_port), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index c9cdbe8ba7..396f847213 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -293,6 +293,7 @@ Socket.DirectoryMode, config_parse_mode, 0, Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable) Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) +Socket.MaxConnectionsPerSource, config_parse_unsigned, 0, offsetof(Socket, max_connections_per_source) Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) Socket.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Socket, keep_alive_time) Socket.KeepAliveIntervalSec, config_parse_sec, 0, offsetof(Socket, keep_alive_interval) diff --git a/src/core/main.c b/src/core/main.c index f2adca7d2b..c46d886653 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -92,8 +92,7 @@ static enum { ACTION_HELP, ACTION_VERSION, ACTION_TEST, - ACTION_DUMP_CONFIGURATION_ITEMS, - ACTION_DONE + ACTION_DUMP_CONFIGURATION_ITEMS } arg_action = ACTION_RUN; static char *arg_default_unit = NULL; static bool arg_system = false; @@ -1415,12 +1414,12 @@ int main(int argc, char *argv[]) { if (mac_selinux_setup(&loaded_policy) < 0) { error_message = "Failed to load SELinux policy"; goto finish; - } else if (ima_setup() < 0) { - error_message = "Failed to load IMA policy"; - goto finish; } else if (mac_smack_setup(&loaded_policy) < 0) { error_message = "Failed to load SMACK policy"; goto finish; + } else if (ima_setup() < 0) { + error_message = "Failed to load IMA policy"; + goto finish; } dual_timestamp_get(&security_finish_timestamp); } @@ -1618,9 +1617,6 @@ int main(int argc, char *argv[]) { unit_dump_config_items(stdout); retval = EXIT_SUCCESS; goto finish; - } else if (arg_action == ACTION_DONE) { - retval = EXIT_SUCCESS; - goto finish; } if (!arg_system && diff --git a/src/core/service.c b/src/core/service.c index 4d59d78ecb..eb125cb999 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -342,6 +342,7 @@ static void service_done(Unit *u) { s->bus_name_owner = mfree(s->bus_name_owner); service_close_socket_fd(s); + s->peer = socket_peer_unref(s->peer); unit_ref_unset(&s->accept_socket); diff --git a/src/core/service.h b/src/core/service.h index 8e56e1acb9..888007cc0b 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -152,6 +152,7 @@ struct Service { pid_t main_pid, control_pid; int socket_fd; + SocketPeer *peer; bool socket_fd_selinux_context_net; bool permissions_start_only; diff --git a/src/core/socket.c b/src/core/socket.c index 1ce41a1f07..ff55885fb3 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -57,6 +57,7 @@ #include "unit-printf.h" #include "unit.h" #include "user-util.h" +#include "in-addr-util.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, @@ -77,6 +78,9 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata); +SocketPeer *socket_peer_new(void); +int socket_find_peer(Socket *s, int fd, SocketPeer **p); + static void socket_init(Unit *u) { Socket *s = SOCKET(u); @@ -141,11 +145,17 @@ void socket_free_ports(Socket *s) { static void socket_done(Unit *u) { Socket *s = SOCKET(u); + SocketPeer *p; assert(s); socket_free_ports(s); + while ((p = hashmap_steal_first(s->peers_by_address))) + p->socket = NULL; + + s->peers_by_address = hashmap_free(s->peers_by_address); + s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX); s->control_command = NULL; @@ -468,6 +478,40 @@ static int socket_verify(Socket *s) { return 0; } +static void peer_address_hash_func(const void *p, struct siphash *state) { + const SocketPeer *s = p; + + assert(s); + + if (s->peer.sa.sa_family == AF_INET) + siphash24_compress(&s->peer.in.sin_addr, sizeof(s->peer.in.sin_addr), state); + else if (s->peer.sa.sa_family == AF_INET6) + siphash24_compress(&s->peer.in6.sin6_addr, sizeof(s->peer.in6.sin6_addr), state); +} + +static int peer_address_compare_func(const void *a, const void *b) { + const SocketPeer *x = a, *y = b; + + if (x->peer.sa.sa_family < y->peer.sa.sa_family) + return -1; + if (x->peer.sa.sa_family > y->peer.sa.sa_family) + return 1; + + switch(x->peer.sa.sa_family) { + case AF_INET: + return memcmp(&x->peer.in.sin_addr, &y->peer.in.sin_addr, sizeof(x->peer.in.sin_addr)); + case AF_INET6: + return memcmp(&x->peer.in6.sin6_addr, &y->peer.in6.sin6_addr, sizeof(x->peer.in6.sin6_addr)); + } + + return -1; +} + +const struct hash_ops peer_address_hash_ops = { + .hash = peer_address_hash_func, + .compare = peer_address_compare_func +}; + static int socket_load(Unit *u) { Socket *s = SOCKET(u); int r; @@ -475,6 +519,10 @@ static int socket_load(Unit *u) { assert(u); assert(u->load_state == UNIT_STUB); + r = hashmap_ensure_allocated(&s->peers_by_address, &peer_address_hash_ops); + if (r < 0) + return r; + r = unit_load_fragment_and_dropin(u); if (r < 0) return r; @@ -2050,6 +2098,7 @@ static void socket_enter_running(Socket *s, int cfd) { socket_set_state(s, SOCKET_RUNNING); } else { _cleanup_free_ char *prefix = NULL, *instance = NULL, *name = NULL; + _cleanup_(socket_peer_unrefp) SocketPeer *p = NULL; Service *service; if (s->n_connections >= s->max_connections) { @@ -2058,6 +2107,21 @@ static void socket_enter_running(Socket *s, int cfd) { return; } + if (s->max_connections_per_source > 0) { + r = socket_find_peer(s, cfd, &p); + if (r < 0) { + safe_close(cfd); + return; + } + + if (p->n_ref > s->max_connections_per_source) { + log_unit_warning(UNIT(s), "Too many incoming connections (%u) from source, refusing connection attempt.", p->n_ref); + safe_close(cfd); + p = NULL; + return; + } + } + r = socket_instantiate_service(s); if (r < 0) goto fail; @@ -2099,6 +2163,11 @@ static void socket_enter_running(Socket *s, int cfd) { cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */ s->n_connections++; + if (s->max_connections_per_source > 0) { + service->peer = socket_peer_ref(p); + p = NULL; + } + r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); if (r < 0) { /* We failed to activate the new service, but it still exists. Let's make sure the service @@ -2244,7 +2313,9 @@ static int socket_stop(Unit *u) { static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { Socket *s = SOCKET(u); + SocketPeer *k; SocketPort *p; + Iterator i; int r; assert(u); @@ -2295,6 +2366,16 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { } } + HASHMAP_FOREACH(k, s->peers_by_address, i) { + _cleanup_free_ char *t = NULL; + + r = sockaddr_pretty(&k->peer.sa, FAMILY_ADDRESS_SIZE(k->peer.sa.sa_family), true, true, &t); + if (r < 0) + return r; + + unit_serialize_item_format(u, f, "peer", "%u %s", k->n_ref, t); + } + return 0; } @@ -2458,6 +2539,33 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, } } + } else if (streq(key, "peer")) { + _cleanup_(socket_peer_unrefp) SocketPeer *p; + int n_ref, skip = 0; + SocketAddress a; + int r; + + if (sscanf(value, "%u %n", &n_ref, &skip) < 1 || n_ref < 1) + log_unit_debug(u, "Failed to parse socket peer value: %s", value); + else { + r = socket_address_parse(&a, value+skip); + if (r < 0) + return r; + + p = socket_peer_new(); + if (!p) + return log_oom(); + + p->n_ref = n_ref; + memcpy(&p->peer, &a.sockaddr, sizeof(a.sockaddr)); + p->socket = s; + + r = hashmap_put(s->peers_by_address, p, p); + if (r < 0) + return r; + + p = NULL; + } } else log_unit_debug(UNIT(s), "Unknown serialization key: %s", key); @@ -2554,6 +2662,83 @@ _pure_ static bool socket_check_gc(Unit *u) { return s->n_connections > 0; } +SocketPeer *socket_peer_new(void) { + SocketPeer *p; + + p = new0(SocketPeer, 1); + if (!p) + return NULL; + + p->n_ref = 1; + + return p; +} + +SocketPeer *socket_peer_ref(SocketPeer *p) { + if (!p) + return NULL; + + assert(p->n_ref > 0); + p->n_ref++; + + return p; +} + +SocketPeer *socket_peer_unref(SocketPeer *p) { + if (!p) + return NULL; + + assert(p->n_ref > 0); + + p->n_ref--; + + if (p->n_ref > 0) + return NULL; + + if (p->socket) + (void) hashmap_remove(p->socket->peers_by_address, p); + + free(p); + + return NULL; +} + +int socket_find_peer(Socket *s, int fd, SocketPeer **p) { + _cleanup_free_ SocketPeer *remote = NULL; + SocketPeer sa, *i; + socklen_t salen = sizeof(sa.peer); + int r; + + assert(fd >= 0); + assert(s); + + r = getpeername(fd, &sa.peer.sa, &salen); + if (r < 0) + return log_error_errno(errno, "getpeername failed: %m"); + + i = hashmap_get(s->peers_by_address, &sa); + if (i) { + *p = i; + return 1; + } + + remote = socket_peer_new(); + if (!remote) + return log_oom(); + + memcpy(&remote->peer, &sa.peer, sizeof(union sockaddr_union)); + remote->socket = s; + + r = hashmap_put(s->peers_by_address, remote, remote); + if (r < 0) + return r; + + *p = remote; + remote = NULL; + + return 0; +} + static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { SocketPort *p = userdata; int cfd = -1; diff --git a/src/core/socket.h b/src/core/socket.h index 6c32d67bef..2fe38ef2aa 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -20,6 +20,7 @@ ***/ typedef struct Socket Socket; +typedef struct SocketPeer SocketPeer; #include "mount.h" #include "service.h" @@ -79,9 +80,12 @@ struct Socket { LIST_HEAD(SocketPort, ports); + Hashmap *peers_by_address; + unsigned n_accepted; unsigned n_connections; unsigned max_connections; + unsigned max_connections_per_source; unsigned backlog; unsigned keep_alive_cnt; @@ -164,6 +168,18 @@ struct Socket { RateLimit trigger_limit; }; +struct SocketPeer { + unsigned n_ref; + + Socket *socket; + union sockaddr_union peer; +}; + +SocketPeer *socket_peer_ref(SocketPeer *p); +SocketPeer *socket_peer_unref(SocketPeer *p); + +DEFINE_TRIVIAL_CLEANUP_FUNC(SocketPeer*, socket_peer_unref); + /* Called from the service code when collecting fds */ int socket_collect_fds(Socket *s, int **fds); diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index dcc09fcc6d..e3d17c864d 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -558,6 +558,89 @@ static int compose_open_fds(pid_t pid, char **open_fds) { return 0; } +static int get_process_ns(pid_t pid, const char *namespace, ino_t *ns) { + const char *p; + struct stat stbuf; + _cleanup_close_ int proc_ns_dir_fd; + + p = procfs_file_alloca(pid, "ns"); + + proc_ns_dir_fd = open(p, O_DIRECTORY | O_CLOEXEC | O_RDONLY); + if (proc_ns_dir_fd < 0) + return -errno; + + if (fstatat(proc_ns_dir_fd, namespace, &stbuf, /* flags */0) < 0) + return -errno; + + *ns = stbuf.st_ino; + return 0; +} + +static int get_mount_namespace_leader(pid_t pid, pid_t *container_pid) { + pid_t cpid = pid, ppid = 0; + ino_t proc_mntns; + int r = 0; + + r = get_process_ns(pid, "mnt", &proc_mntns); + if (r < 0) + return r; + + while (1) { + ino_t parent_mntns; + + r = get_process_ppid(cpid, &ppid); + if (r < 0) + return r; + + r = get_process_ns(ppid, "mnt", &parent_mntns); + if (r < 0) + return r; + + if (proc_mntns != parent_mntns) + break; + + if (ppid == 1) + return -ENOENT; + + cpid = ppid; + } + + *container_pid = ppid; + return 0; +} + +/* Returns 1 if the parent was found. + * Returns 0 if there is not a process we can call the pid's + * container parent (the pid's process isn't 'containerized'). + * Returns a negative number on errors. + */ +static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) { + int r = 0; + pid_t container_pid; + const char *proc_root_path; + struct stat root_stat, proc_root_stat; + + /* To compare inodes of / and /proc/[pid]/root */ + if (stat("/", &root_stat) < 0) + return -errno; + + proc_root_path = procfs_file_alloca(pid, "root"); + if (stat(proc_root_path, &proc_root_stat) < 0) + return -errno; + + /* The process uses system root. */ + if (proc_root_stat.st_ino == root_stat.st_ino) { + *cmdline = NULL; + return 0; + } + + r = get_mount_namespace_leader(pid, &container_pid); + if (r < 0) + return r; + + return get_process_cmdline(container_pid, 0, false, cmdline); +} + static int change_uid_gid(const char *context[]) { uid_t uid; gid_t gid; @@ -933,11 +1016,13 @@ static int process_kernel(int argc, char* argv[]) { /* The larger ones we allocate on the heap */ _cleanup_free_ char *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, - *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL; + *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL, + *core_proc_mountinfo = NULL, *core_container_cmdline = NULL; _cleanup_free_ char *exe = NULL, *comm = NULL; const char *context[_CONTEXT_MAX]; - struct iovec iovec[25]; + bool proc_self_root_is_slash; + struct iovec iovec[27]; size_t n_iovec = 0; uid_t owner_uid; const char *p; @@ -1110,6 +1195,15 @@ static int process_kernel(int argc, char* argv[]) { IOVEC_SET_STRING(iovec[n_iovec++], core_proc_cgroup); } + p = procfs_file_alloca(pid, "mountinfo"); + if (read_full_file(p, &t, NULL) >=0) { + core_proc_mountinfo = strappend("COREDUMP_PROC_MOUNTINFO=", t); + free(t); + + if (core_proc_mountinfo) + IOVEC_SET_STRING(iovec[n_iovec++], core_proc_mountinfo); + } + if (get_process_cwd(pid, &t) >= 0) { core_cwd = strjoina("COREDUMP_CWD=", t); free(t); @@ -1119,9 +1213,20 @@ static int process_kernel(int argc, char* argv[]) { if (get_process_root(pid, &t) >= 0) { core_root = strjoina("COREDUMP_ROOT=", t); - free(t); IOVEC_SET_STRING(iovec[n_iovec++], core_root); + + /* If the process' root is "/", then there is a chance it has + * mounted own root and hence being containerized. */ + proc_self_root_is_slash = strcmp(t, "/") == 0; + free(t); + if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0) { + core_container_cmdline = strappend("COREDUMP_CONTAINER_CMDLINE=", t); + free(t); + + if (core_container_cmdline) + IOVEC_SET_STRING(iovec[n_iovec++], core_container_cmdline); + } } if (get_process_environ(pid, &t) >= 0) { diff --git a/src/journal/.gitignore b/src/journal/.gitignore index 04d5852547..b93a9462fa 100644 --- a/src/journal/.gitignore +++ b/src/journal/.gitignore @@ -1,4 +1,3 @@ /journald-gperf.c -/libsystemd-journal.pc /audit_type-list.txt /audit_type-*-name.* diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 348e396292..63363035e7 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -893,7 +893,7 @@ int config_parse_user_tasks_max( /* First, try to parse as percentage */ r = parse_percent(rvalue); - if (r > 0 && r < 100) + if (r >= 0) k = system_tasks_max_scale(r, 100U); else { diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index ddec6cb4d6..c78ca7ad76 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -185,7 +185,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info); - if (arg_legend) + if (arg_legend && n_machines > 0) printf("%-*s %-*s %-*s\n", (int) max_name, "MACHINE", (int) max_class, "CLASS", @@ -197,8 +197,10 @@ static int list_machines(int argc, char *argv[], void *userdata) { (int) max_class, machines[j].class, (int) max_service, machines[j].service); - if (arg_legend) + if (arg_legend && n_machines > 0) printf("\n%zu machines listed.\n", n_machines); + else + printf("No machines.\n"); return 0; } @@ -305,7 +307,7 @@ static int list_images(int argc, char *argv[], void *userdata) { qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info); - if (arg_legend) + if (arg_legend && n_images > 0) printf("%-*s %-*s %-3s %-*s %-*s %-*s\n", (int) max_name, "NAME", (int) max_type, "TYPE", @@ -326,8 +328,10 @@ static int list_images(int argc, char *argv[], void *userdata) { (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime))); } - if (arg_legend) + if (arg_legend && n_images > 0) printf("\n%zu images listed.\n", n_images); + else + printf("No images.\n"); return 0; } @@ -2314,7 +2318,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info); - if (arg_legend) + if (arg_legend && n_transfers > 0) printf("%-*s %-*s %-*s %-*s %-*s\n", (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID", (int) 7, "PERCENT", @@ -2330,8 +2334,10 @@ static int list_transfers(int argc, char *argv[], void *userdata) { (int) max_local, transfers[j].local, (int) max_remote, transfers[j].remote); - if (arg_legend) + if (arg_legend && n_transfers > 0) printf("\n%zu transfers listed.\n", n_transfers); + else + printf("No transfers.\n"); return 0; } diff --git a/src/test/test-condition.c b/src/test/test-condition.c index 987862f1c6..66003aa6bd 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -25,6 +25,7 @@ #include "audit-util.h" #include "condition.h" #include "hostname-util.h" +#include "id128-util.h" #include "ima-util.h" #include "log.h" #include "macro.h" @@ -142,9 +143,14 @@ static void test_condition_test_host(void) { hostname = gethostname_malloc(); assert_se(hostname); - condition = condition_new(CONDITION_HOST, hostname, false, false); - assert_se(condition_test(condition)); - condition_free(condition); + /* if hostname looks like an id128 then skip testing it */ + if (id128_is_valid(hostname)) + log_notice("hostname is an id128, skipping test"); + else { + condition = condition_new(CONDITION_HOST, hostname, false, false); + assert_se(condition_test(condition)); + condition_free(condition); + } } static void test_condition_test_architecture(void) { diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 77ef4e8b2a..1d24115b5c 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -33,6 +33,7 @@ #include "test-helper.h" #include "unit.h" #include "util.h" +#include "virt.h" typedef void (*test_function_t)(Manager *m); @@ -91,6 +92,16 @@ static void test_exec_personality(Manager *m) { #elif defined(__s390__) test(m, "exec-personality-s390.service", 0, CLD_EXITED); +#elif defined(__powerpc64__) +# if __BYTE_ORDER == __BIG_ENDIAN + test(m, "exec-personality-ppc64.service", 0, CLD_EXITED); +# else + test(m, "exec-personality-ppc64le.service", 0, CLD_EXITED); +# endif + +#elif defined(__aarch64__) + test(m, "exec-personality-aarch64.service", 0, CLD_EXITED); + #elif defined(__i386__) test(m, "exec-personality-x86.service", 0, CLD_EXITED); #endif @@ -111,6 +122,10 @@ static void test_exec_privatetmp(Manager *m) { } static void test_exec_privatedevices(Manager *m) { + if (detect_container() > 0) { + log_notice("testing in container, skipping private device tests"); + return; + } test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED); test(m, "exec-privatedevices-no.service", 0, CLD_EXITED); } diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 6094d4c3e5..164a10d8a8 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -114,7 +114,8 @@ static void test_find_binary(const char *self) { assert_se(find_binary(self, &p) == 0); puts(p); - assert_se(endswith(p, "/lt-test-path-util")); + /* libtool might prefix the binary name with "lt-" */ + assert_se(endswith(p, "/lt-test-path-util") || endswith(p, "/test-path-util")); assert_se(path_is_absolute(p)); free(p); diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 562ad4acb8..9ada46b1e9 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -40,6 +40,7 @@ #include "stdio-util.h" #include "string-util.h" #include "terminal-util.h" +#include "test-helper.h" #include "util.h" #include "virt.h" @@ -357,7 +358,7 @@ int main(int argc, char *argv[]) { (void) parse_pid(argv[1], &pid); test_get_process_comm(pid); } else { - test_get_process_comm(1); + TEST_REQ_RUNNING_SYSTEMD(test_get_process_comm(1)); test_get_process_comm(getpid()); } diff --git a/test/test-execute/exec-personality-aarch64.service b/test/test-execute/exec-personality-aarch64.service new file mode 100644 index 0000000000..40b6d95e3a --- /dev/null +++ b/test/test-execute/exec-personality-aarch64.service @@ -0,0 +1,7 @@ +Unit] +Description=Test for Personality=aarch64 + +[Service] +ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "aarch64")' +Type=oneshot +Personality=aarch64 diff --git a/test/test-execute/exec-personality-ppc64.service b/test/test-execute/exec-personality-ppc64.service new file mode 100644 index 0000000000..ccc2c8d83d --- /dev/null +++ b/test/test-execute/exec-personality-ppc64.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Personality=ppc64 + +[Service] +ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64")' +Type=oneshot +Personality=ppc64 diff --git a/test/test-execute/exec-personality-ppc64le.service b/test/test-execute/exec-personality-ppc64le.service new file mode 100644 index 0000000000..2a7625087d --- /dev/null +++ b/test/test-execute/exec-personality-ppc64le.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Personality=ppc64le + +[Service] +ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "ppc64le")' +Type=oneshot +Personality=ppc64le diff --git a/test/udev-test.pl b/test/udev-test.pl index da0a4e1f6b..129af854f1 100755 --- a/test/udev-test.pl +++ b/test/udev-test.pl @@ -1535,11 +1535,18 @@ if (!($<==0)) { exit($EXIT_TEST_SKIP); } +# skip the test when running in a chroot +system("systemd-detect-virt", "-r", "-q"); +if ($? >> 8 == 0) { + print "Running in a chroot, skipping the test.\n"; + exit($EXIT_TEST_SKIP); +} + # skip the test when running in a container system("systemd-detect-virt", "-c", "-q"); if ($? >> 8 == 0) { - print "Running in a container, skipping the test.\n"; - exit($EXIT_TEST_SKIP); + print "Running in a container, skipping the test.\n"; + exit($EXIT_TEST_SKIP); } udev_setup(); diff --git a/units/systemd-ask-password-console.path b/units/systemd-ask-password-console.path index 2949635fea..7899ae788f 100644 --- a/units/systemd-ask-password-console.path +++ b/units/systemd-ask-password-console.path @@ -11,7 +11,7 @@ Documentation=man:systemd-ask-password-console.service(8) DefaultDependencies=no Conflicts=shutdown.target After=plymouth-start.service -Before=paths.target shutdown.target +Before=paths.target shutdown.target cryptsetup.target ConditionPathExists=!/run/plymouth/pid [Path] diff --git a/units/systemd-ask-password-wall.path b/units/systemd-ask-password-wall.path index 95ec9bc8a0..a3ca617256 100644 --- a/units/systemd-ask-password-wall.path +++ b/units/systemd-ask-password-wall.path @@ -10,7 +10,7 @@ Description=Forward Password Requests to Wall Directory Watch Documentation=man:systemd-ask-password-console.service(8) DefaultDependencies=no Conflicts=shutdown.target -Before=paths.target shutdown.target +Before=paths.target shutdown.target cryptsetup.target [Path] DirectoryNotEmpty=/run/systemd/ask-password diff --git a/units/user/graphical-session-pre.target b/units/user/graphical-session-pre.target new file mode 100644 index 0000000000..86d15aff33 --- /dev/null +++ b/units/user/graphical-session-pre.target @@ -0,0 +1,14 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Session services which should run early before the graphical session is brought up +Documentation=man:systemd.special(7) +Requires=basic.target +Before=graphical-session.target +RefuseManualStart=yes +StopWhenUnneeded=yes |