login: do not wall message on cancelling shutdown when Manager.enable_wall_messages is false
Features:
+* nspawn: greater control over hostname, resolv.conf, timezone, rlim
+
+* nspawn: when operating in a scope, also create /payload subcrgoup
+
* the error paths in usbffs_dispatch_ep() leak memory
* cgroups: figure out if we can somehow communicate in a cleaner way whether a
* add --vacuum-xyz options to coredumpctl, matching those journalctl already has.
-* list the exit codes from the BSD/glibc <sysexits.h> in our own
- exit-codes.[ch] tables.
-
* SuccessExitStatus= and friends should probably also accept symbolic exit
codes names, i.e. error codes from the list maintained in exit-codes.[ch]
cgroup tree of systemd itself is out of limits for you. It's fine to *read*
from any attribute you like however. That's totally OK and welcome.
-4. 🚫 When not using `CLONE_NEWCGROUP` when delegating a sub-tree to a container
- payload running systemd, then don't get the idea that you can bind mount
- only a sub-tree of the host's cgroup tree into the container. Part of the
- cgroup API is that `/proc/$PID/cgroup` reports the cgroup path of every
+4. 🚫 When not using `CLONE_NEWCGROUP` when delegating a sub-tree to a
+ container payload running systemd, then don't get the idea that you can bind
+ mount only a sub-tree of the host's cgroup tree into the container. Part of
+ the cgroup API is that `/proc/$PID/cgroup` reports the cgroup path of every
process, and hence any path below `/sys/fs/cgroup/` needs to match what
`/proc/$PID/cgroup` of the payload processes reports. What you can do safely
- however, is mount the upper parts of the cgroup tree read-only or even
- replace it with an intermediary `tmpfs`, as long as the path to the
- delegated sub-tree remains accessible as-is.
+ however, is mount the upper parts of the cgroup tree read-only (or even
+ replace the middle bits with an intermediary `tmpfs` — but be careful not to
+ break the `statfs()` detection logic discussed above), as long as the path
+ to the delegated sub-tree remains accessible as-is.
5. âš¡ Currently, the algorithm for mapping between slice/scope/service unit
naming and their cgroup paths is not considered public API of systemd, and
pre-defined purposes between Linux, generic low-level distributions and
`systemd`. There might very well be other packages that allocate from these
ranges.
+
+## Notes on resolvability of user and group names
+
+User names, UIDs, group names and GIDs don't have to be resolvable using NSS
+(i.e. getpwuid() and getpwnam() and friends) all the time. However, systemd
+makes the following requirements:
+
+System users generally have to be resolvable during early boot already. This
+means they should not be provided by any networked service (as those usually
+become available during late boot only), except if a local cache is kept that
+makes them available during early boot too (i.e. before networking is
+up). Specifically, system users need to be resolvable at least before
+`systemd-udevd.service` and `systemd-tmpfiles.service` are started, as both
+need to resolve system users — but note that there might be more services
+requiring full resolvability of system users than just these two.
+
+Regular users do not need to be resolvable during early boot, it is sufficient
+if they become resolvable during late boot. Specifically, regular users need to
+be resolvable at the point in time the `nss-user-lookup.target` unit is
+reached. This target unit is generally used as synchronization point between
+providers of the user database and consumers of it. Services that require that
+the user database is fully available (for example, the login service
+`systemd-logind.service`) are ordered *after* it, while services that provide
+parts of the user database (for example an LDAP user database client) are
+ordered *before* it. Note that `nss-user-lookup.target` is a *passive* unit: in
+order to minimize synchronization points on systems that don't need it the unit
+is pulled into the initial transaction only if there's at least one service
+that really needs it, and that means only if there's a service providing the
+local user database somehow through IPC or suchlike. Or in other words: if you
+hack on some networked user database project, then make sure you order your
+service `Before=nss-user-lookup.target` and that you pull it in with
+`Wants=nss-user-lookup.target`. However, if you hack on some project that needs
+the user database to be up in full, then order your service
+`After=nss-user-lookup.target`, but do *not* pull it in via a `Wants=`
+dependency.
<varlistentry>
<term><varname>ServerCertificateFile=</varname></term>
- <listitem><para>SSL CA certificate in PEM format.</para></listitem>
+ <listitem><para>SSL certificate in PEM format.</para></listitem>
</varlistentry>
<varlistentry>
<refsect1>
<title>See Also</title>
<para>
- <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journal-remote.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
<listitem><para>The URL to upload the journal entries to. See the description
of <varname>--url=</varname> option in
<citerefentry><refentrytitle>systemd-journal-upload</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- for the description of possible values.</para></listitem>
+ for the description of possible values. There is no default value, so either this
+ option or the command-line option must be always present to make an upload.</para></listitem>
</varlistentry>
<varlistentry>
<refsect1>
<title>See Also</title>
<para>
- <citerefentry><refentrytitle>systemd-journal-upload</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journal-upload.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
<citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-journal-upload</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd-journal-remote.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journal-upload.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
'8',
['systemd-journal-gatewayd', 'systemd-journal-gatewayd.socket'],
'HAVE_MICROHTTPD'],
- ['systemd-journal-remote', '8', [], 'HAVE_MICROHTTPD'],
- ['systemd-journal-upload', '8', [], 'HAVE_MICROHTTPD'],
+ ['systemd-journal-remote.service',
+ '8',
+ ['systemd-journal-remote', 'systemd-journal-remote.socket'],
+ 'HAVE_MICROHTTPD'],
+ ['systemd-journal-upload.service',
+ '8',
+ ['systemd-journal-upload'],
+ 'HAVE_MICROHTTPD'],
['systemd-journald.service',
'8',
['systemd-journald',
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
- <title>systemd-journal-remote</title>
+ <title>systemd-journal-remote.service</title>
<productname>systemd</productname>
<authorgroup>
</refentryinfo>
<refmeta>
- <refentrytitle>systemd-journal-remote</refentrytitle>
+ <refentrytitle>systemd-journal-remote.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
+ <refname>systemd-journal-remote.service</refname>
+ <refname>systemd-journal-remote.socket</refname>
<refname>systemd-journal-remote</refname>
<refpurpose>Receive journal messages over the network</refpurpose>
</refnamediv>
<refsynopsisdiv>
+ <para><filename>systemd-journal-remote.service</filename></para>
+ <para><filename>systemd-journal-remote.socket</filename></para>
<cmdsynopsis>
- <command>systemd-journal-remote</command>
+ <command>/usr/lib/systemd/systemd-journal-remote</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="norepeat">-o/--output=<replaceable>DIR</replaceable>|<replaceable>FILE</replaceable></arg>
<arg choice="opt" rep="repeat">SOURCES</arg>
<refsect1>
<title>Description</title>
- <para>
- <filename>systemd-journal-remote</filename> is a command to
- receive serialized journal events and store them to the journal.
- Input streams are in the
- <ulink url="https://www.freedesktop.org/wiki/Software/systemd/export">
- Journal Export Format
- </ulink>,
- i.e. like the output from
- <command>journalctl --output=export</command>. For transport over
- the network, this serialized stream is usually carried over an
- HTTPS connection.
- </para>
+ <para><command>systemd-journal-remote</command> is a command to receive serialized journal
+ events and store them to journal files. Input streams are in the
+ <ulink url="https://www.freedesktop.org/wiki/Software/systemd/export">Journal Export Format</ulink>,
+ i.e. like the output from <command>journalctl --output=export</command>. For transport over the
+ network, this serialized stream is usually carried over an HTTPS connection.</para>
+
+ <para><filename>systemd-journal-remote.service</filename> is a system service that uses
+ <command>systemd-journal-remote</command> to listen for connections.
+ <filename>systemd-journal-remote.socket</filename> configures the network address that
+ <filename>systemd-journal-remote.service</filename> listens on. By default this is port 19532.
+ What connections are accepted and how the received data is stored can be configured through the
+ <citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ configuration file.</para>
</refsect1>
<refsect1>
interpreted as the (negated) file descriptor number, or an
address suitable for <option>ListenStream=</option> (c.f.
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
- In the first case, matching file descriptor must be inherited
- through
+ In the first case, the server listens on port 19532 by default,
+ and the matching file descriptor must be inherited through
<varname>$LISTEN_FDS</varname>/<varname>$LISTEN_PID</varname>.
In the second case, an HTTP or HTTPS server will be spawned on
this port, respectively for <option>--listen-http=</option> and
<refsect1>
<title>See Also</title>
<para>
- <citerefentry><refentrytitle>systemd-journal-upload</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-journal-gatewayd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
- <citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd-journal-gatewayd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journal-upload.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
- <title>systemd-journal-upload</title>
+ <title>systemd-journal-upload.service</title>
<productname>systemd</productname>
<authorgroup>
</refentryinfo>
<refmeta>
- <refentrytitle>systemd-journal-upload</refentrytitle>
+ <refentrytitle>systemd-journal-upload.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
+ <refname>systemd-journal-upload.service</refname>
<refname>systemd-journal-upload</refname>
<refpurpose>Send journal messages over the network</refpurpose>
</refnamediv>
<refsynopsisdiv>
+ <para><filename>systemd-journal-upload.service</filename></para>
<cmdsynopsis>
- <command>systemd-journal-upload</command>
+ <command>/usr/lib/systemd/systemd-journal-upload</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="norepeat">-u/--url=<replaceable>URL</replaceable></arg>
<arg choice="opt" rep="repeat">SOURCES</arg>
Unless limited by one of the options specified below, all journal entries accessible to the user
the program is running as will be uploaded, and then the program will wait and send new entries
as they become available.</para>
+
+ <para><filename>systemd-journal-upload.service</filename> is a system service that uses
+ <command>systemd-journal-upload</command> to upload journal entries to a server. It uses the
+ configuration in
+ <citerefentry><refentrytitle>journal-upload.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ At least the <varname>URL=</varname> option must be specified.</para>
</refsect1>
<refsect1>
<variablelist>
<varlistentry>
<term><option>-u</option></term>
- <term><option>--url=<optional>https://</optional><replaceable>URL</replaceable></option></term>
- <term><option>--url=<optional>http://</optional><replaceable>URL</replaceable></option></term>
+ <term><option>--url=<optional>https://</optional><replaceable>URL</replaceable>[:<replaceable>PORT</replaceable>]</option></term>
+ <term><option>--url=<optional>http://</optional><replaceable>URL</replaceable>[:<replaceable>PORT</replaceable>]</option></term>
<listitem><para>Upload to the specified
address. <replaceable>URL</replaceable> may specify either
just the hostname or both the protocol and
hostname. <constant>https</constant> is the default.
+ The port number may be specified after a colon (<literal>:</literal>),
+ otherwise <constant>19532</constant> will be used by default.
</para></listitem>
</varlistentry>
<refsect1>
<title>See Also</title>
<para>
- <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd-journal-remote.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-journal-gatewayd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<refentry id="systemd-networkd-wait-online.service" conditional='ENABLE_NETWORKD'>
<refentryinfo>
- <title>systemd-networkd.service</title>
+ <title>systemd-networkd-wait-online.service</title>
<productname>systemd</productname>
<authorgroup>
Defaults to "unset".</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RxChannels=</varname></term>
+ <listitem>
+ <para>Sets the number of receive channels (a number between 1 and 4294967295) .</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>TxChannels=</varname></term>
+ <listitem>
+ <para>Sets the number of transmit channels (a number between 1 and 4294967295).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>OtherChannels=</varname></term>
+ <listitem>
+ <para>Sets the number of other channels (a number between 1 and 4294967295).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>CombinedChannels=</varname></term>
+ <listitem>
+ <para>Sets the number of combined set channels (a number between 1 and 4294967295).</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>UserClass=</varname></term>
+ <listitem>
+ <para>A DHCPv4 client can use UserClass option to identify the type or category of user or applications
+ it represents. The information contained in this option is a string that represents the user class of which
+ the client is a member. Each class sets an identifying string of information to be used by the DHCP
+ service to classify clients. Takes a whitespace-separated list of strings.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>DUIDType=</varname></term>
<listitem>
<varlistentry>
<term><filename>nss-lookup.target</filename></term>
<listitem>
- <para>A target that should be used as synchronization point
- for all host/network name service lookups. Note that this is
- independent of user/group name lookups for which
- <filename>nss-user-lookup.target</filename> should be used.
- All services for which the availability of full host/network
- name resolution is essential should be ordered after this
- target, but not pull it in. systemd automatically adds
- dependencies of type <varname>After=</varname> for this
- target unit to all SysV init script service units with an
- LSB header referring to the <literal>$named</literal>
- facility.</para>
+ <para>A target that should be used as synchronization point for all host/network name service lookups. Note
+ that this is independent of UNIX user/group name lookups for which <filename>nss-user-lookup.target</filename>
+ should be used. All services for which the availability of full host/network name resolution is essential
+ should be ordered after this target, but not pull it in. systemd automatically adds dependencies of type
+ <varname>After=</varname> for this target unit to all SysV init script service units with an LSB header
+ referring to the <literal>$named</literal> facility.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>nss-user-lookup.target</filename></term>
<listitem>
- <para>A target that should be used as synchronization point
- for all user/group name service lookups. Note that this is
- independent of host/network name lookups for which
- <filename>nss-lookup.target</filename> should be used. All
- services for which the availability of the full user/group
- database is essential should be ordered after this target,
- but not pull it in. Note that system users are always
- resolvable, and hence do not require any special ordering
- against this target.</para>
+ <para>A target that should be used as synchronization point for all regular UNIX user/group name service
+ lookups. Note that this is independent of host/network name lookups for which
+ <filename>nss-lookup.target</filename> should be used. All services for which the availability of the full
+ user/group database is essential should be ordered after this target, but not pull it in. All services which
+ provide parts of the user/group database should be ordered before this target, and pull it in. Note that this
+ unit is only relevant for regular users and groups — system users and groups are required to be resolvable
+ during earliest boot already, and hence do not need any special ordering against this target.</para>
</listitem>
</varlistentry>
<varlistentry>
libsystemd_version = '0.22.0'
libudev_version = '1.6.10'
-# We need the same data in three different formats, ugh!
+# We need the same data in two different formats, ugh!
# Also, for hysterical reasons, we use different variable
# names, sometimes. Not all variables are included in every
# set. Ugh, ugh, ugh!
substs.set('PACKAGE_URL', 'https://www.freedesktop.org/wiki/Software/systemd')
substs.set('PACKAGE_VERSION', meson.project_version())
-m4_defines = []
-
#####################################################################
# Try to install the git pre-commit hook
sysvinit_path = get_option('sysvinit-path')
sysvrcnd_path = get_option('sysvrcnd-path')
-have = sysvinit_path != '' and sysvrcnd_path != ''
-conf.set10('HAVE_SYSV_COMPAT', have,
+conf.set10('HAVE_SYSV_COMPAT', sysvinit_path != '' and sysvrcnd_path != '',
description : 'SysV init scripts and rcN.d links are supported')
-m4_defines += have ? ['-DHAVE_SYSV_COMPAT'] : []
# join_paths ignore the preceding arguments if an absolute component is
# encountered, so this should canonicalize various paths when they are
endif
substs.set('USERS_GID', users_gid)
-if get_option('adm-group')
- m4_defines += ['-DENABLE_ADM_GROUP']
-endif
-
-if get_option('wheel-group')
- m4_defines += ['-DENABLE_WHEEL_GROUP']
-endif
+conf.set10('ENABLE_ADM_GROUP', get_option('adm-group'))
+conf.set10('ENABLE_WHEEL_GROUP', get_option('wheel-group'))
substs.set('DEV_KVM_MODE', get_option('dev-kvm-mode'))
substs.set('GROUP_RENDER_MODE', get_option('group-render-mode'))
libseccomp = []
endif
conf.set10('HAVE_SECCOMP', have)
-m4_defines += have ? ['-DHAVE_SECCOMP'] : []
want_selinux = get_option('selinux')
if want_selinux != 'false' and not fuzzer_build
libselinux = []
endif
conf.set10('HAVE_SELINUX', have)
-m4_defines += have ? ['-DHAVE_SELINUX'] : []
want_apparmor = get_option('apparmor')
if want_apparmor != 'false' and not fuzzer_build
libapparmor = []
endif
conf.set10('HAVE_APPARMOR', have)
-m4_defines += have ? ['-DHAVE_APPARMOR'] : []
smack_run_label = get_option('smack-run-label')
if smack_run_label != ''
conf.set_quoted('SMACK_RUN_LABEL', smack_run_label)
- m4_defines += ['-DHAVE_SMACK_RUN_LABEL']
endif
want_polkit = get_option('polkit')
libacl = []
endif
conf.set10('HAVE_ACL', have)
-m4_defines += have ? ['-DHAVE_ACL'] : []
want_audit = get_option('audit')
if want_audit != 'false' and not fuzzer_build
libpam_misc = []
endif
conf.set10('HAVE_PAM', have)
-m4_defines += have ? ['-DHAVE_PAM'] : []
want_microhttpd = get_option('microhttpd')
if want_microhttpd != 'false' and not fuzzer_build
libmicrohttpd = []
endif
conf.set10('HAVE_MICROHTTPD', have)
-m4_defines += have ? ['-DHAVE_MICROHTTPD'] : []
want_libcryptsetup = get_option('libcryptsetup')
if want_libcryptsetup != 'false' and not fuzzer_build
libcurl = []
endif
conf.set10('HAVE_LIBCURL', have)
-m4_defines += have ? ['-DHAVE_LIBCURL'] : []
want_libidn = get_option('libidn')
want_libidn2 = get_option('libidn2')
libidn = []
endif
conf.set10('HAVE_LIBIDN', have)
-m4_defines += have ? ['-DHAVE_LIBIDN'] : []
if not have and want_libidn2 != 'false' and not fuzzer_build
# libidn is used for both libidn and libidn2 objects
libidn = dependency('libidn2',
have = false
endif
conf.set10('HAVE_LIBIDN2', have)
-m4_defines += have ? ['-DHAVE_LIBIDN2'] : []
want_libiptc = get_option('libiptc')
if want_libiptc != 'false' and not fuzzer_build
libiptc = []
endif
conf.set10('HAVE_LIBIPTC', have)
-m4_defines += have ? ['-DHAVE_LIBIPTC'] : []
want_qrencode = get_option('qrencode')
if want_qrencode != 'false' and not fuzzer_build
have = get_option(term)
name = 'ENABLE_' + term.underscorify().to_upper()
conf.set10(name, have)
- m4_defines += have ? ['-D' + name] : []
endforeach
-if get_option('timedated') or get_option('timesyncd')
- conf.set10('ENABLE_TIMEDATECTL', true)
- m4_defines += ['-DENABLE_TIMEDATECTL']
-else
- conf.set10('ENABLE_TIMEDATECTL', false)
-endif
+conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesyncd'))
want_tests = get_option('tests')
install_tests = get_option('install-tests')
output : 'config.h',
configuration : conf)
+meson_apply_m4 = find_program('tools/meson-apply-m4.sh')
+
includes = include_directories('src/basic',
'src/shared',
'src/systemd',
'load-fragment-gperf.gperf',
input : 'load-fragment-gperf.gperf.m4',
output: 'load-fragment-gperf.gperf',
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true)
load_fragment_gperf_c = custom_target(
/* ProtectKernelTunables= option and the related filesystem APIs */
static const MountEntry protect_kernel_tunables_table[] = {
- { "/proc/sys", READONLY, false },
- { "/proc/sysrq-trigger", READONLY, true },
- { "/proc/latency_stats", READONLY, true },
- { "/proc/mtrr", READONLY, true },
- { "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
{ "/proc/acpi", READONLY, true },
- { "/proc/timer_stats", READONLY, true },
+ { "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
{ "/proc/asound", READONLY, true },
{ "/proc/bus", READONLY, true },
{ "/proc/fs", READONLY, true },
{ "/proc/irq", READONLY, true },
+ { "/proc/kallsyms", INACCESSIBLE, true },
+ { "/proc/kcore", INACCESSIBLE, true },
+ { "/proc/latency_stats", READONLY, true },
+ { "/proc/mtrr", READONLY, true },
+ { "/proc/scsi", READONLY, true },
+ { "/proc/sys", READONLY, false },
+ { "/proc/sysrq-trigger", READONLY, true },
+ { "/proc/timer_stats", READONLY, true },
{ "/sys", READONLY, false },
- { "/sys/kernel/debug", READONLY, true },
- { "/sys/kernel/tracing", READONLY, true },
{ "/sys/fs/bpf", READONLY, true },
{ "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
{ "/sys/fs/selinux", READWRITE, true },
+ { "/sys/kernel/debug", READONLY, true },
+ { "/sys/kernel/tracing", READONLY, true },
};
/* ProtectKernelModules= option */
#include "alloc-util.h"
#include "utf8.h"
+#include "strv.h"
#include "dhcp-internal.h"
*offset += 1;
break;
+ case SD_DHCP_OPTION_USER_CLASS: {
+ size_t len = 0;
+ char **s;
+
+ STRV_FOREACH(s, (char **) optval)
+ len += strlen(*s) + 1;
+
+ if (size < *offset + len + 2)
+ return -ENOBUFS;
+
+ options[*offset] = code;
+ options[*offset + 1] = len;
+ *offset += 2;
+
+ STRV_FOREACH(s, (char **) optval) {
+ len = strlen(*s);
+
+ if (len > 255)
+ return -ENAMETOOLONG;
+
+ options[*offset] = len;
+
+ memcpy_safe(&options[*offset + 1], *s, len);
+ *offset += len + 1;
+ }
+
+ break;
+ }
default:
if (size < *offset + optlen + 2)
return -ENOBUFS;
#include "random-util.h"
#include "string-util.h"
#include "util.h"
+#include "strv.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
size_t client_id_len;
char *hostname;
char *vendor_class_identifier;
+ char **user_class;
uint32_t mtu;
uint32_t xid;
usec_t start_time;
return free_and_strdup(&client->vendor_class_identifier, vci);
}
+int sd_dhcp_client_set_user_class(
+ sd_dhcp_client *client,
+ const char* const* user_class) {
+
+ _cleanup_strv_free_ char **s = NULL;
+ char **p;
+
+ STRV_FOREACH(p, (char **) user_class)
+ if (strlen(*p) > 255)
+ return -ENAMETOOLONG;
+
+ s = strv_copy((char **) user_class);
+ if (!s)
+ return -ENOMEM;
+
+ client->user_class = TAKE_PTR(s);
+
+ return 0;
+}
+
int sd_dhcp_client_set_client_port(
sd_dhcp_client *client,
uint16_t port) {
return r;
}
+ if (client->user_class) {
+ r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
+ SD_DHCP_OPTION_USER_CLASS,
+ strv_length(client->user_class),
+ client->user_class);
+ if (r < 0)
+ return r;
+ }
+
r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0,
SD_DHCP_OPTION_END, 0, NULL);
if (r < 0)
free(client->req_opts);
free(client->hostname);
free(client->vendor_class_identifier);
+ client->user_class = strv_free(client->user_class);
return mfree(client);
}
'73-seat-late.rules',
input : '73-seat-late.rules.m4',
output: '73-seat-late.rules',
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true,
install : true,
install_dir : udevrulesdir)
'systemd-user',
input : 'systemd-user.m4',
output: 'systemd-user',
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true,
install : pamconfdir != 'no',
install_dir : pamconfdir)
return r;
}
+ if (link->network->dhcp_user_class) {
+ r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class);
+ if (r < 0)
+ return r;
+ }
+
if (link->network->dhcp_client_port) {
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
if (r < 0)
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
+DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
free(network->description);
free(network->dhcp_vendor_class_identifier);
+ strv_free(network->dhcp_user_class);
free(network->dhcp_hostname);
free(network->mac);
return 0;
}
+int config_parse_dhcp_user_class(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char ***l = data;
+ int r;
+
+ assert(l);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *l = strv_free(*l);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+
+ r = extract_first_word(&rvalue, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ if (strlen(w) > 255) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
+ continue;
+ }
+
+ r = strv_push(l, w);
+ if (r < 0)
+ return log_oom();
+
+ w = NULL;
+ }
+
+ return 0;
+}
+
int config_parse_dhcp_route_table(const char *unit,
const char *filename,
unsigned line,
AddressFamilyBoolean dhcp;
DHCPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
+ char **dhcp_user_class;
char *dhcp_hostname;
unsigned dhcp_route_metric;
uint32_t dhcp_route_table;
int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_dhcp_route_table(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_dhcp_route_table(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);int config_parse_dhcp_user_class(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
return r;
}
-int create_subcgroup(pid_t pid, CGroupUnified unified_requested) {
+int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested) {
_cleanup_free_ char *cgroup = NULL;
- const char *child;
- int r;
CGroupMask supported;
+ const char *payload;
+ int r;
- /* In the unified hierarchy inner nodes may only contain
- * subgroups, but not processes. Hence, if we running in the
- * unified hierarchy and the container does the same, and we
- * did not create a scope unit for the container move us and
- * the container into two separate subcgroups. */
-
- if (unified_requested == CGROUP_UNIFIED_NONE)
- return 0;
-
- r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
- if (r < 0)
- return log_error_errno(r, "Failed to determine whether the systemd controller is unified: %m");
- if (r == 0)
- return 0;
+ assert(pid > 1);
+
+ /* In the unified hierarchy inner nodes may only contain subgroups, but not processes. Hence, if we running in
+ * the unified hierarchy and the container does the same, and we did not create a scope unit for the container
+ * move us and the container into two separate subcgroups.
+ *
+ * Moreover, container payloads such as systemd try to manage the cgroup they run in in full (i.e. including
+ * its attributes), while the host systemd will only delegate cgroups for children of the cgroup created for a
+ * delegation unit, instead of the cgroup itself. This means, if we'd pass on the cgroup allocated from the
+ * host systemd directly to the payload, the host and payload systemd might fight for the cgroup
+ * attributes. Hence, let's insert an intermediary cgroup to cover that case too.
+ *
+ * Note that we only bother with the main hierarchy here, not with any secondary ones. On the unified setup
+ * that's fine because there's only one hiearchy anyway and controllers are enabled directly on it. On the
+ * legacy setup, this is fine too, since delegation of controllers is generally not safe there, hence we won't
+ * do it. */
r = cg_mask_supported(&supported);
if (r < 0)
return log_error_errno(r, "Failed to determine supported controllers: %m");
- r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
+ if (keep_unit)
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &cgroup);
+ else
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
if (r < 0)
return log_error_errno(r, "Failed to get our control group: %m");
- child = strjoina(cgroup, "/payload");
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, child, pid);
+ payload = strjoina(cgroup, "/payload");
+ r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, payload, pid);
if (r < 0)
- return log_error_errno(r, "Failed to create %s subcgroup: %m", child);
+ return log_error_errno(r, "Failed to create %s subcgroup: %m", payload);
- child = strjoina(cgroup, "/supervisor");
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, child, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to create %s subcgroup: %m", child);
+ if (keep_unit) {
+ const char *supervisor;
+
+ supervisor = strjoina(cgroup, "/supervisor");
+ r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, supervisor, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create %s subcgroup: %m", supervisor);
+ }
/* Try to enable as many controllers as possible for the new payload. */
(void) cg_enable_everywhere(supported, supported, cgroup);
int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
-int create_subcgroup(pid_t pid, CGroupUnified unified_requested);
+int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested);
#include "user-util.h"
#include "util.h"
-CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t) {
+CustomMount* custom_mount_add(CustomMount **l, size_t *n, CustomMountType t) {
CustomMount *c, *ret;
assert(l);
return ret;
}
-void custom_mount_free_all(CustomMount *l, unsigned n) {
- unsigned i;
+void custom_mount_free_all(CustomMount *l, size_t n) {
+ size_t i;
for (i = 0; i < n; i++) {
CustomMount *m = l + i;
return strdup(source);
}
-int custom_mount_prepare_all(const char *dest, CustomMount *l, unsigned n) {
- unsigned i;
+int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) {
+ size_t i;
int r;
/* Prepare all custom mounts. This will make source we know all temporary directories. This is called in the
if (!s)
return log_oom();
- free(m->source);
- m->source = s;
+ free_and_replace(m->source, s);
} else {
/* No source specified? In that case, use a throw-away temporary directory in /var/tmp */
if (!s)
return log_oom();
- free(*j);
- *j = s;
+ free_and_replace(*j, s);
}
if (m->work_dir) {
if (!s)
return log_oom();
- free(m->work_dir);
- m->work_dir = s;
+ free_and_replace(m->work_dir, s);
} else {
assert(m->source);
return 0;
}
-int bind_mount_parse(CustomMount **l, unsigned *n, const char *s, bool read_only) {
+int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only) {
_cleanup_free_ char *source = NULL, *destination = NULL, *opts = NULL;
const char *p = s;
CustomMount *m;
return 0;
}
-int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s) {
+int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s) {
_cleanup_free_ char *path = NULL, *opts = NULL;
const char *p = s;
CustomMount *m;
return 0;
}
-int overlay_mount_parse(CustomMount **l, unsigned *n, const char *s, bool read_only) {
+int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only) {
_cleanup_free_ char *upper = NULL, *destination = NULL;
_cleanup_strv_free_ char **lower = NULL;
CustomMount *m;
uid_t uid_shift, uid_t uid_range,
const char *selinux_apifs_context) {
+#define PROC_INACCESSIBLE(path) \
+ { NULL, (path), NULL, NULL, MS_BIND, \
+ MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO|MOUNT_INACCESSIBLE_REG }, /* Bind mount first ... */ \
+ { NULL, (path), NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, \
+ MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO } /* Then, make it r/o */
+
+#define PROC_READ_ONLY(path) \
+ { (path), (path), NULL, NULL, MS_BIND, \
+ MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */ \
+ { NULL, (path), NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, \
+ MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO } /* Then, make it r/o */
+
typedef struct MountPoint {
const char *what;
const char *where;
} MountPoint;
static const MountPoint mount_table[] = {
- /* inner child mounts */
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, MOUNT_FATAL|MOUNT_IN_USERNS },
- { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */
- { "/proc/sys/net", "/proc/sys/net", NULL, NULL, MS_BIND, MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_APIVFS_NETNS }, /* (except for this) */
- { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* ... then, make it r/o */
- { "/proc/sysrq-trigger", "/proc/sysrq-trigger", NULL, NULL, MS_BIND, MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */
- { NULL, "/proc/sysrq-trigger", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* ... then, make it r/o */
-
- /* outer child mounts */
- { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, MOUNT_FATAL },
- { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS },
- { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO }, /* skipped if above was mounted */
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, MOUNT_FATAL }, /* skipped if above was mounted */
-
- { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, MOUNT_FATAL },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, MOUNT_FATAL },
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, MOUNT_FATAL },
+ /* First we list inner child mounts (i.e. mounts applied *after* entering user namespacing) */
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_IN_USERNS },
+
+ { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND,
+ MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */
+
+ { "/proc/sys/net", "/proc/sys/net", NULL, NULL, MS_BIND,
+ MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_APIVFS_NETNS }, /* (except for this) */
+
+ { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ MOUNT_FATAL|MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* ... then, make it r/o */
+
+ /* Make these files inaccessible to container payloads: they potentially leak information about kernel
+ * internals or the host's execution environment to the container */
+ PROC_INACCESSIBLE("/proc/kallsyms"),
+ PROC_INACCESSIBLE("/proc/kcore"),
+ PROC_INACCESSIBLE("/proc/keys"),
+ PROC_INACCESSIBLE("/proc/sysrq-trigger"),
+ PROC_INACCESSIBLE("/proc/timer_list"),
+
+ /* Make these directories read-only to container payloads: they show hardware information, and in some
+ * cases contain tunables the container really shouldn't have access to. */
+ PROC_READ_ONLY("/proc/acpi"),
+ PROC_READ_ONLY("/proc/apm"),
+ PROC_READ_ONLY("/proc/asound"),
+ PROC_READ_ONLY("/proc/bus"),
+ PROC_READ_ONLY("/proc/fs"),
+ PROC_READ_ONLY("/proc/irq"),
+ PROC_READ_ONLY("/proc/scsi"),
+
+ /* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing) */
+ { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ MOUNT_FATAL },
+ { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_APPLY_APIVFS_NETNS },
+ { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL|MOUNT_APPLY_APIVFS_RO }, /* skipped if above was mounted */
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ MOUNT_FATAL }, /* skipped if above was mounted */
+ { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME,
+ MOUNT_FATAL },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ MOUNT_FATAL },
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ MOUNT_FATAL },
+
#if HAVE_SELINUX
- { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, 0 }, /* Bind mount first */
- { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, 0 }, /* Then, make it r/o */
+ { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND,
+ 0 }, /* Bind mount first */
+ { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT,
+ 0 }, /* Then, make it r/o */
#endif
};
- unsigned k;
- int r;
+ _cleanup_(unlink_and_freep) char *inaccessible = NULL;
bool use_userns = (mount_settings & MOUNT_USE_USERNS);
bool netns = (mount_settings & MOUNT_APPLY_APIVFS_NETNS);
bool ro = (mount_settings & MOUNT_APPLY_APIVFS_RO);
bool in_userns = (mount_settings & MOUNT_IN_USERNS);
+ size_t k;
+ int r;
for (k = 0; k < ELEMENTSOF(mount_table); k++) {
_cleanup_free_ char *where = NULL, *options = NULL;
- const char *o;
+ const char *o, *what;
bool fatal = (mount_table[k].mount_settings & MOUNT_FATAL);
if (in_userns != (bool)(mount_table[k].mount_settings & MOUNT_IN_USERNS))
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
+ if (mount_table[k].mount_settings & MOUNT_INACCESSIBLE_REG) {
+
+ if (!inaccessible) {
+ _cleanup_free_ char *np = NULL;
+
+ r = tempfn_random_child(NULL, "inaccessible", &np);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate inaccessible file node path: %m");
+
+ r = touch_file(np, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0000);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create inaccessible file node '%s': %m", np);
+
+ inaccessible = TAKE_PTR(np);
+ }
+
+ what = inaccessible;
+ } else
+ what = mount_table[k].what;
+
r = path_is_mount_point(where, NULL, 0);
if (r < 0 && r != -ENOENT)
return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
/* Skip this entry if it is not a remount. */
- if (mount_table[k].what && r > 0)
+ if (what && r > 0)
continue;
r = mkdir_userns_p(dest, where, 0755, mount_settings, uid_shift);
}
r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
- mount_table[k].what,
+ what,
where,
mount_table[k].type,
mount_table[k].flags,
int mount_custom(
const char *dest,
- CustomMount *mounts, unsigned n,
+ CustomMount *mounts, size_t n,
bool userns, uid_t uid_shift, uid_t uid_range,
const char *selinux_apifs_context) {
- unsigned i;
+ size_t i;
int r;
assert(dest);
#include "volatile-util.h"
typedef enum MountSettingsMask {
- MOUNT_FATAL = 1 << 0, /* if set, a mount error is considered fatal */
- MOUNT_USE_USERNS = 1 << 1, /* if set, mounts are patched considering uid/gid shifts in a user namespace */
- MOUNT_IN_USERNS = 1 << 2, /* if set, the mount is executed in the inner child, otherwise in the outer child */
- MOUNT_APPLY_APIVFS_RO = 1 << 3, /* if set, /proc/sys, and /sysfs will be mounted read-only, otherwise read-write. */
- MOUNT_APPLY_APIVFS_NETNS = 1 << 4, /* if set, /proc/sys/net will be mounted read-write.
- Works only if MOUNT_APPLY_APIVFS_RO is also set. */
+ MOUNT_FATAL = 1U << 0, /* if set, a mount error is considered fatal */
+ MOUNT_USE_USERNS = 1U << 1, /* if set, mounts are patched considering uid/gid shifts in a user namespace */
+ MOUNT_IN_USERNS = 1U << 2, /* if set, the mount is executed in the inner child, otherwise in the outer child */
+ MOUNT_APPLY_APIVFS_RO = 1U << 3, /* if set, /proc/sys, and /sys will be mounted read-only, otherwise read-write. */
+ MOUNT_APPLY_APIVFS_NETNS = 1U << 4, /* if set, /proc/sys/net will be mounted read-write.
+ Works only if MOUNT_APPLY_APIVFS_RO is also set. */
+ MOUNT_INACCESSIBLE_REG = 1U << 5, /* if set, create an inaccessible regular file first and use as bind mount source */
} MountSettingsMask;
typedef enum CustomMountType {
char *rm_rf_tmpdir;
} CustomMount;
-CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t);
-void custom_mount_free_all(CustomMount *l, unsigned n);
-int custom_mount_prepare_all(const char *dest, CustomMount *l, unsigned n);
+CustomMount* custom_mount_add(CustomMount **l, size_t *n, CustomMountType t);
+void custom_mount_free_all(CustomMount *l, size_t n);
+int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n);
-int bind_mount_parse(CustomMount **l, unsigned *n, const char *s, bool read_only);
-int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s);
-int overlay_mount_parse(CustomMount **l, unsigned *n, const char *s, bool read_only);
+int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
+int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s);
+int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
int mount_cgroups(const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool use_cgns);
int mount_systemd_cgroup_writable(const char *dest, CGroupUnified unified_requested);
-int mount_custom(const char *dest, CustomMount *mounts, unsigned n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int setup_volatile_state(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
#include "bus-unit-util.h"
#include "bus-util.h"
#include "nspawn-register.h"
+#include "special.h"
#include "stat-util.h"
#include "strv.h"
#include "util.h"
"PIDs", "au", 1, pid,
"Description", "s", description,
"Delegate", "b", 1,
- "Slice", "s", isempty(slice) ? "machine.slice" : slice);
+ "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice);
if (r < 0)
return bus_log_create_error(r);
int read_only;
VolatileMode volatile_mode;
CustomMount *custom_mounts;
- unsigned n_custom_mounts;
+ size_t n_custom_mounts;
int userns_chown;
/* [Network] */
(1ULL << CAP_SYS_RESOURCE) |
(1ULL << CAP_SYS_TTY_CONFIG);
static CustomMount *arg_custom_mounts = NULL;
-static unsigned arg_n_custom_mounts = 0;
+static size_t arg_n_custom_mounts = 0;
static char **arg_setenv = NULL;
static bool arg_quiet = false;
static bool arg_register = true;
}
static int custom_mount_check_all(void) {
- unsigned i;
+ size_t i;
for (i = 0; i < arg_n_custom_mounts; i++) {
CustomMount *m = &arg_custom_mounts[i];
}
static int setup_boot_id(void) {
+ _cleanup_(unlink_and_freep) char *from = NULL;
+ _cleanup_free_ char *path = NULL;
sd_id128_t rnd = SD_ID128_NULL;
- const char *from, *to;
+ const char *to;
int r;
/* Generate a new randomized boot ID, so that each boot-up of
* the container gets a new one */
- from = "/run/proc-sys-kernel-random-boot-id";
- to = "/proc/sys/kernel/random/boot_id";
+ r = tempfn_random_child(NULL, "proc-sys-kernel-random-boot-id", &path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate random boot ID path: %m");
r = sd_id128_randomize(&rnd);
if (r < 0)
return log_error_errno(r, "Failed to generate random boot id: %m");
- r = id128_write(from, ID128_UUID, rnd, false);
+ r = id128_write(path, ID128_UUID, rnd, false);
if (r < 0)
return log_error_errno(r, "Failed to write boot id: %m");
+ from = TAKE_PTR(path);
+ to = "/proc/sys/kernel/random/boot_id";
+
r = mount_verbose(LOG_ERR, from, to, NULL, MS_BIND, NULL);
- if (r >= 0)
- r = mount_verbose(LOG_ERR, NULL, to, NULL,
- MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL);
+ if (r < 0)
+ return r;
- (void) unlink(from);
- return r;
+ return mount_verbose(LOG_ERR, NULL, to, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
}
static int copy_devnodes(const char *dest) {
}
static int setup_kmsg(int kmsg_socket) {
- const char *from, *to;
+ _cleanup_(unlink_and_freep) char *from = NULL;
+ _cleanup_free_ char *fifo = NULL;
+ _cleanup_close_ int fd = -1;
_cleanup_umask_ mode_t u;
- int fd, r;
+ const char *to;
+ int r;
assert(kmsg_socket >= 0);
u = umask(0000);
- /* We create the kmsg FIFO as /run/kmsg, but immediately
- * delete it after bind mounting it to /proc/kmsg. While FIFOs
- * on the reading side behave very similar to /proc/kmsg,
- * their writing side behaves differently from /dev/kmsg in
- * that writing blocks when nothing is reading. In order to
- * avoid any problems with containers deadlocking due to this
- * we simply make /dev/kmsg unavailable to the container. */
- from = "/run/kmsg";
- to = "/proc/kmsg";
+ /* We create the kmsg FIFO as as temporary file in /tmp, but immediately delete it after bind mounting it to
+ * /proc/kmsg. While FIFOs on the reading side behave very similar to /proc/kmsg, their writing side behaves
+ * differently from /dev/kmsg in that writing blocks when nothing is reading. In order to avoid any problems
+ * with containers deadlocking due to this we simply make /dev/kmsg unavailable to the container. */
- if (mkfifo(from, 0600) < 0)
+ r = tempfn_random_child(NULL, "proc-kmsg", &fifo);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate kmsg path: %m");
+
+ if (mkfifo(fifo, 0600) < 0)
return log_error_errno(errno, "mkfifo() for /run/kmsg failed: %m");
+
+ from = TAKE_PTR(fifo);
+ to = "/proc/kmsg";
+
r = mount_verbose(LOG_ERR, from, to, NULL, MS_BIND, NULL);
if (r < 0)
return r;
if (fd < 0)
return log_error_errno(errno, "Failed to open fifo: %m");
- /* Store away the fd in the socket, so that it stays open as
- * long as we run the child */
+ /* Store away the fd in the socket, so that it stays open as long as we run the child */
r = send_one_fd(kmsg_socket, fd, 0);
- safe_close(fd);
-
if (r < 0)
return log_error_errno(r, "Failed to send FIFO fd: %m");
- /* And now make the FIFO unavailable as /run/kmsg... */
- (void) unlink(from);
-
return 0;
}
_cleanup_free_ char *home = NULL;
char as_uuid[37];
- unsigned n_env = 1;
+ size_t n_env = 1;
const char *envp[] = {
"PATH=" DEFAULT_PATH_COMPAT,
NULL, /* container */
if (r < 0)
return r;
- if (arg_keep_unit) {
- r = create_subcgroup(*pid, arg_unified_cgroup_hierarchy);
- if (r < 0)
- return r;
- }
+ r = create_subcgroup(*pid, arg_keep_unit, arg_unified_cgroup_hierarchy);
+ if (r < 0)
+ return r;
r = chown_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
if (r < 0)
SD_DHCP_OPTION_REBINDING_T2_TIME = 59,
SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61,
+ SD_DHCP_OPTION_USER_CLASS = 77,
SD_DHCP_OPTION_FQDN = 81,
SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100,
SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101,
int sd_dhcp_client_set_vendor_class_identifier(
sd_dhcp_client *client,
const char *vci);
+int sd_dhcp_client_set_user_class(
+ sd_dhcp_client *client,
+ const char* const *user_class);
int sd_dhcp_client_get_lease(
sd_dhcp_client *client,
sd_dhcp_lease **ret);
return r;
}
+
+int config_parse_channel(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ link_config *config = data;
+ uint32_t k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse channel value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (k < 1) {
+ log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid %s value, ignoring: %s", lvalue, rvalue);
+ return 0;
+ }
+
+ if (streq(lvalue, "RxChannels")) {
+ config->channels.rx_count = k;
+ config->channels.rx_count_set = true;
+ } else if (streq(lvalue, "TxChannels")) {
+ config->channels.tx_count = k;
+ config->channels.tx_count_set = true;
+ } else if (streq(lvalue, "OtherChannels")) {
+ config->channels.other_count = k;
+ config->channels.other_count_set = true;
+ } else if (streq(lvalue, "CombinedChannels")) {
+ config->channels.combined_count = k;
+ config->channels.combined_count_set = true;
+ }
+
+ return 0;
+}
+
+int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
+ struct ethtool_channels ecmd = {
+ .cmd = ETHTOOL_GCHANNELS
+ };
+ struct ifreq ifr = {
+ .ifr_data = (void*) &ecmd
+ };
+
+ bool need_update = false;
+ int r;
+
+ if (*fd < 0) {
+ r = ethtool_connect(fd);
+ if (r < 0)
+ return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
+ }
+
+ strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
+
+ r = ioctl(*fd, SIOCETHTOOL, &ifr);
+ if (r < 0)
+ return -errno;
+
+ if (channels->rx_count_set && ecmd.rx_count != channels->rx_count) {
+ ecmd.rx_count = channels->rx_count;
+ need_update = true;
+ }
+
+ if (channels->tx_count_set && ecmd.tx_count != channels->tx_count) {
+ ecmd.tx_count = channels->tx_count;
+ need_update = true;
+ }
+
+ if (channels->other_count_set && ecmd.other_count != channels->other_count) {
+ ecmd.other_count = channels->other_count;
+ need_update = true;
+ }
+
+ if (channels->combined_count_set && ecmd.combined_count != channels->combined_count) {
+ ecmd.combined_count = channels->combined_count;
+ need_update = true;
+ }
+
+ if (need_update) {
+ ecmd.cmd = ETHTOOL_SCHANNELS;
+
+ r = ioctl(*fd, SIOCETHTOOL, &ifr);
+ if (r < 0)
+ return -errno;
+ }
+
+ return 0;
+}
} link_modes;
};
+typedef struct netdev_channels {
+ uint32_t rx_count;
+ uint32_t tx_count;
+ uint32_t other_count;
+ uint32_t combined_count;
+
+ bool rx_count_set;
+ bool tx_count_set;
+ bool other_count_set;
+ bool combined_count_set;
+} netdev_channels;
+
int ethtool_connect(int *ret);
int ethtool_get_driver(int *fd, const char *ifname, char **ret);
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
int ethtool_set_features(int *fd, const char *ifname, NetDevFeature *features);
int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *link);
+int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels);
const char *duplex_to_string(Duplex d) _const_;
Duplex duplex_from_string(const char *d) _pure_;
int config_parse_duplex(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_wol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_port(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_channel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0
Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
+Link.RxChannels, config_parse_channel, 0, 0
+Link.TxChannels, config_parse_channel, 0, 0
+Link.OtherChannels, config_parse_channel, 0, 0
+Link.CombinedChannels, config_parse_channel, 0, 0
if (r < 0)
log_warning_errno(r, "Could not set offload features of %s: %m", old_name);
+ if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
+ r = ethtool_set_channels(&ctx->ethtool_fd, old_name, &config->channels);
+ if (r < 0)
+ log_warning_errno(r, "Could not set channels of %s: %m", old_name);
+ }
+
ifindex = udev_device_get_ifindex(device);
if (ifindex <= 0) {
log_warning("Could not find ifindex");
WakeOnLan wol;
NetDevPort port;
NetDevFeature features[_NET_DEV_FEAT_MAX];
+ netdev_channels channels;
LIST_FIELDS(link_config, links);
};
'sysusers.d_' + file,
input : file + '.m4',
output: file,
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true,
install : enable_sysusers,
install_dir : sysusersdir)
'tmpfiles.d_' + pair[0],
input : pair[0] + '.m4',
output: pair[0],
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true,
install : true,
install_dir : tmpfilesdir)
--- /dev/null
+#!/bin/sh
+set -eu
+
+CONFIG=$1
+TARGET=$2
+
+if [ $# -ne 2 ]; then
+ echo 'Invalid number of arguments.'
+ exit 1
+fi
+
+if [ ! -f $CONFIG ]; then
+ echo "$CONFIG not found."
+ exit 2
+fi
+
+if [ ! -f $TARGET ]; then
+ echo "$TARGET not found."
+ exit 3
+fi
+
+DEFINES=$(awk '$1 == "#define" && $3 == "1" { printf "-D%s ", $2 }' $CONFIG)
+
+m4 -P $DEFINES $TARGET
file,
input : input,
output: file,
- command : [m4, '-P'] + m4_defines + ['@INPUT@'],
+ command : [meson_apply_m4, config_h, '@INPUT@'],
capture : true,
install : install,
install_dir : systemunitdir)