diff options
35 files changed, 451 insertions, 181 deletions
diff --git a/.mkosi/mkosi.fedora b/.mkosi/mkosi.fedora index 478703c41a..4f5f084f93 100644 --- a/.mkosi/mkosi.fedora +++ b/.mkosi/mkosi.fedora @@ -27,7 +27,7 @@ Format=raw_btrfs Bootable=yes [Partitions] -RootSize=2G +RootSize=3G [Packages] BuildPackages= @@ -37,6 +37,7 @@ BuildPackages= bzip2-devel cryptsetup-devel dbus-devel + diffutils docbook-style-xsl elfutils-devel gcc @@ -69,4 +70,5 @@ BuildPackages= python3-devel python3-lxml qrencode-devel + tree xz-devel diff --git a/Makefile.am b/Makefile.am index 8f7b83f0ab..d75807a9f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -149,7 +149,8 @@ TESTS = endif AM_TESTS_ENVIRONMENT = \ export SYSTEMD_KBD_MODEL_MAP=$(abs_top_srcdir)/src/locale/kbd-model-map; \ - export SYSTEMD_LANGUAGE_FALLBACK_MAP=$(abs_top_srcdir)/src/locale/language-fallback-map; + export SYSTEMD_LANGUAGE_FALLBACK_MAP=$(abs_top_srcdir)/src/locale/language-fallback-map; \ + export PATH=$(abs_top_builddir):$$PATH; if ENABLE_BASH_COMPLETION dist_bashcompletion_DATA = $(dist_bashcompletion_data) @@ -143,6 +143,8 @@ REQUIREMENTS: util-linux >= v2.27.1 required dbus >= 1.4.0 (strictly speaking optional, but recommended) + NOTE: If using dbus < 1.9.18, you should override the default + policy directory (--with-dbuspolicydir=/etc/dbus-1/system.d). dracut (optional) PolicyKit (optional) @@ -12,9 +12,6 @@ Bugfixes: Environment=ONE='one' "TWO='two two' too" THREE= ExecStart=/bin/python3 -c 'import sys;print(sys.argv)' $ONE $TWO $THREE -* When systemctl --host is used, underlying ssh connection can remain open. - bus_close does not kill children? - External: * Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros. @@ -34,6 +31,38 @@ Features: * replace all canonicalize_file_name() invocations by chase_symlinks(), in particulr those where a rootdir is relevant. +* maybe introduce gpt auto discovery for /var/tmp? + +* set ProtectSystem=strict for all our usual services. + +* maybe add gpt-partition-based user management: each user gets his own + LUKS-encrypted GPT partition with a new GPT type. A small nss module + enumerates users via udev partition enumeration. UIDs are assigned in a fixed + way: the partition index is added as offset to some fixed base uid. User name + is stored in GPT partition name. A PAM module authenticates the user via the + LUKS partition password. Benefits: strong per-user security, compatibility + with stateless/read-only/verity-enabled root. (other idea: do this based on + loopback files in /home, without GPT involvement) + +* gpt-auto logic: introduce support for discovering /var matching an image. For + that, use a partition type UUID that is hashed from the OS name (as encoded + in /etc/os-release), the architecture, and 4 new bits from the gpt flags + field of the root partition. This way can easily support multiple OS + installations on the same GPT partition table, without problems with + unmatched /var partitions. + +* gpt-auto logic: related to the above, maybe support a "secondary" root + partition, that is mounted to / and is writable, and where the actual root's + /usr is mounted into. + +* add dm-verity boots, and in nspawn (libcryptsetup knows this, should be relatively straight-forward) + +* machined: add apis to query /etc/machine-info data of a container + +* .mount and .swap units: add Format=yes|no option that formats the partition before mounting/enabling it, implicitly + +* gpt-auto logic: support encrypted swap, add kernel cmdline option to force it, and honour a gpt bit about it, plus maybe a configuration file + * drop nss-myhostname in favour of nss-resolve? * drop internal dlopen() based nss-dns fallback in nss-resolve, and rely on the @@ -279,8 +308,6 @@ Features: * For timer units: add some mechanisms so that timer units that trigger immediately on boot do not have the services they run added to the initial transaction and thus confuse Type=idle. -* Run most system services with cgroupfs read-only and procfs with a more secure mode (doesn't work, since the hidepid= option is per-pid-namespace, not per-mount) - * add bus api to query unit file's X fields. * gpt-auto-generator: diff --git a/configure.ac b/configure.ac index 32febcabe9..11bd46cbab 100644 --- a/configure.ac +++ b/configure.ac @@ -155,7 +155,6 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ -Wall \ -Wextra \ -Wundef \ - "-Wformat=2 -Wformat-security -Wformat-nonliteral" \ -Wlogical-op \ -Wmissing-include-dirs \ -Wold-style-definition \ @@ -168,6 +167,7 @@ CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\ -Werror=implicit-function-declaration \ -Werror=missing-declarations \ -Werror=return-type \ + -Werror=format=2 \ -Wstrict-prototypes \ -Wredundant-decls \ -Wmissing-noreturn \ @@ -1451,7 +1451,7 @@ AC_SUBST(TTY_GID) AC_ARG_WITH([dbuspolicydir], AS_HELP_STRING([--with-dbuspolicydir=DIR], [D-Bus policy directory]), [], - [with_dbuspolicydir=${sysconfdir}/dbus-1/system.d]) + [with_dbuspolicydir=${datadir}/dbus-1/system.d]) AX_NORMALIZE_PATH([with_dbuspolicydir]) AC_ARG_WITH([dbussessionservicedir], diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb index feb4a97192..4eedaf55ee 100644 --- a/hwdb/60-evdev.hwdb +++ b/hwdb/60-evdev.hwdb @@ -93,6 +93,14 @@ evdev:input:b0003v05ACp025B* ######################################### # ASUS ######################################### + +# Asus VivoBook E402SA +evdev:name:Elan Touchpad:dmi:*svnASUSTeKCOMPUTERINC.:pnE402SA* + EVDEV_ABS_00=::29 + EVDEV_ABS_01=::29 + EVDEV_ABS_35=::29 + EVDEV_ABS_36=::29 + # Asus K52JT evdev:name:ETPS/2 Elantech Touchpad:dmi:bvn*:bvr*:bd*:svnASUSTeKComputerInc.:pnK52JT:* EVDEV_ABS_00=::18 @@ -191,6 +199,13 @@ evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondv7* EVDEV_ABS_35=1068:5805:44 EVDEV_ABS_36=1197:4890:57 +# HP Spectre +evdev:name:SynPS/2 Synaptics TouchPad:dmi:i*svnHP:pnHPSpectreNotebook* + EVDEV_ABS_00=1205:5691:47 + EVDEV_ABS_01=1083:4808:65 + EVDEV_ABS_35=1205:5691:47 + EVDEV_ABS_36=1083:4808:65 + ######################################### # Lenovo ######################################### @@ -243,6 +258,13 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrLenovoV360* EVDEV_ABS_00=1243:5927:60 EVDEV_ABS_01=902:5330:108 +# Lenovo W530 +evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadW530* + EVDEV_ABS_00=1250:5631:59 + EVDEV_ABS_01=1205:4834:81 + EVDEV_ABS_35=1250:5631:59 + EVDEV_ABS_36=1205:4834:81 + # Lenovo X220 series evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*pvrThinkPadX220* EVDEV_ABS_00=1316:5627:58 @@ -286,3 +308,12 @@ evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn305V4A/ EVDEV_ABS_01=0:1116:24 EVDEV_ABS_35=0:2480:28 EVDEV_ABS_36=0:1116:24 + +######################################### +# Toshiba +######################################### + +# Toshiba Tecra M11 +evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:*svnTOSHIBA:pnTECRAM11* + EVDEV_ABS_00=90:962:11 + EVDEV_ABS_01=51:681:14 diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml index 5538805e65..ff3638c909 100644 --- a/man/sd_journal_print.xml +++ b/man/sd_journal_print.xml @@ -189,10 +189,9 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid( <refsect1> <title>Return Value</title> - <para>The four calls return 0 on success or a negative errno-style - error code. The - <citerefentry project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> - variable itself is not altered.</para> + <para>The five calls return 0 on success or a negative errno-style error code. The <citerefentry + project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> variable itself is + not altered.</para> <para>If <citerefentry><refentrytitle>systemd-journald</refentrytitle><manvolnum>8</manvolnum></citerefentry> @@ -218,13 +217,11 @@ sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid( <refsect1> <title>Notes</title> - <para>The <function>sd_journal_print()</function>, - <function>sd_journal_printv()</function>, - <function>sd_journal_send()</function> and - <function>sd_journal_sendv()</function> interfaces are available - as a shared library, which can be compiled and linked to with the - <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> - file.</para> + <para>The <function>sd_journal_print()</function>, <function>sd_journal_printv()</function>, + <function>sd_journal_send()</function>, <function>sd_journal_sendv()</function> and + <function>sd_journal_perror()</function> interfaces are available as a shared library, which can be compiled and + linked to with the <constant>libsystemd</constant> <citerefentry + project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> file.</para> </refsect1> <refsect1> diff --git a/man/systemctl.xml b/man/systemctl.xml index 68c8546189..acf975138a 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -882,17 +882,21 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <term><command>show</command> <optional><replaceable>PATTERN</replaceable>…|<replaceable>JOB</replaceable>…</optional></term> <listitem> - <para>Show properties of one or more units, jobs, or the - manager itself. If no argument is specified, properties of - the manager will be shown. If a unit name is specified, - properties of the unit are shown, and if a job ID is - specified, properties of the job are shown. By default, empty - properties are suppressed. Use <option>--all</option> to - show those too. To select specific properties to show, use - <option>--property=</option>. This command is intended to be - used whenever computer-parsable output is required. Use - <command>status</command> if you are looking for formatted - human-readable output.</para> + <para>Show properties of one or more units, jobs, or the manager itself. If no argument is specified, + properties of the manager will be shown. If a unit name is specified, properties of the unit are shown, and + if a job ID is specified, properties of the job are shown. By default, empty properties are suppressed. Use + <option>--all</option> to show those too. To select specific properties to show, use + <option>--property=</option>. This command is intended to be used whenever computer-parsable output is + required. Use <command>status</command> if you are looking for formatted human-readable output.</para> + + <para>Many properties shown by <command>systemctl show</command> map directly to configuration settings of + the system and service manager and its unit files. Note that the properties shown by the command are + generally more low-level, normalized versions of the original configuration settings and expose runtime + state in addition to configuration. For example, properties shown for service units include the service's + current main process identifier as <literal>MainPID</literal> (which is runtime state), and time settings + are always exposed as properties ending in the <literal>…USec</literal> suffix even if a matching + configuration options end in <literal>…Sec</literal>, because microseconds is the normalized time unit used + by the system and service manager.</para> </listitem> </varlistentry> <varlistentry> diff --git a/mkosi.build b/mkosi.build index 94a6667e42..872841eb63 100755 --- a/mkosi.build +++ b/mkosi.build @@ -22,4 +22,14 @@ ./autogen.sh c make -j `nproc` + +make check make install + +mkdir -p $DESTDIR/etc + +cat > $DESTDIR/etc/issue <<EOF +\S (built from systemd tree) +Kernel \r on an \m (\l) + +EOF diff --git a/src/basic/log.c b/src/basic/log.c index 71d5a0baa2..557212c022 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -243,13 +243,13 @@ int log_open(void) { return 0; } - if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) || + if (!IN_SET(log_target, LOG_TARGET_AUTO, LOG_TARGET_SAFE) || getpid() == 1 || isatty(STDERR_FILENO) <= 0) { - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_JOURNAL) { + if (IN_SET(log_target, LOG_TARGET_AUTO, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_JOURNAL)) { r = log_open_journal(); if (r >= 0) { log_close_syslog(); @@ -258,8 +258,8 @@ int log_open(void) { } } - if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) { + if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_SYSLOG)) { r = log_open_syslog(); if (r >= 0) { log_close_journal(); @@ -268,11 +268,11 @@ int log_open(void) { } } - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SAFE || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_KMSG) { + if (IN_SET(log_target, LOG_TARGET_AUTO, + LOG_TARGET_SAFE, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_KMSG)) { r = log_open_kmsg(); if (r >= 0) { log_close_journal(); @@ -588,9 +588,9 @@ static int log_dispatch( if ((e = strpbrk(buffer, NEWLINE))) *(e++) = 0; - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_JOURNAL) { + if (IN_SET(log_target, LOG_TARGET_AUTO, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_JOURNAL)) { k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer); if (k < 0) { @@ -600,8 +600,8 @@ static int log_dispatch( } } - if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) { + if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_SYSLOG)) { k = write_to_syslog(level, error, file, line, func, buffer); if (k < 0) { @@ -612,11 +612,11 @@ static int log_dispatch( } if (k <= 0 && - (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SAFE || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_KMSG)) { + IN_SET(log_target, LOG_TARGET_AUTO, + LOG_TARGET_SAFE, + LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_KMSG)) { k = write_to_kmsg(level, error, file, line, func, buffer); if (k < 0) { @@ -881,9 +881,9 @@ int log_struct_internal( if ((level & LOG_FACMASK) == 0) level = log_facility | LOG_PRI(level); - if ((log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_JOURNAL) && + if (IN_SET(log_target, LOG_TARGET_AUTO, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_JOURNAL) && journal_fd >= 0) { char header[LINE_MAX]; struct iovec iovec[17] = {}; @@ -1078,8 +1078,8 @@ int log_show_location_from_string(const char *e) { } bool log_on_console(void) { - if (log_target == LOG_TARGET_CONSOLE || - log_target == LOG_TARGET_CONSOLE_PREFIXED) + if (IN_SET(log_target, LOG_TARGET_CONSOLE, + LOG_TARGET_CONSOLE_PREFIXED)) return true; return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0; diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 8970050408..840e94a553 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -693,13 +693,12 @@ int umount_verbose(const char *what) { const char *mount_propagation_flags_to_string(unsigned long flags) { switch (flags & (MS_SHARED|MS_SLAVE|MS_PRIVATE)) { - + case 0: + return ""; case MS_SHARED: return "shared"; - case MS_SLAVE: return "slave"; - case MS_PRIVATE: return "private"; } @@ -707,17 +706,18 @@ const char *mount_propagation_flags_to_string(unsigned long flags) { return NULL; } -unsigned long mount_propagation_flags_from_string(const char *name) { - if (isempty(name)) - return 0; - - if (streq(name, "shared")) - return MS_SHARED; - if (streq(name, "slave")) - return MS_SLAVE; - if (streq(name, "private")) - return MS_PRIVATE; +int mount_propagation_flags_from_string(const char *name, unsigned long *ret) { + if (isempty(name)) + *ret = 0; + else if (streq(name, "shared")) + *ret = MS_SHARED; + else if (streq(name, "slave")) + *ret = MS_SLAVE; + else if (streq(name, "private")) + *ret = MS_PRIVATE; + else + return -EINVAL; return 0; } diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index c8049198d4..1615c94e9a 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -63,4 +63,4 @@ int mount_verbose( int umount_verbose(const char *where); const char *mount_propagation_flags_to_string(unsigned long flags); -unsigned long mount_propagation_flags_from_string(const char *name); +int mount_propagation_flags_from_string(const char *name, unsigned long *ret); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 1f4c2e4e43..d5e7edb589 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -27,6 +27,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <sys/personality.h> #include <sys/prctl.h> #include <sys/types.h> @@ -274,27 +275,100 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return 0; } -void rename_process(const char name[8]) { - assert(name); +int rename_process(const char name[]) { + static size_t mm_size = 0; + static char *mm = NULL; + bool truncated = false; + size_t l; + + /* This is a like a poor man's setproctitle(). It changes the comm field, argv[0], and also the glibc's + * internally used name of the process. For the first one a limit of 16 chars applies; to the second one in + * many cases one of 10 (i.e. length of "/sbin/init") — however if we have CAP_SYS_RESOURCES it is unbounded; + * to the third one 7 (i.e. the length of "systemd". If you pass a longer string it will likely be + * truncated. + * + * Returns 0 if a name was set but truncated, > 0 if it was set but not truncated. */ + + if (isempty(name)) + return -EINVAL; /* let's not confuse users unnecessarily with an empty name */ - /* This is a like a poor man's setproctitle(). It changes the - * comm field, argv[0], and also the glibc's internally used - * name of the process. For the first one a limit of 16 chars - * applies, to the second one usually one of 10 (i.e. length - * of "/sbin/init"), to the third one one of 7 (i.e. length of - * "systemd"). If you pass a longer string it will be - * truncated */ + l = strlen(name); + /* First step, change the comm field. */ (void) prctl(PR_SET_NAME, name); + if (l > 15) /* Linux process names can be 15 chars at max */ + truncated = true; + + /* Second step, change glibc's ID of the process name. */ + if (program_invocation_name) { + size_t k; + + k = strlen(program_invocation_name); + strncpy(program_invocation_name, name, k); + if (l > k) + truncated = true; + } + + /* Third step, completely replace the argv[] array the kernel maintains for us. This requires privileges, but + * has the advantage that the argv[] array is exactly what we want it to be, and not filled up with zeros at + * the end. This is the best option for changing /proc/self/cmdline.*/ + if (mm_size < l+1) { + size_t nn_size; + char *nn; + + /* Let's not bother with this if we don't have euid == 0. Strictly speaking if people do weird stuff + * with capabilities this could work even for euid != 0, but our own code generally doesn't do that, + * hence let's use this as quick bypass check, to avoid calling mmap() if PR_SET_MM_ARG_START fails + * with EPERM later on anyway. After all geteuid() is dead cheap to call, but mmap() is not. */ + if (geteuid() != 0) { + log_debug("Skipping PR_SET_MM_ARG_START, as we don't have privileges."); + goto use_saved_argv; + } + + nn_size = PAGE_ALIGN(l+1); + nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + if (nn == MAP_FAILED) { + log_debug_errno(errno, "mmap() failed: %m"); + goto use_saved_argv; + } + + strncpy(nn, name, nn_size); + + /* Now, let's tell the kernel about this new memory */ + if (prctl(PR_SET_MM, PR_SET_MM_ARG_START, (unsigned long) nn, 0, 0) < 0) { + log_debug_errno(errno, "PR_SET_MM_ARG_START failed, proceeding without: %m"); + (void) munmap(nn, nn_size); + goto use_saved_argv; + } + + /* And update the end pointer to the new end, too. If this fails, we don't really know what to do, it's + * pretty unlikely that we can rollback, hence we'll just accept the failure, and continue. */ + if (prctl(PR_SET_MM, PR_SET_MM_ARG_END, (unsigned long) nn + l + 1, 0, 0) < 0) + log_debug_errno(errno, "PR_SET_MM_ARG_END failed, proceeding without: %m"); - if (program_invocation_name) - strncpy(program_invocation_name, name, strlen(program_invocation_name)); + if (mm) + (void) munmap(mm, mm_size); + + mm = nn; + mm_size = nn_size; + } else + strncpy(mm, name, mm_size); + +use_saved_argv: + /* Fourth step: in all cases we'll also update the original argv[], so that our own code gets it right too if + * it still looks here */ if (saved_argc > 0) { int i; - if (saved_argv[0]) - strncpy(saved_argv[0], name, strlen(saved_argv[0])); + if (saved_argv[0]) { + size_t k; + + k = strlen(saved_argv[0]); + strncpy(saved_argv[0], name, k); + if (l > k) + truncated = true; + } for (i = 1; i < saved_argc; i++) { if (!saved_argv[i]) @@ -303,6 +377,8 @@ void rename_process(const char name[8]) { memzero(saved_argv[i], strlen(saved_argv[i])); } } + + return !truncated; } int is_kernel_thread(pid_t pid) { diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 89dfeb4d6a..d378901399 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -64,7 +64,7 @@ void sigkill_waitp(pid_t *pid); int kill_and_sigcont(pid_t pid, int sig); -void rename_process(const char name[8]); +int rename_process(const char name[]); int is_kernel_thread(pid_t pid); int getenv_for_pid(pid_t pid, const char *field, char **_value); diff --git a/src/basic/virt.c b/src/basic/virt.c index 9b7eb71319..33641e6886 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -409,8 +409,7 @@ int detect_container(void) { if (cached_found >= 0) return cached_found; - /* /proc/vz exists in container and outside of the container, - * /proc/bc only outside of the container. */ + /* /proc/vz exists in container and outside of the container, /proc/bc only outside of the container. */ if (access("/proc/vz", F_OK) >= 0 && access("/proc/bc", F_OK) < 0) { r = VIRTUALIZATION_OPENVZ; @@ -418,50 +417,58 @@ int detect_container(void) { } if (getpid() == 1) { - /* If we are PID 1 we can just check our own - * environment variable */ + /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */ e = getenv("container"); if (isempty(e)) { r = VIRTUALIZATION_NONE; goto finish; } - } else { - - /* Otherwise, PID 1 dropped this information into a - * file in /run. This is better than accessing - * /proc/1/environ, since we don't need CAP_SYS_PTRACE - * for that. */ - - r = read_one_line_file("/run/systemd/container", &m); - if (r == -ENOENT) { - - /* Fallback for cases where PID 1 was not - * systemd (for example, cases where - * init=/bin/sh is used. */ - - r = getenv_for_pid(1, "container", &m); - if (r <= 0) { - - /* If that didn't work, give up, - * assume no container manager. - * - * Note: This means we still cannot - * detect containers if init=/bin/sh - * is passed but privileges dropped, - * as /proc/1/environ is only readable - * with privileges. */ - - r = VIRTUALIZATION_NONE; - goto finish; - } - } - if (r < 0) - return r; + goto translate_name; + } + + /* Otherwise, PID 1 might have dropped this information into a file in /run. This is better than accessing + * /proc/1/environ, since we don't need CAP_SYS_PTRACE for that. */ + r = read_one_line_file("/run/systemd/container", &m); + if (r >= 0) { + e = m; + goto translate_name; + } + if (r != -ENOENT) + return log_debug_errno(r, "Failed to read /run/systemd/container: %m"); + + /* Fallback for cases where PID 1 was not systemd (for example, cases where init=/bin/sh is used. */ + r = getenv_for_pid(1, "container", &m); + if (r > 0) { e = m; + goto translate_name; } + if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */ + log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m"); + + /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. Hence, if the PID shown + * there is not 1, we know we are in a PID namespace. and hence a container. */ + r = read_one_line_file("/proc/1/sched", &m); + if (r >= 0) { + const char *t; + + t = strrchr(m, '('); + if (!t) + return -EIO; + + if (!startswith(t, "(1,")) { + r = VIRTUALIZATION_CONTAINER_OTHER; + goto finish; + } + } else if (r != -ENOENT) + return r; + + /* If that didn't work, give up, assume no container manager. */ + r = VIRTUALIZATION_NONE; + goto finish; +translate_name: for (j = 0; j < ELEMENTSOF(value_table); j++) if (streq(e, value_table[j].value)) { r = value_table[j].id; @@ -471,7 +478,7 @@ int detect_container(void) { r = VIRTUALIZATION_CONTAINER_OTHER; finish: - log_debug("Found container virtualization %s", virtualization_to_string(r)); + log_debug("Found container virtualization %s.", virtualization_to_string(r)); cached_found = r; return r; } diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index b3fc0ff5c3..9960b7a811 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1671,7 +1671,7 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { c->mount_flags = flags; - unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, strempty(mount_propagation_flags_to_string(flags))); + unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, mount_propagation_flags_to_string(flags)); } return 1; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index f325d853c6..bc0cf73d39 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1278,25 +1278,17 @@ int config_parse_exec_mount_flags( void *userdata) { - unsigned long flags; ExecContext *c = data; + int r; assert(filename); assert(lvalue); assert(rvalue); assert(data); - if (isempty(rvalue)) - flags = 0; - else { - flags = mount_propagation_flags_from_string(rvalue); - if (flags == 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue); - return 0; - } - } - - c->mount_flags = flags; + r = mount_propagation_flags_from_string(rvalue, &c->mount_flags); + if (r < 0) + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue); return 0; } diff --git a/src/core/main.c b/src/core/main.c index 5f9b1acad3..02992c7324 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -904,7 +904,6 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_UNIT: - r = free_and_strdup(&arg_default_unit, optarg); if (r < 0) return log_error_errno(r, "Failed to set default unit %s: %m", optarg); diff --git a/src/core/manager.c b/src/core/manager.c index 1192b20b74..d83c5ef5e2 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2165,7 +2165,7 @@ static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint assert(m); assert(m->time_change_fd == fd); - log_struct(LOG_INFO, + log_struct(LOG_DEBUG, LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE), LOG_MESSAGE("Time has been changed"), NULL); diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 877bbb34fc..646757f9d9 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -821,6 +821,9 @@ static int run_gdb(sd_journal *j) { if (r < 0) return r; + /* Don't interfere with gdb and its handling of SIGINT. */ + (void) ignore_signals(SIGINT, -1); + pid = fork(); if (pid < 0) { r = log_error_errno(errno, "Failed to fork(): %m"); @@ -845,6 +848,8 @@ static int run_gdb(sd_journal *j) { r = st.si_code == CLD_EXITED ? st.si_status : 255; finish: + (void) default_signals(SIGINT, -1); + if (unlink_path) { log_debug("Removed temporary file %s", path); unlink(path); diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c index 1ee3471355..28ebe36b38 100644 --- a/src/debug-generator/debug-generator.c +++ b/src/debug-generator/debug-generator.c @@ -135,8 +135,9 @@ static int generate_wants_symlinks(void) { STRV_FOREACH(u, arg_wants) { _cleanup_free_ char *p = NULL, *f = NULL; + const char *target = arg_default_unit ?: SPECIAL_DEFAULT_TARGET; - p = strjoin(arg_dest, "/", arg_default_unit, ".wants/", *u); + p = strjoin(arg_dest, "/", target, ".wants/", *u); if (!p) return log_oom(); @@ -172,12 +173,6 @@ int main(int argc, char *argv[]) { umask(0022); - r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); - if (r < 0) { - log_error_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET); - goto finish; - } - r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); @@ -197,6 +192,7 @@ int main(int argc, char *argv[]) { r = q; finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + arg_default_unit = mfree(arg_default_unit); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 10d3ff3b45..ecd1e94a33 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2318,7 +2318,7 @@ int main(int argc, char *argv[]) { if (arg_boot_offset != 0 && sd_journal_has_runtime_files(j) > 0 && sd_journal_has_persistent_files(j) == 0) { - log_info("Specifying boot ID has no effect, no persistent journal was found"); + log_info("Specifying boot ID or boot offset has no effect, no persistent journal was found."); r = 0; goto finish; } diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c index 72cadf1771..0469393f3b 100644 --- a/src/journal/test-compress.c +++ b/src/journal/test-compress.c @@ -216,7 +216,11 @@ static void test_lz4_decompress_partial(void) { memset(huge, 'x', HUGE_SIZE); memcpy(huge, "HUGE=", 5); +#if LZ4_VERSION_NUMBER >= 10700 + r = LZ4_compress_default(huge, buf, HUGE_SIZE, buf_size); +#else r = LZ4_compress_limitedOutput(huge, buf, HUGE_SIZE, buf_size); +#endif assert_se(r >= 0); compressed = r; log_info("Compressed %i → %zu", HUGE_SIZE, compressed); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 3294ea7821..36c2607ba9 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2769,7 +2769,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argv); for (;;) { - static const char option_string[] = "-hp:als:H:M:qn:o:"; + static const char option_string[] = "-hp:als:H:M:qn:o:E:"; c = getopt_long(argc, argv, option_string + reorder, options, NULL); if (c < 0) diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 5320592f7a..5097ab9d72 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -118,7 +118,9 @@ static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { } r = sd_ndisc_router_get_mtu(rt, &mtu); - if (r < 0) { + if (r == -ENODATA) + mtu = 0; + else if (r < 0) { log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m"); return; } diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c index 2de87e3c63..38ab37367e 100644 --- a/src/nspawn/nspawn-stub-pid1.c +++ b/src/nspawn/nspawn-stub-pid1.c @@ -20,6 +20,7 @@ #include <sys/reboot.h> #include <sys/unistd.h> #include <sys/wait.h> +#include <sys/prctl.h> #include "fd-util.h" #include "log.h" @@ -29,7 +30,22 @@ #include "time-util.h" #include "def.h" -int stub_pid1(void) { +static int reset_environ(const char *new_environment, size_t length) { + unsigned long start, end; + + start = (unsigned long) new_environment; + end = start + length; + + if (prctl(PR_SET_MM, PR_SET_MM_ENV_START, start, 0, 0) < 0) + return -errno; + + if (prctl(PR_SET_MM, PR_SET_MM_ENV_END, end, 0, 0) < 0) + return -errno; + + return 0; +} + +int stub_pid1(sd_id128_t uuid) { enum { STATE_RUNNING, STATE_REBOOT, @@ -41,6 +57,11 @@ int stub_pid1(void) { pid_t pid; int r; + /* The new environment we set up, on the stack. */ + char new_environment[] = + "container=systemd-nspawn\0" + "container_uuid=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; + /* Implements a stub PID 1, that reaps all processes and processes a couple of standard signals. This is useful * for allowing arbitrary processes run in a container, and still have all zombies reaped. */ @@ -64,6 +85,12 @@ int stub_pid1(void) { close_all_fds(NULL, 0); log_open(); + /* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also, + * set $container= and $container_uuid= so that clients in the container that query it from /proc/1/environ + * find them set set. */ + sd_id128_to_string(uuid, new_environment + sizeof(new_environment) - SD_ID128_STRING_MAX); + reset_environ(new_environment, sizeof(new_environment)); + rename_process("STUBINIT"); assert_se(sigemptyset(&waitmask) >= 0); diff --git a/src/nspawn/nspawn-stub-pid1.h b/src/nspawn/nspawn-stub-pid1.h index 36c1aaf5dd..7ca83078c0 100644 --- a/src/nspawn/nspawn-stub-pid1.h +++ b/src/nspawn/nspawn-stub-pid1.h @@ -19,4 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int stub_pid1(void); +#include "sd-id128.h" + +int stub_pid1(sd_id128_t uuid); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 080bd7c31e..dcc639f15c 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2278,7 +2278,7 @@ static int inner_child( return log_error_errno(errno, "Failed to change to specified working directory %s: %m", arg_chdir); if (arg_start_mode == START_PID2) { - r = stub_pid1(); + r = stub_pid1(arg_uuid); if (r < 0) return r; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index b030b3b9d1..829be2c6da 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -579,15 +579,9 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen else if (streq(field, "MountFlags")) { unsigned long f; - if (isempty(eq)) - f = 0; - else { - f = mount_propagation_flags_from_string(eq); - if (f == 0) { - log_error("Failed to parse mount propagation type: %s", eq); - return -EINVAL; - } - } + r = mount_propagation_flags_from_string(eq, &f); + if (r < 0) + return log_error_errno(r, "Failed to parse mount propagation flags: %s", eq); r = sd_bus_message_append(m, "v", "t", f); } else if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) { diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c index a3d677f068..6ffb169b21 100644 --- a/src/system-update-generator/system-update-generator.c +++ b/src/system-update-generator/system-update-generator.c @@ -22,12 +22,12 @@ #include "fs-util.h" #include "log.h" +#include "special.h" #include "string-util.h" #include "util.h" /* - * Implements the logic described in - * http://freedesktop.org/wiki/Software/systemd/SystemUpdates + * Implements the logic described in systemd.offline-updates(7). */ static const char *arg_dest = "/tmp"; @@ -43,7 +43,7 @@ static int generate_symlink(void) { return -EINVAL; } - p = strjoina(arg_dest, "/default.target"); + p = strjoina(arg_dest, "/" SPECIAL_DEFAULT_TARGET); if (symlink(SYSTEM_DATA_UNIT_PATH "/system-update.target", p) < 0) return log_error_errno(errno, "Failed to create symlink %s: %m", p); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 67516cf5fb..f7e85c1ade 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2559,6 +2559,7 @@ static int unit_find_paths( } } else { _cleanup_set_free_ Set *names; + _cleanup_free_ char *template = NULL; names = set_new(NULL); if (!names) @@ -2569,8 +2570,6 @@ static int unit_find_paths( return r; if (r == 0) { - _cleanup_free_ char *template = NULL; - r = unit_name_template(unit_name, &template); if (r < 0 && r != -EINVAL) return log_error_errno(r, "Failed to determine template name: %m"); @@ -2581,7 +2580,22 @@ static int unit_find_paths( } } - r = set_put(names, basename(path)); + if (path) + /* We found the unit file. If we followed symlinks, this name might be + * different then the unit_name with started with. Look for dropins matching + * that "final" name. */ + r = set_put(names, basename(path)); + else if (!template) + /* No unit file, let's look for dropins matching the original name. + * systemd has fairly complicated rules (based on unit type and provenience), + * which units are allowed not to have the main unit file. We err on the + * side of including too many files, and always try to load dropins. */ + r = set_put(names, unit_name); + else + /* The cases where we allow a unit to exist without the main file are + * never valid for templates. Don't try to load dropins in this case. */ + goto not_found; + if (r < 0) return log_error_errno(r, "Failed to add unit name: %m"); @@ -2605,7 +2619,7 @@ static int unit_find_paths( dropins = NULL; r = 1; } - + not_found: if (r == 0 && !arg_force) log_error("No files found for %s.", unit_name); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 921fd478d0..9fde9b1884 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -292,8 +292,10 @@ static int sysv_translate_facility(SysvStub *s, unsigned line, const char *name, if (!streq(table[i], n)) continue; - if (!table[i+1]) + if (!table[i+1]) { + *ret = NULL; return 0; + } m = strdup(table[i+1]); if (!m) @@ -312,7 +314,7 @@ static int sysv_translate_facility(SysvStub *s, unsigned line, const char *name, if (r < 0) return log_error_errno(r, "[%s:%u] Could not build name for facility %s: %m", s->path, line, name); - return r; + return 1; } /* Strip ".sh" suffix from file name for comparison */ @@ -324,8 +326,10 @@ static int sysv_translate_facility(SysvStub *s, unsigned line, const char *name, } /* Names equaling the file name of the services are redundant */ - if (streq_ptr(n, filename)) + if (streq_ptr(n, filename)) { + *ret = NULL; return 0; + } /* Everything else we assume to be normal service names */ m = sysv_translate_name(n); diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index a98de76b43..d0bc8004f3 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -22,6 +22,7 @@ #include "install.h" #include "mkdir.h" #include "rm-rf.h" +#include "special.h" #include "string-util.h" static void test_basic_mask_and_enable(const char *root) { @@ -338,7 +339,7 @@ static void test_default(const char *root) { assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); - p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target"); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH "/" SPECIAL_DEFAULT_TARGET); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c index da7f35623b..7c5929d009 100644 --- a/src/test/test-mount-util.c +++ b/src/test/test-mount-util.c @@ -23,23 +23,35 @@ #include "mount-util.h" #include "string-util.h" -static void test_mount_propagation_flags(const char *name, unsigned long f) { - assert(mount_propagation_flags_from_string(name) == f); +static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) { + long unsigned flags; - if (f != 0) - assert_se(streq_ptr(mount_propagation_flags_to_string(f), name)); + assert(mount_propagation_flags_from_string(name, &flags) == ret); + + if (ret >= 0) { + const char *c; + + assert_se(flags == expected); + + c = mount_propagation_flags_to_string(flags); + if (isempty(name)) + assert_se(isempty(c)); + else + assert_se(streq(c, name)); + } } int main(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); - test_mount_propagation_flags("shared", MS_SHARED); - test_mount_propagation_flags("slave", MS_SLAVE); - test_mount_propagation_flags("private", MS_PRIVATE); - test_mount_propagation_flags(NULL, 0); - test_mount_propagation_flags("", 0); - test_mount_propagation_flags("xxxx", 0); + test_mount_propagation_flags("shared", 0, MS_SHARED); + test_mount_propagation_flags("slave", 0, MS_SLAVE); + test_mount_propagation_flags("private", 0, MS_PRIVATE); + test_mount_propagation_flags(NULL, 0, 0); + test_mount_propagation_flags("", 0, 0); + test_mount_propagation_flags("xxxx", -EINVAL, 0); + test_mount_propagation_flags(" ", -EINVAL, 0); return 0; } diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 7242b2c8b5..c5edbcc5d2 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -355,10 +355,70 @@ static void test_get_process_cmdline_harder(void) { _exit(0); } +static void test_rename_process_one(const char *p, int ret) { + _cleanup_free_ char *comm = NULL, *cmdline = NULL; + pid_t pid; + int r; + + pid = fork(); + assert_se(pid >= 0); + + if (pid > 0) { + siginfo_t si; + + assert_se(wait_for_terminate(pid, &si) >= 0); + assert_se(si.si_code == CLD_EXITED); + assert_se(si.si_status == EXIT_SUCCESS); + + return; + } + + /* child */ + r = rename_process(p); + + assert_se(r == ret || + (ret == 0 && r >= 0) || + (ret > 0 && r > 0)); + + if (r < 0) + goto finish; + +#ifdef HAVE_VALGRIND_VALGRIND_H + /* see above, valgrind is weird, we can't verify what we are doing here */ + if (RUNNING_ON_VALGRIND) + goto finish; +#endif + + assert_se(get_process_comm(0, &comm) >= 0); + log_info("comm = <%s>", comm); + assert_se(strneq(comm, p, 15)); + + assert_se(get_process_cmdline(0, 0, false, &cmdline) >= 0); + log_info("cmdline = <%s>", cmdline); + assert_se(strneq(p, cmdline, strlen("test-process-util"))); + assert_se(startswith(p, cmdline)); + +finish: + _exit(EXIT_SUCCESS); +} + +static void test_rename_process(void) { + test_rename_process_one(NULL, -EINVAL); + test_rename_process_one("", -EINVAL); + test_rename_process_one("foo", 1); /* should always fit */ + test_rename_process_one("this is a really really long process name, followed by some more words", 0); /* unlikely to fit */ + test_rename_process_one("1234567", 1); /* should always fit */ +} + int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); log_parse_environment(); log_open(); + saved_argc = argc; + saved_argv = argv; + if (argc > 1) { pid_t pid = 0; @@ -373,6 +433,7 @@ int main(int argc, char *argv[]) { test_pid_is_alive(); test_personality(); test_get_process_cmdline_harder(); + test_rename_process(); return 0; } |