Compare commits
21 Commits
b18573e16f
...
f49bead3b0
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | f49bead3b0 | |
Lennart Poettering | b7d81d19cc | |
Evgeny Vereshchagin | a055076988 | |
Evgeny Vereshchagin | efa5bef285 | |
Luca Boccassi | d4d55b0d13 | |
Luca Boccassi | c2923fdcd7 | |
Luca Boccassi | 035e8e50d7 | |
Zbigniew Jędrzejewski-Szmek | e60d3b13df | |
Zbigniew Jędrzejewski-Szmek | fd7c7fc8ee | |
Michal Koutný | e41de5e491 | |
Lennart Poettering | 6b000af4f2 | |
Zbigniew Jędrzejewski-Szmek | f23810da20 | |
Zbigniew Jędrzejewski-Szmek | 85fbebe61a | |
Yu Watanabe | f50f597217 | |
Yu Watanabe | 7936917e3e | |
Yu Watanabe | e856ed00f9 | |
Yu Watanabe | 25b831bac8 | |
Michal Koutný | d184fb39b6 | |
Michal Koutný | 67e2baff6b | |
Zbigniew Jędrzejewski-Szmek | db3b8d5d41 | |
Zbigniew Jędrzejewski-Szmek | c238a1f5f1 |
43
NEWS
43
NEWS
|
@ -373,6 +373,10 @@ CHANGES WITH 246 in spe:
|
||||||
its pending removal 2 years ago (also see NEWS file below). It's
|
its pending removal 2 years ago (also see NEWS file below). It's
|
||||||
finally gone now.
|
finally gone now.
|
||||||
|
|
||||||
|
* The BlackList= settings in .network files' [DHCPv4] and
|
||||||
|
[IPv6AcceptRA] sections have been renamed DenyList=. The old names
|
||||||
|
are still understood to provide compatibility.
|
||||||
|
|
||||||
CHANGES WITH 245:
|
CHANGES WITH 245:
|
||||||
|
|
||||||
* A new tool "systemd-repart" has been added, that operates as an
|
* A new tool "systemd-repart" has been added, that operates as an
|
||||||
|
@ -744,7 +748,7 @@ CHANGES WITH 244:
|
||||||
of the PAM session, for example for time-limited logins.
|
of the PAM session, for example for time-limited logins.
|
||||||
|
|
||||||
* A new @pkey system call group is now defined to make it easier to
|
* A new @pkey system call group is now defined to make it easier to
|
||||||
whitelist memory protection syscalls for containers and services
|
allow-list memory protection syscalls for containers and services
|
||||||
which need to use them.
|
which need to use them.
|
||||||
|
|
||||||
* systemd-udevd: removed the 30s timeout for killing stale workers on
|
* systemd-udevd: removed the 30s timeout for killing stale workers on
|
||||||
|
@ -761,10 +765,10 @@ CHANGES WITH 244:
|
||||||
* udev now provides a program (fido_id) that identifies FIDO CTAP1
|
* udev now provides a program (fido_id) that identifies FIDO CTAP1
|
||||||
("U2F")/CTAP2 security tokens based on the usage declared in their
|
("U2F")/CTAP2 security tokens based on the usage declared in their
|
||||||
report and descriptor and outputs suitable environment variables.
|
report and descriptor and outputs suitable environment variables.
|
||||||
This replaces the externally maintained whitelists of all known
|
This replaces the externally maintained allow lists of all known
|
||||||
security tokens that were used previously.
|
security tokens that were used previously.
|
||||||
|
|
||||||
* Automatically generated autosuspend udev rules for whitelisted
|
* Automatically generated autosuspend udev rules for allow-listed
|
||||||
devices have been imported from the Chromium OS project. This should
|
devices have been imported from the Chromium OS project. This should
|
||||||
improve power saving with many more devices.
|
improve power saving with many more devices.
|
||||||
|
|
||||||
|
@ -1131,7 +1135,7 @@ CHANGES WITH 243:
|
||||||
|
|
||||||
* systemd-networkd's DHCPv4 support now understands a new MaxAttempts=
|
* systemd-networkd's DHCPv4 support now understands a new MaxAttempts=
|
||||||
option for configuring the maximum number of DHCP lease requests. It
|
option for configuring the maximum number of DHCP lease requests. It
|
||||||
also learnt a new BlackList= option for blacklisting DHCP servers (a
|
also learnt a new BlackList= option for deny-listing DHCP servers (a
|
||||||
similar setting has also been added to the IPv6 RA client), as well
|
similar setting has also been added to the IPv6 RA client), as well
|
||||||
as a SendRelease= option for configuring whether to send a DHCP
|
as a SendRelease= option for configuring whether to send a DHCP
|
||||||
RELEASE message when terminating.
|
RELEASE message when terminating.
|
||||||
|
@ -2363,12 +2367,12 @@ CHANGES WITH 239:
|
||||||
any relevant symlinks both in /run and /etc.
|
any relevant symlinks both in /run and /etc.
|
||||||
|
|
||||||
* Note that all long-running system services shipped with systemd will
|
* Note that all long-running system services shipped with systemd will
|
||||||
now default to a system call whitelist (rather than a blacklist, as
|
now default to a system call allow list (rather than a deny list, as
|
||||||
before). In particular, systemd-udevd will now enforce one too. For
|
before). In particular, systemd-udevd will now enforce one too. For
|
||||||
most cases this should be safe, however downstream distributions
|
most cases this should be safe, however downstream distributions
|
||||||
which disabled sandboxing of systemd-udevd (specifically the
|
which disabled sandboxing of systemd-udevd (specifically the
|
||||||
MountFlags= setting), might want to disable this security feature
|
MountFlags= setting), might want to disable this security feature
|
||||||
too, as the default whitelisting will prohibit all mount, swap,
|
too, as the default allow-listing will prohibit all mount, swap,
|
||||||
reboot and clock changing operations from udev rules.
|
reboot and clock changing operations from udev rules.
|
||||||
|
|
||||||
* sd-boot acquired new loader configuration settings to optionally turn
|
* sd-boot acquired new loader configuration settings to optionally turn
|
||||||
|
@ -3396,7 +3400,7 @@ CHANGES WITH 235:
|
||||||
* systemd-nspawn gained support for a new --system-call-filter= command
|
* systemd-nspawn gained support for a new --system-call-filter= command
|
||||||
line option for adding and removing entries in the default system
|
line option for adding and removing entries in the default system
|
||||||
call filter it applies. Moreover systemd-nspawn has been changed to
|
call filter it applies. Moreover systemd-nspawn has been changed to
|
||||||
implement a system call whitelist instead of a blacklist.
|
implement a system call allow list instead of a deny list.
|
||||||
|
|
||||||
* systemd-run gained support for a new --pipe command line option. If
|
* systemd-run gained support for a new --pipe command line option. If
|
||||||
used the STDIN/STDOUT/STDERR file descriptors passed to systemd-run
|
used the STDIN/STDOUT/STDERR file descriptors passed to systemd-run
|
||||||
|
@ -6109,11 +6113,10 @@ CHANGES WITH 220:
|
||||||
fsck's progress report to an AF_UNIX socket in the file
|
fsck's progress report to an AF_UNIX socket in the file
|
||||||
system.
|
system.
|
||||||
|
|
||||||
* udev will no longer create device symlinks for all block
|
* udev will no longer create device symlinks for all block devices by
|
||||||
devices by default. A blacklist for excluding special block
|
default. A deny list for excluding special block devices from this
|
||||||
devices from this logic has been turned into a whitelist
|
logic has been turned into a allow list that requires picking block
|
||||||
that requires picking block devices explicitly that require
|
devices explicitly that require device symlinks.
|
||||||
device symlinks.
|
|
||||||
|
|
||||||
* A new (currently still internal) API sd-device.h has been
|
* A new (currently still internal) API sd-device.h has been
|
||||||
added to libsystemd. This modernized API is supposed to
|
added to libsystemd. This modernized API is supposed to
|
||||||
|
@ -8002,11 +8005,11 @@ CHANGES WITH 210:
|
||||||
Wikipedia. We explicitly document which base applies for
|
Wikipedia. We explicitly document which base applies for
|
||||||
each configuration option.
|
each configuration option.
|
||||||
|
|
||||||
* The DeviceAllow= setting in unit files now supports a syntax
|
* The DeviceAllow= setting in unit files now supports a syntax to
|
||||||
to whitelist an entire group of devices node majors at once,
|
allow-list an entire group of devices node majors at once, based on
|
||||||
based on the /proc/devices listing. For example, with the
|
the /proc/devices listing. For example, with the string "char-pts",
|
||||||
string "char-pts", it is now possible to whitelist all
|
it is now possible to allow-list all current and future pseudo-TTYs
|
||||||
current and future pseudo-TTYs at once.
|
at once.
|
||||||
|
|
||||||
* sd-event learned a new "post" event source. Event sources of
|
* sd-event learned a new "post" event source. Event sources of
|
||||||
this type are triggered by the dispatching of any event
|
this type are triggered by the dispatching of any event
|
||||||
|
@ -10249,9 +10252,9 @@ CHANGES WITH 187:
|
||||||
* journalctl gained the new "--header" switch to introspect
|
* journalctl gained the new "--header" switch to introspect
|
||||||
header data of journal files.
|
header data of journal files.
|
||||||
|
|
||||||
* A new setting SystemCallFilters= has been added to services
|
* A new setting SystemCallFilters= has been added to services which may
|
||||||
which may be used to apply blacklists or whitelists to
|
be used to apply deny lists or allow lists to system calls. This is
|
||||||
system calls. This is based on SECCOMP Mode 2 of Linux 3.5.
|
based on SECCOMP Mode 2 of Linux 3.5.
|
||||||
|
|
||||||
* nspawn gained a new --link-journal= switch (and quicker: -j)
|
* nspawn gained a new --link-journal= switch (and quicker: -j)
|
||||||
to link the container journal with the host. This makes it
|
to link the container journal with the host. This makes it
|
||||||
|
|
6
README
6
README
|
@ -35,6 +35,7 @@ LICENSE:
|
||||||
REQUIREMENTS:
|
REQUIREMENTS:
|
||||||
Linux kernel >= 3.13
|
Linux kernel >= 3.13
|
||||||
Linux kernel >= 4.2 for unified cgroup hierarchy support
|
Linux kernel >= 4.2 for unified cgroup hierarchy support
|
||||||
|
Linux kernel >= 5.4 for signed Verity images support
|
||||||
|
|
||||||
Kernel Config Options:
|
Kernel Config Options:
|
||||||
CONFIG_DEVTMPFS
|
CONFIG_DEVTMPFS
|
||||||
|
@ -102,6 +103,9 @@ REQUIREMENTS:
|
||||||
CONFIG_EFIVAR_FS
|
CONFIG_EFIVAR_FS
|
||||||
CONFIG_EFI_PARTITION
|
CONFIG_EFI_PARTITION
|
||||||
|
|
||||||
|
Required for signed Verity images support:
|
||||||
|
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
|
||||||
|
|
||||||
We recommend to turn off Real-Time group scheduling in the
|
We recommend to turn off Real-Time group scheduling in the
|
||||||
kernel when using systemd. RT group scheduling effectively
|
kernel when using systemd. RT group scheduling effectively
|
||||||
makes RT scheduling unavailable for most userspace, since it
|
makes RT scheduling unavailable for most userspace, since it
|
||||||
|
@ -144,7 +148,7 @@ REQUIREMENTS:
|
||||||
libblkid >= 2.24 (from util-linux) (optional)
|
libblkid >= 2.24 (from util-linux) (optional)
|
||||||
libkmod >= 15 (optional)
|
libkmod >= 15 (optional)
|
||||||
PAM >= 1.1.2 (optional)
|
PAM >= 1.1.2 (optional)
|
||||||
libcryptsetup (optional)
|
libcryptsetup (optional), >= 2.3.0 required for signed Verity images support
|
||||||
libaudit (optional)
|
libaudit (optional)
|
||||||
libacl (optional)
|
libacl (optional)
|
||||||
libselinux (optional)
|
libselinux (optional)
|
||||||
|
|
|
@ -68,9 +68,9 @@ Distilled from the above, below are the rules systemd enforces on user/group
|
||||||
names. An additional, common rule between both modes listed below is that empty
|
names. An additional, common rule between both modes listed below is that empty
|
||||||
strings are not valid user/group names.
|
strings are not valid user/group names.
|
||||||
|
|
||||||
Philosophically, the strict mode described below enforces a white-list of what's
|
Philosophically, the strict mode described below enforces an allow list of
|
||||||
allowed and prohibits everything else, while the relaxed mode described below
|
what's allowed and prohibits everything else, while the relaxed mode described
|
||||||
implements a blacklist of what's not allowed and permits everything else.
|
below implements a deny list of what's not allowed and permits everything else.
|
||||||
|
|
||||||
### Strict mode
|
### Strict mode
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,7 @@
|
||||||
|
|
||||||
<para>Single file system images (i.e. file systems without a surrounding partition table) can be opened using
|
<para>Single file system images (i.e. file systems without a surrounding partition table) can be opened using
|
||||||
dm-verity if the integrity data is passed using the <option>--root-hash=</option> and
|
dm-verity if the integrity data is passed using the <option>--root-hash=</option> and
|
||||||
<option>--verity-data=</option> options.</para>
|
<option>--verity-data=</option> (and optionally <option>--root-hash-sig=</option>) options.</para>
|
||||||
|
|
||||||
<para>Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified
|
<para>Any other partitions, such as foreign partitions or swap partitions are not mounted. May not be specified
|
||||||
together with <option>--directory=</option>, <option>--template=</option>.</para></listitem>
|
together with <option>--directory=</option>, <option>--template=</option>.</para></listitem>
|
||||||
|
@ -399,6 +399,18 @@
|
||||||
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
|
is read from it and automatically used, also as formatted hexadecimal characters.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--root-hash-sig=</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a PKCS7 formatted binary signature of the <option>--root-hash=</option> option as a path
|
||||||
|
to a DER encoded signature file or as an ASCII base64 string encoding of the DER encoded signature, prefixed
|
||||||
|
by <literal>base64:</literal>. The dm-verity volume will only be opened if the signature of the root hash hex
|
||||||
|
string is valid and done by a public key present in the kernel keyring. If this option is not specified, but a
|
||||||
|
file with the <filename>.roothash.p7s</filename> suffix is found next to the image file, bearing otherwise the
|
||||||
|
same name (except if the image has the <filename>.raw</filename> suffix, in which case the signature file must
|
||||||
|
not have it in its name), the signature is read from it and automatically used.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--verity-data=</option></term>
|
<term><option>--verity-data=</option></term>
|
||||||
|
|
||||||
|
@ -1000,29 +1012,28 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--no-new-privileges=</option></term>
|
<term><option>--no-new-privileges=</option></term>
|
||||||
|
|
||||||
<listitem><para>Takes a boolean argument. Specifies the value of the <constant>PR_SET_NO_NEW_PRIVS</constant>
|
<listitem><para>Takes a boolean argument. Specifies the value of the
|
||||||
flag for the container payload. Defaults to off. When turned on the payload code of the container cannot
|
<constant>PR_SET_NO_NEW_PRIVS</constant> flag for the container payload. Defaults to off. When turned
|
||||||
acquire new privileges, i.e. the "setuid" file bit as well as file system capabilities will not have an effect
|
on the payload code of the container cannot acquire new privileges, i.e. the "setuid" file bit as
|
||||||
anymore. See <citerefentry
|
well as file system capabilities will not have an effect anymore. See <citerefentry
|
||||||
project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details
|
project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
|
||||||
about this flag. </para></listitem>
|
details about this flag. </para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--system-call-filter=</option></term>
|
<term><option>--system-call-filter=</option></term> <listitem><para>Alter the system call filter
|
||||||
|
applied to containers. Takes a space-separated list of system call names or group names (the latter
|
||||||
<listitem><para>Alter the system call filter applied to containers. Takes a space-separated list of system call
|
prefixed with <literal>@</literal>, as listed by the <command>syscall-filter</command> command of
|
||||||
names or group names (the latter prefixed with <literal>@</literal>, as listed by the
|
|
||||||
<command>syscall-filter</command> command of
|
|
||||||
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
|
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>). Passed
|
||||||
system calls will be permitted. The list may optionally be prefixed by <literal>~</literal>, in which case all
|
system calls will be permitted. The list may optionally be prefixed by <literal>~</literal>, in which
|
||||||
listed system calls are prohibited. If this command line option is used multiple times the configured lists are
|
case all listed system calls are prohibited. If this command line option is used multiple times the
|
||||||
combined. If both a positive and a negative list (that is one system call list without and one with the
|
configured lists are combined. If both a positive and a negative list (that is one system call list
|
||||||
<literal>~</literal> prefix) are configured, the negative list takes precedence over the positive list. Note
|
without and one with the <literal>~</literal> prefix) are configured, the negative list takes
|
||||||
that <command>systemd-nspawn</command> always implements a system call whitelist (as opposed to a blacklist),
|
precedence over the positive list. Note that <command>systemd-nspawn</command> always implements a
|
||||||
and this command line option hence adds or removes entries from the default whitelist, depending on the
|
system call allow list (as opposed to a deny list!), and this command line option hence adds or
|
||||||
<literal>~</literal> prefix. Note that the applied system call filter is also altered implicitly if additional
|
removes entries from the default allow list, depending on the <literal>~</literal> prefix. Note that
|
||||||
capabilities are passed using the <command>--capabilities=</command>.</para></listitem>
|
the applied system call filter is also altered implicitly if additional capabilities are passed using
|
||||||
|
the <command>--capabilities=</command>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -164,6 +164,20 @@
|
||||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>RootHashSignature=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a PKCS7 formatted binary signature of the <varname>RootHash=</varname> option as a path
|
||||||
|
to a DER encoded signature file or as an ASCII base64 string encoding of the DER encoded signature, prefixed
|
||||||
|
by <literal>base64:</literal>. The dm-verity volume will only be opened if the signature of the root hash
|
||||||
|
signature is valid and created by a public key present in the kernel keyring. If this option is not specified,
|
||||||
|
but a file with the <filename>.roothash.p7s</filename> suffix is found next to the image file, bearing otherwise
|
||||||
|
the same name (except if the image has the <filename>.raw</filename> suffix, in which case the signature file
|
||||||
|
must not have it in its name), the signature is read from it and automatically used.</para>
|
||||||
|
|
||||||
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>RootVerity=</varname></term>
|
<term><varname>RootVerity=</varname></term>
|
||||||
|
|
||||||
|
@ -318,7 +332,7 @@
|
||||||
files or directories. Moreover <varname>ProtectSystem=strict</varname> and
|
files or directories. Moreover <varname>ProtectSystem=strict</varname> and
|
||||||
<varname>ProtectHome=read-only</varname> are implied, thus prohibiting the service to write to
|
<varname>ProtectHome=read-only</varname> are implied, thus prohibiting the service to write to
|
||||||
arbitrary file system locations. In order to allow the service to write to certain directories, they
|
arbitrary file system locations. In order to allow the service to write to certain directories, they
|
||||||
have to be whitelisted using <varname>ReadWritePaths=</varname>, but care must be taken so that
|
have to be allow-listed using <varname>ReadWritePaths=</varname>, but care must be taken so that
|
||||||
UID/GID recycling doesn't create security issues involving files created by the service. Use
|
UID/GID recycling doesn't create security issues involving files created by the service. Use
|
||||||
<varname>RuntimeDirectory=</varname> (see below) in order to assign a writable runtime directory to a
|
<varname>RuntimeDirectory=</varname> (see below) in order to assign a writable runtime directory to a
|
||||||
service, owned by the dynamic user/group and removed automatically when the unit is terminated. Use
|
service, owned by the dynamic user/group and removed automatically when the unit is terminated. Use
|
||||||
|
@ -1150,12 +1164,13 @@ StateDirectory=aaa/bbb ccc</programlisting>
|
||||||
contain symlinks, they are resolved relative to the root directory set with
|
contain symlinks, they are resolved relative to the root directory set with
|
||||||
<varname>RootDirectory=</varname>/<varname>RootImage=</varname>.</para>
|
<varname>RootDirectory=</varname>/<varname>RootImage=</varname>.</para>
|
||||||
|
|
||||||
<para>Paths listed in <varname>ReadWritePaths=</varname> are accessible from within the namespace with the same
|
<para>Paths listed in <varname>ReadWritePaths=</varname> are accessible from within the namespace
|
||||||
access modes as from outside of it. Paths listed in <varname>ReadOnlyPaths=</varname> are accessible for
|
with the same access modes as from outside of it. Paths listed in <varname>ReadOnlyPaths=</varname>
|
||||||
reading only, writing will be refused even if the usual file access controls would permit this. Nest
|
are accessible for reading only, writing will be refused even if the usual file access controls would
|
||||||
<varname>ReadWritePaths=</varname> inside of <varname>ReadOnlyPaths=</varname> in order to provide writable
|
permit this. Nest <varname>ReadWritePaths=</varname> inside of <varname>ReadOnlyPaths=</varname> in
|
||||||
subdirectories within read-only directories. Use <varname>ReadWritePaths=</varname> in order to whitelist
|
order to provide writable subdirectories within read-only directories. Use
|
||||||
specific paths for write access if <varname>ProtectSystem=strict</varname> is used.</para>
|
<varname>ReadWritePaths=</varname> in order to allow-list specific paths for write access if
|
||||||
|
<varname>ProtectSystem=strict</varname> is used.</para>
|
||||||
|
|
||||||
<para>Paths listed in <varname>InaccessiblePaths=</varname> will be made inaccessible for processes inside
|
<para>Paths listed in <varname>InaccessiblePaths=</varname> will be made inaccessible for processes inside
|
||||||
the namespace along with everything below them in the file system hierarchy. This may be more restrictive than
|
the namespace along with everything below them in the file system hierarchy. This may be more restrictive than
|
||||||
|
@ -1469,29 +1484,31 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>RestrictAddressFamilies=</varname></term>
|
<term><varname>RestrictAddressFamilies=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Restricts the set of socket address families accessible to the processes of this unit. Takes a
|
<listitem><para>Restricts the set of socket address families accessible to the processes of this
|
||||||
space-separated list of address family names to whitelist, such as <constant>AF_UNIX</constant>,
|
unit. Takes a space-separated list of address family names to allow-list, such as
|
||||||
<constant>AF_INET</constant> or <constant>AF_INET6</constant>. When prefixed with <constant>~</constant> the
|
<constant>AF_UNIX</constant>, <constant>AF_INET</constant> or <constant>AF_INET6</constant>. When
|
||||||
listed address families will be applied as blacklist, otherwise as whitelist. Note that this restricts access
|
prefixed with <constant>~</constant> the listed address families will be applied as deny list,
|
||||||
to the <citerefentry
|
otherwise as allow list. Note that this restricts access to the <citerefentry
|
||||||
project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call
|
project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||||
only. Sockets passed into the process by other means (for example, by using socket activation with socket
|
system call only. Sockets passed into the process by other means (for example, by using socket
|
||||||
units, see <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>)
|
activation with socket units, see
|
||||||
are unaffected. Also, sockets created with <function>socketpair()</function> (which creates connected AF_UNIX
|
<citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>)
|
||||||
sockets only) are unaffected. Note that this option has no effect on 32-bit x86, s390, s390x, mips, mips-le,
|
are unaffected. Also, sockets created with <function>socketpair()</function> (which creates connected
|
||||||
ppc, ppc-le, pcc64, ppc64-le and is ignored (but works correctly on other ABIs, including x86-64). Note that on
|
AF_UNIX sockets only) are unaffected. Note that this option has no effect on 32-bit x86, s390, s390x,
|
||||||
systems supporting multiple ABIs (such as x86/x86-64) it is recommended to turn off alternative ABIs for
|
mips, mips-le, ppc, ppc-le, pcc64, ppc64-le and is ignored (but works correctly on other ABIs,
|
||||||
services, so that they cannot be used to circumvent the restrictions of this option. Specifically, it is
|
including x86-64). Note that on systems supporting multiple ABIs (such as x86/x86-64) it is
|
||||||
recommended to combine this option with <varname>SystemCallArchitectures=native</varname> or similar. If
|
recommended to turn off alternative ABIs for services, so that they cannot be used to circumvent the
|
||||||
running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant> capability
|
restrictions of this option. Specifically, it is recommended to combine this option with
|
||||||
(e.g. setting <varname>User=nobody</varname>), <varname>NoNewPrivileges=yes</varname> is implied. By default,
|
<varname>SystemCallArchitectures=native</varname> or similar. If running in user mode, or in system
|
||||||
no restrictions apply, all address families are accessible to processes. If assigned the empty string, any
|
mode, but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
|
||||||
previous address family restriction changes are undone. This setting does not affect commands prefixed with
|
<varname>User=nobody</varname>), <varname>NoNewPrivileges=yes</varname> is implied. By default, no
|
||||||
<literal>+</literal>.</para>
|
restrictions apply, all address families are accessible to processes. If assigned the empty string,
|
||||||
|
any previous address family restriction changes are undone. This setting does not affect commands
|
||||||
|
prefixed with <literal>+</literal>.</para>
|
||||||
|
|
||||||
<para>Use this option to limit exposure of processes to remote access, in particular via exotic and sensitive
|
<para>Use this option to limit exposure of processes to remote access, in particular via exotic and sensitive
|
||||||
network protocols, such as <constant>AF_PACKET</constant>. Note that in most cases, the local
|
network protocols, such as <constant>AF_PACKET</constant>. Note that in most cases, the local
|
||||||
<constant>AF_UNIX</constant> address family should be included in the configured whitelist as it is frequently
|
<constant>AF_UNIX</constant> address family should be included in the configured allow list as it is frequently
|
||||||
used for local communication, including for
|
used for local communication, including for
|
||||||
<citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||||
logging.</para></listitem>
|
logging.</para></listitem>
|
||||||
|
@ -1509,9 +1526,9 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
|
||||||
any combination of: <constant>cgroup</constant>, <constant>ipc</constant>, <constant>net</constant>,
|
any combination of: <constant>cgroup</constant>, <constant>ipc</constant>, <constant>net</constant>,
|
||||||
<constant>mnt</constant>, <constant>pid</constant>, <constant>user</constant> and <constant>uts</constant>. Any
|
<constant>mnt</constant>, <constant>pid</constant>, <constant>user</constant> and <constant>uts</constant>. Any
|
||||||
namespace type listed is made accessible to the unit's processes, access to namespace types not listed is
|
namespace type listed is made accessible to the unit's processes, access to namespace types not listed is
|
||||||
prohibited (whitelisting). By prepending the list with a single tilde character (<literal>~</literal>) the
|
prohibited (allow-listing). By prepending the list with a single tilde character (<literal>~</literal>) the
|
||||||
effect may be inverted: only the listed namespace types will be made inaccessible, all unlisted ones are
|
effect may be inverted: only the listed namespace types will be made inaccessible, all unlisted ones are
|
||||||
permitted (blacklisting). If the empty string is assigned, the default namespace restrictions are applied,
|
permitted (deny-listing). If the empty string is assigned, the default namespace restrictions are applied,
|
||||||
which is equivalent to false. This option may appear more than once, in which case the namespace types are
|
which is equivalent to false. This option may appear more than once, in which case the namespace types are
|
||||||
merged by <constant>OR</constant>, or by <constant>AND</constant> if the lines are prefixed with
|
merged by <constant>OR</constant>, or by <constant>AND</constant> if the lines are prefixed with
|
||||||
<literal>~</literal> (see examples below). Internally, this setting limits access to the
|
<literal>~</literal> (see examples below). Internally, this setting limits access to the
|
||||||
|
@ -1701,15 +1718,15 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||||
|
|
||||||
<listitem><para>Takes a space-separated list of system call names. If this setting is used, all
|
<listitem><para>Takes a space-separated list of system call names. If this setting is used, all
|
||||||
system calls executed by the unit processes except for the listed ones will result in immediate
|
system calls executed by the unit processes except for the listed ones will result in immediate
|
||||||
process termination with the <constant>SIGSYS</constant> signal (whitelisting). (See
|
process termination with the <constant>SIGSYS</constant> signal (allow-listing). (See
|
||||||
<varname>SystemCallErrorNumber=</varname> below for changing the default action). If the first
|
<varname>SystemCallErrorNumber=</varname> below for changing the default action). If the first
|
||||||
character of the list is <literal>~</literal>, the effect is inverted: only the listed system calls
|
character of the list is <literal>~</literal>, the effect is inverted: only the listed system calls
|
||||||
will result in immediate process termination (blacklisting). Blacklisted system calls and system call
|
will result in immediate process termination (deny-listing). Deny-listed system calls and system call
|
||||||
groups may optionally be suffixed with a colon (<literal>:</literal>) and <literal>errno</literal>
|
groups may optionally be suffixed with a colon (<literal>:</literal>) and <literal>errno</literal>
|
||||||
error number (between 0 and 4095) or errno name such as <constant>EPERM</constant>,
|
error number (between 0 and 4095) or errno name such as <constant>EPERM</constant>,
|
||||||
<constant>EACCES</constant> or <constant>EUCLEAN</constant> (see <citerefentry
|
<constant>EACCES</constant> or <constant>EUCLEAN</constant> (see <citerefentry
|
||||||
project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
|
project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry> for a
|
||||||
full list). This value will be returned when a blacklisted system call is triggered, instead of
|
full list). This value will be returned when a deny-listed system call is triggered, instead of
|
||||||
terminating the processes immediately. This value takes precedence over the one given in
|
terminating the processes immediately. This value takes precedence over the one given in
|
||||||
<varname>SystemCallErrorNumber=</varname>, see below. If running in user mode, or in system mode,
|
<varname>SystemCallErrorNumber=</varname>, see below. If running in user mode, or in system mode,
|
||||||
but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
|
but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
|
||||||
|
@ -1718,7 +1735,7 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||||
for enforcing a minimal sandboxing environment. Note that the <function>execve</function>,
|
for enforcing a minimal sandboxing environment. Note that the <function>execve</function>,
|
||||||
<function>exit</function>, <function>exit_group</function>, <function>getrlimit</function>,
|
<function>exit</function>, <function>exit_group</function>, <function>getrlimit</function>,
|
||||||
<function>rt_sigreturn</function>, <function>sigreturn</function> system calls and the system calls
|
<function>rt_sigreturn</function>, <function>sigreturn</function> system calls and the system calls
|
||||||
for querying time and sleeping are implicitly whitelisted and do not need to be listed
|
for querying time and sleeping are implicitly allow-listed and do not need to be listed
|
||||||
explicitly. This option may be specified more than once, in which case the filter masks are
|
explicitly. This option may be specified more than once, in which case the filter masks are
|
||||||
merged. If the empty string is assigned, the filter is reset, all prior assignments will have no
|
merged. If the empty string is assigned, the filter is reset, all prior assignments will have no
|
||||||
effect. This does not affect commands prefixed with <literal>+</literal>.</para>
|
effect. This does not affect commands prefixed with <literal>+</literal>.</para>
|
||||||
|
@ -1736,12 +1753,13 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||||
might be necessary to temporarily disable system call filters in order to simplify debugging of such
|
might be necessary to temporarily disable system call filters in order to simplify debugging of such
|
||||||
failures.</para>
|
failures.</para>
|
||||||
|
|
||||||
<para>If you specify both types of this option (i.e. whitelisting and blacklisting), the first encountered
|
<para>If you specify both types of this option (i.e. allow-listing and deny-listing), the first
|
||||||
will take precedence and will dictate the default action (termination or approval of a system call). Then the
|
encountered will take precedence and will dictate the default action (termination or approval of a
|
||||||
next occurrences of this option will add or delete the listed system calls from the set of the filtered system
|
system call). Then the next occurrences of this option will add or delete the listed system calls
|
||||||
calls, depending of its type and the default action. (For example, if you have started with a whitelisting of
|
from the set of the filtered system calls, depending of its type and the default action. (For
|
||||||
<function>read</function> and <function>write</function>, and right after it add a blacklisting of
|
example, if you have started with an allow list rule for <function>read</function> and
|
||||||
<function>write</function>, then <function>write</function> will be removed from the set.)</para>
|
<function>write</function>, and right after it add a deny list rule for <function>write</function>,
|
||||||
|
then <function>write</function> will be removed from the set.)</para>
|
||||||
|
|
||||||
<para>As the number of possible system calls is large, predefined sets of system calls are provided. A set
|
<para>As the number of possible system calls is large, predefined sets of system calls are provided. A set
|
||||||
starts with <literal>@</literal> character, followed by name of the set.
|
starts with <literal>@</literal> character, followed by name of the set.
|
||||||
|
@ -1857,7 +1875,7 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>@system-service</entry>
|
<entry>@system-service</entry>
|
||||||
<entry>A reasonable set of system calls used by common system services, excluding any special purpose calls. This is the recommended starting point for whitelisting system calls for system services, as it contains what is typically needed by system services, but excludes overly specific interfaces. For example, the following APIs are excluded: <literal>@clock</literal>, <literal>@mount</literal>, <literal>@swap</literal>, <literal>@reboot</literal>.</entry>
|
<entry>A reasonable set of system calls used by common system services, excluding any special purpose calls. This is the recommended starting point for allow-listing system calls for system services, as it contains what is typically needed by system services, but excludes overly specific interfaces. For example, the following APIs are excluded: <literal>@clock</literal>, <literal>@mount</literal>, <literal>@swap</literal>, <literal>@reboot</literal>.</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
<entry>@timer</entry>
|
<entry>@timer</entry>
|
||||||
|
@ -1873,9 +1891,10 @@ RestrictNamespaces=~cgroup net</programlisting>
|
||||||
<command>systemd-analyze syscall-filter</command> to list the actual list of system calls in each
|
<command>systemd-analyze syscall-filter</command> to list the actual list of system calls in each
|
||||||
filter.</para>
|
filter.</para>
|
||||||
|
|
||||||
<para>Generally, whitelisting system calls (rather than blacklisting) is the safer mode of operation. It is
|
<para>Generally, allow-listing system calls (rather than deny-listing) is the safer mode of
|
||||||
recommended to enforce system call whitelists for all long-running system services. Specifically, the
|
operation. It is recommended to enforce system call allow lists for all long-running system
|
||||||
following lines are a relatively safe basic choice for the majority of system services:</para>
|
services. Specifically, the following lines are a relatively safe basic choice for the majority of
|
||||||
|
system services:</para>
|
||||||
|
|
||||||
<programlisting>[Service]
|
<programlisting>[Service]
|
||||||
SystemCallFilter=@system-service
|
SystemCallFilter=@system-service
|
||||||
|
@ -1886,9 +1905,9 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||||
call may be used to execute operations similar to what can be done with the older
|
call may be used to execute operations similar to what can be done with the older
|
||||||
<function>kill()</function> system call, hence blocking the latter without the former only provides
|
<function>kill()</function> system call, hence blocking the latter without the former only provides
|
||||||
weak protection. Since new system calls are added regularly to the kernel as development progresses,
|
weak protection. Since new system calls are added regularly to the kernel as development progresses,
|
||||||
keeping system call blacklists comprehensive requires constant work. It is thus recommended to use
|
keeping system call deny lists comprehensive requires constant work. It is thus recommended to use
|
||||||
whitelisting instead, which offers the benefit that new system calls are by default implicitly
|
allow-listing instead, which offers the benefit that new system calls are by default implicitly
|
||||||
blocked until the whitelist is updated.</para>
|
blocked until the allow list is updated.</para>
|
||||||
|
|
||||||
<para>Also note that a number of system calls are required to be accessible for the dynamic linker to
|
<para>Also note that a number of system calls are required to be accessible for the dynamic linker to
|
||||||
work. The dynamic linker is required for running most regular programs (specifically: all dynamic ELF
|
work. The dynamic linker is required for running most regular programs (specifically: all dynamic ELF
|
||||||
|
|
|
@ -1679,7 +1679,7 @@
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>BlackList=</varname></term>
|
<term><varname>DenyList=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>A whitespace-separated list of IPv4 addresses. DHCP offers from servers in the list are rejected.</para>
|
<para>A whitespace-separated list of IPv4 addresses. DHCP offers from servers in the list are rejected.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
@ -1945,7 +1945,7 @@
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>BlackList=</varname></term>
|
<term><varname>DenyList=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router advertisements in the list are ignored.</para>
|
<para>A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router advertisements in the list are ignored.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
|
@ -596,13 +596,13 @@
|
||||||
<listitem><para>Otherwise, access is granted.</para></listitem>
|
<listitem><para>Otherwise, access is granted.</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
<para>In order to implement a whitelisting IP firewall, it is recommended to use a
|
<para>In order to implement an allow-listing IP firewall, it is recommended to use a
|
||||||
<varname>IPAddressDeny=</varname><constant>any</constant> setting on an upper-level slice unit (such as the
|
<varname>IPAddressDeny=</varname><constant>any</constant> setting on an upper-level slice unit
|
||||||
root slice <filename>-.slice</filename> or the slice containing all system services
|
(such as the root slice <filename>-.slice</filename> or the slice containing all system services
|
||||||
<filename>system.slice</filename> – see
|
<filename>system.slice</filename> – see
|
||||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||||
details on these slice units), plus individual per-service <varname>IPAddressAllow=</varname> lines
|
for details on these slice units), plus individual per-service <varname>IPAddressAllow=</varname>
|
||||||
permitting network access to relevant services, and only them.</para>
|
lines permitting network access to relevant services, and only them.</para>
|
||||||
|
|
||||||
<para>Note that for socket-activated services, the IP access list configured on the socket unit
|
<para>Note that for socket-activated services, the IP access list configured on the socket unit
|
||||||
applies to all sockets associated with it directly, but not to any sockets created by the
|
applies to all sockets associated with it directly, but not to any sockets created by the
|
||||||
|
@ -719,7 +719,7 @@
|
||||||
<para>The device node specifier is either a path to a device node in the file system, starting with
|
<para>The device node specifier is either a path to a device node in the file system, starting with
|
||||||
<filename>/dev/</filename>, or a string starting with either <literal>char-</literal> or
|
<filename>/dev/</filename>, or a string starting with either <literal>char-</literal> or
|
||||||
<literal>block-</literal> followed by a device group name, as listed in
|
<literal>block-</literal> followed by a device group name, as listed in
|
||||||
<filename>/proc/devices</filename>. The latter is useful to whitelist all current and future
|
<filename>/proc/devices</filename>. The latter is useful to allow-list all current and future
|
||||||
devices belonging to a specific device group at once. The device group is matched according to
|
devices belonging to a specific device group at once. The device group is matched according to
|
||||||
filename globbing rules, you may hence use the <literal>*</literal> and <literal>?</literal>
|
filename globbing rules, you may hence use the <literal>*</literal> and <literal>?</literal>
|
||||||
wildcards. (Note that such globbing wildcards are not available for device node path
|
wildcards. (Note that such globbing wildcards are not available for device node path
|
||||||
|
@ -733,9 +733,9 @@
|
||||||
all pseudo TTYs and all ALSA sound devices, respectively. <literal>char-cpu/*</literal> is a
|
all pseudo TTYs and all ALSA sound devices, respectively. <literal>char-cpu/*</literal> is a
|
||||||
specifier matching all CPU related device groups.</para>
|
specifier matching all CPU related device groups.</para>
|
||||||
|
|
||||||
<para>Note that whitelists defined this way should only reference device groups which are
|
<para>Note that allow lists defined this way should only reference device groups which are
|
||||||
resolvable at the time the unit is started. Any device groups not resolvable then are not added to
|
resolvable at the time the unit is started. Any device groups not resolvable then are not added to
|
||||||
the device whitelist. In order to work around this limitation, consider extending service units
|
the device allow list. In order to work around this limitation, consider extending service units
|
||||||
with a pair of <command>After=modprobe@xyz.service</command> and
|
with a pair of <command>After=modprobe@xyz.service</command> and
|
||||||
<command>Wants=modprobe@xyz.service</command> lines that load the necessary kernel module
|
<command>Wants=modprobe@xyz.service</command> lines that load the necessary kernel module
|
||||||
implementing the device group if missing.
|
implementing the device group if missing.
|
||||||
|
|
|
@ -1035,6 +1035,8 @@ if want_libcryptsetup != 'false' and not skip_deps
|
||||||
|
|
||||||
conf.set10('HAVE_CRYPT_SET_METADATA_SIZE',
|
conf.set10('HAVE_CRYPT_SET_METADATA_SIZE',
|
||||||
have and cc.has_function('crypt_set_metadata_size', dependencies : libcryptsetup))
|
have and cc.has_function('crypt_set_metadata_size', dependencies : libcryptsetup))
|
||||||
|
conf.set10('HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY',
|
||||||
|
have and cc.has_function('crypt_activate_by_signed_key', dependencies : libcryptsetup))
|
||||||
else
|
else
|
||||||
have = false
|
have = false
|
||||||
libcryptsetup = []
|
libcryptsetup = []
|
||||||
|
|
|
@ -13,6 +13,7 @@ AUTOPKGTEST_DIR="${CACHE_DIR}/autopkgtest"
|
||||||
# semaphore cannot expose these, but useful for interactive/local runs
|
# semaphore cannot expose these, but useful for interactive/local runs
|
||||||
ARTIFACTS_DIR=/tmp/artifacts
|
ARTIFACTS_DIR=/tmp/artifacts
|
||||||
PHASES=(${@:-SETUP RUN})
|
PHASES=(${@:-SETUP RUN})
|
||||||
|
UBUNTU_RELEASE="$(lsb_release -cs)"
|
||||||
|
|
||||||
create_container() {
|
create_container() {
|
||||||
# create autopkgtest LXC image; this sometimes fails with "Unable to fetch
|
# create autopkgtest LXC image; this sometimes fails with "Unable to fetch
|
||||||
|
@ -51,9 +52,9 @@ for phase in "${PHASES[@]}"; do
|
||||||
sudo rm -f /etc/apt/sources.list.d/*
|
sudo rm -f /etc/apt/sources.list.d/*
|
||||||
|
|
||||||
# enable backports for latest LXC
|
# enable backports for latest LXC
|
||||||
echo 'deb http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse' | sudo tee -a /etc/apt/sources.list.d/backports.list
|
echo "deb http://archive.ubuntu.com/ubuntu $UBUNTU_RELEASE-backports main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/backports.list
|
||||||
sudo apt-get -q update
|
sudo apt-get -q update
|
||||||
sudo apt-get install -y -t xenial-backports lxc
|
sudo apt-get install -y -t "$UBUNTU_RELEASE-backports" lxc
|
||||||
sudo apt-get install -y python3-debian git dpkg-dev fakeroot
|
sudo apt-get install -y python3-debian git dpkg-dev fakeroot
|
||||||
|
|
||||||
[ -d $AUTOPKGTEST_DIR ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR"
|
[ -d $AUTOPKGTEST_DIR ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR"
|
||||||
|
|
|
@ -71,7 +71,7 @@ _systemd_nspawn() {
|
||||||
--pivot-root --property --private-users --network-namespace-path --network-ipvlan
|
--pivot-root --property --private-users --network-namespace-path --network-ipvlan
|
||||||
--network-veth-extra --network-zone -p --port --system-call-filter --overlay --overlay-ro
|
--network-veth-extra --network-zone -p --port --system-call-filter --overlay --overlay-ro
|
||||||
--settings --rlimit --hostname --no-new-privileges --oom-score-adjust --cpu-affinity
|
--settings --rlimit --hostname --no-new-privileges --oom-score-adjust --cpu-affinity
|
||||||
--resolv-conf --timezone'
|
--resolv-conf --timezone --root-hash-sig'
|
||||||
)
|
)
|
||||||
|
|
||||||
_init_completion || return
|
_init_completion || return
|
||||||
|
@ -183,6 +183,10 @@ _systemd_nspawn() {
|
||||||
--timezone)
|
--timezone)
|
||||||
comps=$( systemd-nspawn --timezone=help 2>/dev/null )
|
comps=$( systemd-nspawn --timezone=help 2>/dev/null )
|
||||||
;;
|
;;
|
||||||
|
--root-hash-sig)
|
||||||
|
compopt -o nospace
|
||||||
|
comps=$( compgen -A file -- "$cur" )
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -91,7 +91,7 @@ struct security_info {
|
||||||
|
|
||||||
char **system_call_architectures;
|
char **system_call_architectures;
|
||||||
|
|
||||||
bool system_call_filter_whitelist;
|
bool system_call_filter_allow_list;
|
||||||
Set *system_call_filter;
|
Set *system_call_filter;
|
||||||
|
|
||||||
uint32_t _umask;
|
uint32_t _umask;
|
||||||
|
@ -492,7 +492,7 @@ static int assess_system_call_architectures(
|
||||||
|
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
|
|
||||||
static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterSet *f) {
|
static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f) {
|
||||||
const char *syscall;
|
const char *syscall;
|
||||||
|
|
||||||
NULSTR_FOREACH(syscall, f->value) {
|
NULSTR_FOREACH(syscall, f->value) {
|
||||||
|
@ -502,7 +502,7 @@ static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterS
|
||||||
const SyscallFilterSet *g;
|
const SyscallFilterSet *g;
|
||||||
|
|
||||||
assert_se(g = syscall_filter_set_find(syscall));
|
assert_se(g = syscall_filter_set_find(syscall));
|
||||||
if (syscall_names_in_filter(s, whitelist, g))
|
if (syscall_names_in_filter(s, allow_list, g))
|
||||||
return true; /* bad! */
|
return true; /* bad! */
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -513,7 +513,7 @@ static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterS
|
||||||
if (id < 0)
|
if (id < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (set_contains(s, syscall) == whitelist) {
|
if (set_contains(s, syscall) == allow_list) {
|
||||||
log_debug("Offending syscall filter item: %s", syscall);
|
log_debug("Offending syscall filter item: %s", syscall);
|
||||||
return true; /* bad! */
|
return true; /* bad! */
|
||||||
}
|
}
|
||||||
|
@ -541,30 +541,30 @@ static int assess_system_call_filter(
|
||||||
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
|
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
|
||||||
f = syscall_filter_sets + a->parameter;
|
f = syscall_filter_sets + a->parameter;
|
||||||
|
|
||||||
if (!info->system_call_filter_whitelist && set_isempty(info->system_call_filter)) {
|
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
|
||||||
d = strdup("Service does not filter system calls");
|
d = strdup("Service does not filter system calls");
|
||||||
b = 10;
|
b = 10;
|
||||||
} else {
|
} else {
|
||||||
bool bad;
|
bool bad;
|
||||||
|
|
||||||
log_debug("Analyzing system call filter, checking against: %s", f->name);
|
log_debug("Analyzing system call filter, checking against: %s", f->name);
|
||||||
bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_whitelist, f);
|
bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_allow_list, f);
|
||||||
log_debug("Result: %s", bad ? "bad" : "good");
|
log_debug("Result: %s", bad ? "bad" : "good");
|
||||||
|
|
||||||
if (info->system_call_filter_whitelist) {
|
if (info->system_call_filter_allow_list) {
|
||||||
if (bad) {
|
if (bad) {
|
||||||
(void) asprintf(&d, "System call whitelist defined for service, and %s is included", f->name);
|
(void) asprintf(&d, "System call allow list defined for service, and %s is included", f->name);
|
||||||
b = 9;
|
b = 9;
|
||||||
} else {
|
} else {
|
||||||
(void) asprintf(&d, "System call whitelist defined for service, and %s is not included", f->name);
|
(void) asprintf(&d, "System call allow list defined for service, and %s is not included", f->name);
|
||||||
b = 0;
|
b = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bad) {
|
if (bad) {
|
||||||
(void) asprintf(&d, "System call blacklist defined for service, and %s is not included", f->name);
|
(void) asprintf(&d, "System call deny list defined for service, and %s is not included", f->name);
|
||||||
b = 10;
|
b = 10;
|
||||||
} else {
|
} else {
|
||||||
(void) asprintf(&d, "System call blacklist defined for service, and %s is included", f->name);
|
(void) asprintf(&d, "System call deny list defined for service, and %s is included", f->name);
|
||||||
b = 5;
|
b = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -599,13 +599,13 @@ static int assess_ip_address_allow(
|
||||||
d = strdup("Service defines custom ingress/egress IP filters with BPF programs");
|
d = strdup("Service defines custom ingress/egress IP filters with BPF programs");
|
||||||
b = 0;
|
b = 0;
|
||||||
} else if (!info->ip_address_deny_all) {
|
} else if (!info->ip_address_deny_all) {
|
||||||
d = strdup("Service does not define an IP address whitelist");
|
d = strdup("Service does not define an IP address allow list");
|
||||||
b = 10;
|
b = 10;
|
||||||
} else if (info->ip_address_allow_other) {
|
} else if (info->ip_address_allow_other) {
|
||||||
d = strdup("Service defines IP address whitelist with non-localhost entries");
|
d = strdup("Service defines IP address allow list with non-localhost entries");
|
||||||
b = 5;
|
b = 5;
|
||||||
} else if (info->ip_address_allow_localhost) {
|
} else if (info->ip_address_allow_localhost) {
|
||||||
d = strdup("Service defines IP address whitelist with only localhost entries");
|
d = strdup("Service defines IP address allow list with only localhost entries");
|
||||||
b = 2;
|
b = 2;
|
||||||
} else {
|
} else {
|
||||||
d = strdup("Service blocks all IP address ranges");
|
d = strdup("Service blocks all IP address ranges");
|
||||||
|
@ -1639,7 +1639,7 @@ static int property_read_restrict_address_families(
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
struct security_info *info = userdata;
|
struct security_info *info = userdata;
|
||||||
int whitelist, r;
|
int allow_list, r;
|
||||||
|
|
||||||
assert(bus);
|
assert(bus);
|
||||||
assert(member);
|
assert(member);
|
||||||
|
@ -1649,7 +1649,7 @@ static int property_read_restrict_address_families(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_bus_message_read(m, "b", &whitelist);
|
r = sd_bus_message_read(m, "b", &allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1657,7 +1657,7 @@ static int property_read_restrict_address_families(
|
||||||
info->restrict_address_family_unix =
|
info->restrict_address_family_unix =
|
||||||
info->restrict_address_family_netlink =
|
info->restrict_address_family_netlink =
|
||||||
info->restrict_address_family_packet =
|
info->restrict_address_family_packet =
|
||||||
info->restrict_address_family_other = whitelist;
|
info->restrict_address_family_other = allow_list;
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(m, 'a', "s");
|
r = sd_bus_message_enter_container(m, 'a', "s");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -1673,15 +1673,15 @@ static int property_read_restrict_address_families(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (STR_IN_SET(name, "AF_INET", "AF_INET6"))
|
if (STR_IN_SET(name, "AF_INET", "AF_INET6"))
|
||||||
info->restrict_address_family_inet = !whitelist;
|
info->restrict_address_family_inet = !allow_list;
|
||||||
else if (streq(name, "AF_UNIX"))
|
else if (streq(name, "AF_UNIX"))
|
||||||
info->restrict_address_family_unix = !whitelist;
|
info->restrict_address_family_unix = !allow_list;
|
||||||
else if (streq(name, "AF_NETLINK"))
|
else if (streq(name, "AF_NETLINK"))
|
||||||
info->restrict_address_family_netlink = !whitelist;
|
info->restrict_address_family_netlink = !allow_list;
|
||||||
else if (streq(name, "AF_PACKET"))
|
else if (streq(name, "AF_PACKET"))
|
||||||
info->restrict_address_family_packet = !whitelist;
|
info->restrict_address_family_packet = !allow_list;
|
||||||
else
|
else
|
||||||
info->restrict_address_family_other = !whitelist;
|
info->restrict_address_family_other = !allow_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_bus_message_exit_container(m);
|
r = sd_bus_message_exit_container(m);
|
||||||
|
@ -1699,7 +1699,7 @@ static int property_read_system_call_filter(
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
struct security_info *info = userdata;
|
struct security_info *info = userdata;
|
||||||
int whitelist, r;
|
int allow_list, r;
|
||||||
|
|
||||||
assert(bus);
|
assert(bus);
|
||||||
assert(member);
|
assert(member);
|
||||||
|
@ -1709,11 +1709,11 @@ static int property_read_system_call_filter(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_bus_message_read(m, "b", &whitelist);
|
r = sd_bus_message_read(m, "b", &allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
info->system_call_filter_whitelist = whitelist;
|
info->system_call_filter_allow_list = allow_list;
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(m, 'a', "s");
|
r = sd_bus_message_enter_container(m, 'a', "s");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "device-nodes.h"
|
#include "device-nodes.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
|
||||||
int whitelisted_char_for_devnode(char c, const char *white) {
|
int allow_listed_char_for_devnode(char c, const char *white) {
|
||||||
|
|
||||||
if ((c >= '0' && c <= '9') ||
|
if ((c >= '0' && c <= '9') ||
|
||||||
(c >= 'A' && c <= 'Z') ||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
|
@ -38,7 +38,7 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) {
|
||||||
j += seqlen;
|
j += seqlen;
|
||||||
i += (seqlen-1);
|
i += (seqlen-1);
|
||||||
|
|
||||||
} else if (str[i] == '\\' || !whitelisted_char_for_devnode(str[i], NULL)) {
|
} else if (str[i] == '\\' || !allow_listed_char_for_devnode(str[i], NULL)) {
|
||||||
|
|
||||||
if (len-j < 4)
|
if (len-j < 4)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
|
|
||||||
int encode_devnode_name(const char *str, char *str_enc, size_t len);
|
int encode_devnode_name(const char *str, char *str_enc, size_t len);
|
||||||
int whitelisted_char_for_devnode(char c, const char *additional);
|
int allow_listed_char_for_devnode(char c, const char *additional);
|
||||||
|
|
||||||
#define DEV_NUM_PATH_MAX \
|
#define DEV_NUM_PATH_MAX \
|
||||||
(STRLEN("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t))
|
(STRLEN("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t))
|
||||||
|
|
|
@ -210,9 +210,9 @@ int efi_set_variable(
|
||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Newer efivarfs protects variables that are not in a whitelist with FS_IMMUTABLE_FL by default, to protect
|
/* Newer efivarfs protects variables that are not in an allow list with FS_IMMUTABLE_FL by default,
|
||||||
* them for accidental removal and modification. We are not changing these variables accidentally however,
|
* to protect them for accidental removal and modification. We are not changing these variables
|
||||||
* hence let's unset the bit first. */
|
* accidentally however, hence let's unset the bit first. */
|
||||||
|
|
||||||
r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags);
|
r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
|
|
|
@ -1576,7 +1576,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
|
||||||
|
|
||||||
d = opendir(p);
|
d = opendir(p);
|
||||||
if (!d) {
|
if (!d) {
|
||||||
if (errno == ENOENT) /* Doesn't have slaves */
|
if (errno == ENOENT) /* Doesn't have underlying devices */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return -errno;
|
return -errno;
|
||||||
|
@ -1592,7 +1592,7 @@ static int blockdev_is_encrypted(const char *sysfs_path, unsigned depth_left) {
|
||||||
if (errno != 0)
|
if (errno != 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
break; /* No more slaves */
|
break; /* No more underlying devices */
|
||||||
}
|
}
|
||||||
|
|
||||||
q = path_join(p, de->d_name);
|
q = path_join(p, de->d_name);
|
||||||
|
|
|
@ -10,3 +10,19 @@
|
||||||
#undef CAP_LAST_CAP
|
#undef CAP_LAST_CAP
|
||||||
#define CAP_LAST_CAP CAP_AUDIT_READ
|
#define CAP_LAST_CAP CAP_AUDIT_READ
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* 980737282232b752bb14dab96d77665c15889c36 (5.8) */
|
||||||
|
#ifndef CAP_PERFMON
|
||||||
|
#define CAP_PERFMON 38
|
||||||
|
|
||||||
|
#undef CAP_LAST_CAP
|
||||||
|
#define CAP_LAST_CAP CAP_PERFMON
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* a17b53c4a4b55ec322c132b6670743612229ee9c (5.8) */
|
||||||
|
#ifndef CAP_BPF
|
||||||
|
#define CAP_BPF 39
|
||||||
|
|
||||||
|
#undef CAP_LAST_CAP
|
||||||
|
#define CAP_LAST_CAP CAP_BPF
|
||||||
|
#endif
|
||||||
|
|
|
@ -38,7 +38,7 @@ static int bpf_access_type(const char *acc) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_prog_whitelist_device(
|
static int bpf_prog_allow_list_device(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
char type,
|
char type,
|
||||||
int major,
|
int major,
|
||||||
|
@ -80,7 +80,7 @@ static int bpf_prog_whitelist_device(
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_prog_whitelist_major(
|
static int bpf_prog_allow_list_major(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
char type,
|
char type,
|
||||||
int major,
|
int major,
|
||||||
|
@ -120,7 +120,7 @@ static int bpf_prog_whitelist_major(
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bpf_prog_whitelist_class(
|
static int bpf_prog_allow_list_class(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
char type,
|
char type,
|
||||||
const char *acc) {
|
const char *acc) {
|
||||||
|
@ -161,7 +161,7 @@ static int bpf_prog_whitelist_class(
|
||||||
int bpf_devices_cgroup_init(
|
int bpf_devices_cgroup_init(
|
||||||
BPFProgram **ret,
|
BPFProgram **ret,
|
||||||
CGroupDevicePolicy policy,
|
CGroupDevicePolicy policy,
|
||||||
bool whitelist) {
|
bool allow_list) {
|
||||||
|
|
||||||
const struct bpf_insn pre_insn[] = {
|
const struct bpf_insn pre_insn[] = {
|
||||||
/* load device type to r2 */
|
/* load device type to r2 */
|
||||||
|
@ -188,14 +188,14 @@ int bpf_devices_cgroup_init(
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
if (policy == CGROUP_DEVICE_POLICY_AUTO && !whitelist)
|
if (policy == CGROUP_DEVICE_POLICY_AUTO && !allow_list)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE, &prog);
|
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE, &prog);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Loading device control BPF program failed: %m");
|
return log_error_errno(r, "Loading device control BPF program failed: %m");
|
||||||
|
|
||||||
if (policy == CGROUP_DEVICE_POLICY_CLOSED || whitelist) {
|
if (policy == CGROUP_DEVICE_POLICY_CLOSED || allow_list) {
|
||||||
r = bpf_program_add_instructions(prog, pre_insn, ELEMENTSOF(pre_insn));
|
r = bpf_program_add_instructions(prog, pre_insn, ELEMENTSOF(pre_insn));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Extending device control BPF program failed: %m");
|
return log_error_errno(r, "Extending device control BPF program failed: %m");
|
||||||
|
@ -209,7 +209,7 @@ int bpf_devices_cgroup_init(
|
||||||
int bpf_devices_apply_policy(
|
int bpf_devices_apply_policy(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
CGroupDevicePolicy policy,
|
CGroupDevicePolicy policy,
|
||||||
bool whitelist,
|
bool allow_list,
|
||||||
const char *cgroup_path,
|
const char *cgroup_path,
|
||||||
BPFProgram **prog_installed) {
|
BPFProgram **prog_installed) {
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ int bpf_devices_apply_policy(
|
||||||
if (!prog)
|
if (!prog)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
const bool deny_everything = policy == CGROUP_DEVICE_POLICY_STRICT && !whitelist;
|
const bool deny_everything = policy == CGROUP_DEVICE_POLICY_STRICT && !allow_list;
|
||||||
|
|
||||||
const struct bpf_insn post_insn[] = {
|
const struct bpf_insn post_insn[] = {
|
||||||
/* return DENY */
|
/* return DENY */
|
||||||
|
@ -325,7 +325,7 @@ int bpf_devices_supported(void) {
|
||||||
return supported = 1;
|
return supported = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int whitelist_device_pattern(
|
static int allow_list_device_pattern(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
const char *path,
|
const char *path,
|
||||||
char type,
|
char type,
|
||||||
|
@ -340,11 +340,11 @@ static int whitelist_device_pattern(
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (maj && min)
|
if (maj && min)
|
||||||
return bpf_prog_whitelist_device(prog, type, *maj, *min, acc);
|
return bpf_prog_allow_list_device(prog, type, *maj, *min, acc);
|
||||||
else if (maj)
|
else if (maj)
|
||||||
return bpf_prog_whitelist_major(prog, type, *maj, acc);
|
return bpf_prog_allow_list_major(prog, type, *maj, acc);
|
||||||
else
|
else
|
||||||
return bpf_prog_whitelist_class(prog, type, acc);
|
return bpf_prog_allow_list_class(prog, type, acc);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
char buf[2+DECIMAL_STR_MAX(unsigned)*2+2+4];
|
char buf[2+DECIMAL_STR_MAX(unsigned)*2+2+4];
|
||||||
|
@ -369,7 +369,7 @@ static int whitelist_device_pattern(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_devices_whitelist_device(
|
int bpf_devices_allow_list_device(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *node,
|
const char *node,
|
||||||
|
@ -405,10 +405,10 @@ int bpf_devices_whitelist_device(
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned maj = major(rdev), min = minor(rdev);
|
unsigned maj = major(rdev), min = minor(rdev);
|
||||||
return whitelist_device_pattern(prog, path, S_ISCHR(mode) ? 'c' : 'b', &maj, &min, acc);
|
return allow_list_device_pattern(prog, path, S_ISCHR(mode) ? 'c' : 'b', &maj, &min, acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_devices_whitelist_major(
|
int bpf_devices_allow_list_major(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
const char *path,
|
const char *path,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -424,12 +424,12 @@ int bpf_devices_whitelist_major(
|
||||||
|
|
||||||
if (streq(name, "*"))
|
if (streq(name, "*"))
|
||||||
/* If the name is a wildcard, then apply this list to all devices of this type */
|
/* If the name is a wildcard, then apply this list to all devices of this type */
|
||||||
return whitelist_device_pattern(prog, path, type, NULL, NULL, acc);
|
return allow_list_device_pattern(prog, path, type, NULL, NULL, acc);
|
||||||
|
|
||||||
if (safe_atou(name, &maj) >= 0 && DEVICE_MAJOR_VALID(maj))
|
if (safe_atou(name, &maj) >= 0 && DEVICE_MAJOR_VALID(maj))
|
||||||
/* The name is numeric and suitable as major. In that case, let's take its major, and create
|
/* The name is numeric and suitable as major. In that case, let's take its major, and create
|
||||||
* the entry directly. */
|
* the entry directly. */
|
||||||
return whitelist_device_pattern(prog, path, type, &maj, NULL, acc);
|
return allow_list_device_pattern(prog, path, type, &maj, NULL, acc);
|
||||||
|
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
bool good = false, any = false;
|
bool good = false, any = false;
|
||||||
|
@ -486,17 +486,17 @@ int bpf_devices_whitelist_major(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
any = true;
|
any = true;
|
||||||
(void) whitelist_device_pattern(prog, path, type, &maj, NULL, acc);
|
(void) allow_list_device_pattern(prog, path, type, &maj, NULL, acc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!any)
|
if (!any)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
|
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
|
||||||
"Device whitelist pattern \"%s\" did not match anything.", name);
|
"Device allow list pattern \"%s\" did not match anything.", name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_devices_whitelist_static(
|
int bpf_devices_allow_list_static(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
const char *path) {
|
const char *path) {
|
||||||
|
|
||||||
|
@ -515,13 +515,13 @@ int bpf_devices_whitelist_static(
|
||||||
|
|
||||||
const char *node, *acc;
|
const char *node, *acc;
|
||||||
NULSTR_FOREACH_PAIR(node, acc, auto_devices) {
|
NULSTR_FOREACH_PAIR(node, acc, auto_devices) {
|
||||||
k = bpf_devices_whitelist_device(prog, path, node, acc);
|
k = bpf_devices_allow_list_device(prog, path, node, acc);
|
||||||
if (r >= 0 && k < 0)
|
if (r >= 0 && k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PTS (/dev/pts) devices may not be duplicated, but accessed */
|
/* PTS (/dev/pts) devices may not be duplicated, but accessed */
|
||||||
k = bpf_devices_whitelist_major(prog, path, "pts", 'c', "rw");
|
k = bpf_devices_allow_list_major(prog, path, "pts", 'c', "rw");
|
||||||
if (r >= 0 && k < 0)
|
if (r >= 0 && k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
|
|
||||||
typedef struct BPFProgram BPFProgram;
|
typedef struct BPFProgram BPFProgram;
|
||||||
|
|
||||||
int bpf_devices_cgroup_init(BPFProgram **ret, CGroupDevicePolicy policy, bool whitelist);
|
int bpf_devices_cgroup_init(BPFProgram **ret, CGroupDevicePolicy policy, bool allow_list);
|
||||||
int bpf_devices_apply_policy(
|
int bpf_devices_apply_policy(
|
||||||
BPFProgram *prog,
|
BPFProgram *prog,
|
||||||
CGroupDevicePolicy policy,
|
CGroupDevicePolicy policy,
|
||||||
bool whitelist,
|
bool allow_list,
|
||||||
const char *cgroup_path,
|
const char *cgroup_path,
|
||||||
BPFProgram **prog_installed);
|
BPFProgram **prog_installed);
|
||||||
|
|
||||||
int bpf_devices_supported(void);
|
int bpf_devices_supported(void);
|
||||||
int bpf_devices_whitelist_device(BPFProgram *prog, const char *path, const char *node, const char *acc);
|
int bpf_devices_allow_list_device(BPFProgram *prog, const char *path, const char *node, const char *acc);
|
||||||
int bpf_devices_whitelist_major(BPFProgram *prog, const char *path, const char *name, char type, const char *acc);
|
int bpf_devices_allow_list_major(BPFProgram *prog, const char *path, const char *name, char type, const char *acc);
|
||||||
int bpf_devices_whitelist_static(BPFProgram *prog, const char *path);
|
int bpf_devices_allow_list_static(BPFProgram *prog, const char *path);
|
||||||
|
|
|
@ -990,12 +990,12 @@ static int cgroup_apply_devices(Unit *u) {
|
||||||
"Failed to reset devices.allow/devices.deny: %m");
|
"Failed to reset devices.allow/devices.deny: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool whitelist_static = policy == CGROUP_DEVICE_POLICY_CLOSED ||
|
bool allow_list_static = policy == CGROUP_DEVICE_POLICY_CLOSED ||
|
||||||
(policy == CGROUP_DEVICE_POLICY_AUTO && c->device_allow);
|
(policy == CGROUP_DEVICE_POLICY_AUTO && c->device_allow);
|
||||||
if (whitelist_static)
|
if (allow_list_static)
|
||||||
(void) bpf_devices_whitelist_static(prog, path);
|
(void) bpf_devices_allow_list_static(prog, path);
|
||||||
|
|
||||||
bool any = whitelist_static;
|
bool any = allow_list_static;
|
||||||
LIST_FOREACH(device_allow, a, c->device_allow) {
|
LIST_FOREACH(device_allow, a, c->device_allow) {
|
||||||
char acc[4], *val;
|
char acc[4], *val;
|
||||||
unsigned k = 0;
|
unsigned k = 0;
|
||||||
|
@ -1011,11 +1011,11 @@ static int cgroup_apply_devices(Unit *u) {
|
||||||
acc[k++] = 0;
|
acc[k++] = 0;
|
||||||
|
|
||||||
if (path_startswith(a->path, "/dev/"))
|
if (path_startswith(a->path, "/dev/"))
|
||||||
r = bpf_devices_whitelist_device(prog, path, a->path, acc);
|
r = bpf_devices_allow_list_device(prog, path, a->path, acc);
|
||||||
else if ((val = startswith(a->path, "block-")))
|
else if ((val = startswith(a->path, "block-")))
|
||||||
r = bpf_devices_whitelist_major(prog, path, val, 'b', acc);
|
r = bpf_devices_allow_list_major(prog, path, val, 'b', acc);
|
||||||
else if ((val = startswith(a->path, "char-")))
|
else if ((val = startswith(a->path, "char-")))
|
||||||
r = bpf_devices_whitelist_major(prog, path, val, 'c', acc);
|
r = bpf_devices_allow_list_major(prog, path, val, 'c', acc);
|
||||||
else {
|
else {
|
||||||
log_unit_debug(u, "Ignoring device '%s' while writing cgroup attribute.", a->path);
|
log_unit_debug(u, "Ignoring device '%s' while writing cgroup attribute.", a->path);
|
||||||
continue;
|
continue;
|
||||||
|
@ -1029,7 +1029,7 @@ static int cgroup_apply_devices(Unit *u) {
|
||||||
log_unit_warning_errno(u, SYNTHETIC_ERRNO(ENODEV), "No devices matched by device filter.");
|
log_unit_warning_errno(u, SYNTHETIC_ERRNO(ENODEV), "No devices matched by device filter.");
|
||||||
|
|
||||||
/* The kernel verifier would reject a program we would build with the normal intro and outro
|
/* The kernel verifier would reject a program we would build with the normal intro and outro
|
||||||
but no whitelisting rules (outro would contain an unreachable instruction for successful
|
but no allow-listing rules (outro would contain an unreachable instruction for successful
|
||||||
return). */
|
return). */
|
||||||
policy = CGROUP_DEVICE_POLICY_STRICT;
|
policy = CGROUP_DEVICE_POLICY_STRICT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,7 +370,7 @@ static int property_get_syscall_filter(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
|
r = sd_bus_message_append(reply, "b", c->syscall_allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -536,7 +536,7 @@ static int property_get_address_families(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
|
r = sd_bus_message_append(reply, "b", c->address_families_allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -765,6 +765,25 @@ static int property_get_root_hash(
|
||||||
return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
|
return sd_bus_message_append_array(reply, 'y', c->root_hash, c->root_hash_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int property_get_root_hash_sig(
|
||||||
|
sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
ExecContext *c = userdata;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(c);
|
||||||
|
assert(property);
|
||||||
|
assert(reply);
|
||||||
|
|
||||||
|
return sd_bus_message_append_array(reply, 'y', c->root_hash_sig, c->root_hash_sig_size);
|
||||||
|
}
|
||||||
|
|
||||||
const sd_bus_vtable bus_exec_vtable[] = {
|
const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
@ -809,6 +828,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHash", "ay", property_get_root_hash, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHashPath", "s", NULL, offsetof(ExecContext, root_hash_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
@ -1326,6 +1347,53 @@ int bus_exec_context_set_transient_property(
|
||||||
return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
|
return bus_set_transient_path(u, "RootHash", &c->root_hash_path, message, flags, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(name, "RootHashSignature")) {
|
||||||
|
const void *roothash_sig_decoded;
|
||||||
|
size_t roothash_sig_decoded_size;
|
||||||
|
|
||||||
|
r = sd_bus_message_read_array(message, 'y', &roothash_sig_decoded, &roothash_sig_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
_cleanup_free_ char *encoded = NULL;
|
||||||
|
|
||||||
|
if (roothash_sig_decoded_size == 0) {
|
||||||
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "RootHashSignature=");
|
||||||
|
} else {
|
||||||
|
_cleanup_free_ void *p;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
len = base64mem(roothash_sig_decoded, roothash_sig_decoded_size, &encoded);
|
||||||
|
if (len < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
p = memdup(roothash_sig_decoded, roothash_sig_decoded_size);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(c->root_hash_sig, p);
|
||||||
|
c->root_hash_sig_size = roothash_sig_decoded_size;
|
||||||
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "RootHashSignature=base64:%s", encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "RootHashSignaturePath")) {
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
|
||||||
|
return bus_set_transient_path(u, "RootHashSignature", &c->root_hash_sig_path, message, flags, error);
|
||||||
|
}
|
||||||
|
|
||||||
if (streq(name, "RootVerity"))
|
if (streq(name, "RootVerity"))
|
||||||
return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
|
return bus_set_transient_path(u, name, &c->root_verity, message, flags, error);
|
||||||
|
|
||||||
|
@ -1672,14 +1740,14 @@ int bus_exec_context_set_transient_property(
|
||||||
return bus_set_transient_errno(u, name, &c->syscall_errno, message, flags, error);
|
return bus_set_transient_errno(u, name, &c->syscall_errno, message, flags, error);
|
||||||
|
|
||||||
if (streq(name, "SystemCallFilter")) {
|
if (streq(name, "SystemCallFilter")) {
|
||||||
int whitelist;
|
int allow_list;
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(message, 'r', "bas");
|
r = sd_bus_message_enter_container(message, 'r', "bas");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_bus_message_read(message, "b", &whitelist);
|
r = sd_bus_message_read(message, "b", &allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1693,11 +1761,11 @@ int bus_exec_context_set_transient_property(
|
||||||
|
|
||||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
_cleanup_free_ char *joined = NULL;
|
_cleanup_free_ char *joined = NULL;
|
||||||
SeccompParseFlags invert_flag = whitelist ? 0 : SECCOMP_PARSE_INVERT;
|
SeccompParseFlags invert_flag = allow_list ? 0 : SECCOMP_PARSE_INVERT;
|
||||||
char **s;
|
char **s;
|
||||||
|
|
||||||
if (strv_isempty(l)) {
|
if (strv_isempty(l)) {
|
||||||
c->syscall_whitelist = false;
|
c->syscall_allow_list = false;
|
||||||
c->syscall_filter = hashmap_free(c->syscall_filter);
|
c->syscall_filter = hashmap_free(c->syscall_filter);
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "SystemCallFilter=");
|
unit_write_settingf(u, flags, name, "SystemCallFilter=");
|
||||||
|
@ -1709,14 +1777,14 @@ int bus_exec_context_set_transient_property(
|
||||||
if (!c->syscall_filter)
|
if (!c->syscall_filter)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
c->syscall_whitelist = whitelist;
|
c->syscall_allow_list = allow_list;
|
||||||
|
|
||||||
if (c->syscall_whitelist) {
|
if (c->syscall_allow_list) {
|
||||||
r = seccomp_parse_syscall_filter("@default",
|
r = seccomp_parse_syscall_filter("@default",
|
||||||
-1,
|
-1,
|
||||||
c->syscall_filter,
|
c->syscall_filter,
|
||||||
SECCOMP_PARSE_PERMISSIVE |
|
SECCOMP_PARSE_PERMISSIVE |
|
||||||
SECCOMP_PARSE_WHITELIST | invert_flag,
|
SECCOMP_PARSE_ALLOW_LIST | invert_flag,
|
||||||
u->id,
|
u->id,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -1737,7 +1805,7 @@ int bus_exec_context_set_transient_property(
|
||||||
c->syscall_filter,
|
c->syscall_filter,
|
||||||
SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
|
SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE |
|
||||||
invert_flag |
|
invert_flag |
|
||||||
(c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
|
(c->syscall_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
|
||||||
u->id,
|
u->id,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -1748,7 +1816,7 @@ int bus_exec_context_set_transient_property(
|
||||||
if (!joined)
|
if (!joined)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "SystemCallFilter=%s%s", whitelist ? "" : "~", joined);
|
unit_write_settingf(u, flags, name, "SystemCallFilter=%s%s", allow_list ? "" : "~", joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1792,14 +1860,14 @@ int bus_exec_context_set_transient_property(
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
} else if (streq(name, "RestrictAddressFamilies")) {
|
} else if (streq(name, "RestrictAddressFamilies")) {
|
||||||
int whitelist;
|
int allow_list;
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(message, 'r', "bas");
|
r = sd_bus_message_enter_container(message, 'r', "bas");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_bus_message_read(message, "b", &whitelist);
|
r = sd_bus_message_read(message, "b", &allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -1816,7 +1884,7 @@ int bus_exec_context_set_transient_property(
|
||||||
char **s;
|
char **s;
|
||||||
|
|
||||||
if (strv_isempty(l)) {
|
if (strv_isempty(l)) {
|
||||||
c->address_families_whitelist = false;
|
c->address_families_allow_list = false;
|
||||||
c->address_families = set_free(c->address_families);
|
c->address_families = set_free(c->address_families);
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "RestrictAddressFamilies=");
|
unit_write_settingf(u, flags, name, "RestrictAddressFamilies=");
|
||||||
|
@ -1828,7 +1896,7 @@ int bus_exec_context_set_transient_property(
|
||||||
if (!c->address_families)
|
if (!c->address_families)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
c->address_families_whitelist = whitelist;
|
c->address_families_allow_list = allow_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRV_FOREACH(s, l) {
|
STRV_FOREACH(s, l) {
|
||||||
|
@ -1838,7 +1906,7 @@ int bus_exec_context_set_transient_property(
|
||||||
if (af < 0)
|
if (af < 0)
|
||||||
return af;
|
return af;
|
||||||
|
|
||||||
if (whitelist == c->address_families_whitelist) {
|
if (allow_list == c->address_families_allow_list) {
|
||||||
r = set_put(c->address_families, INT_TO_PTR(af));
|
r = set_put(c->address_families, INT_TO_PTR(af));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -1850,7 +1918,7 @@ int bus_exec_context_set_transient_property(
|
||||||
if (!joined)
|
if (!joined)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
unit_write_settingf(u, flags, name, "RestrictAddressFamilies=%s%s", whitelist ? "" : "~", joined);
|
unit_write_settingf(u, flags, name, "RestrictAddressFamilies=%s%s", allow_list ? "" : "~", joined);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1380,14 +1380,14 @@ static void rename_process_from_path(const char *path) {
|
||||||
static bool context_has_address_families(const ExecContext *c) {
|
static bool context_has_address_families(const ExecContext *c) {
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
return c->address_families_whitelist ||
|
return c->address_families_allow_list ||
|
||||||
!set_isempty(c->address_families);
|
!set_isempty(c->address_families);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool context_has_syscall_filters(const ExecContext *c) {
|
static bool context_has_syscall_filters(const ExecContext *c) {
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
return c->syscall_whitelist ||
|
return c->syscall_allow_list ||
|
||||||
!hashmap_isempty(c->syscall_filter);
|
!hashmap_isempty(c->syscall_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1443,7 +1443,7 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
|
||||||
|
|
||||||
negative_action = c->syscall_errno == 0 ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
|
negative_action = c->syscall_errno == 0 ? scmp_act_kill_process() : SCMP_ACT_ERRNO(c->syscall_errno);
|
||||||
|
|
||||||
if (c->syscall_whitelist) {
|
if (c->syscall_allow_list) {
|
||||||
default_action = negative_action;
|
default_action = negative_action;
|
||||||
action = SCMP_ACT_ALLOW;
|
action = SCMP_ACT_ALLOW;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1452,7 +1452,7 @@ static int apply_syscall_filter(const Unit* u, const ExecContext *c, bool needs_
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needs_ambient_hack) {
|
if (needs_ambient_hack) {
|
||||||
r = seccomp_filter_set_add(c->syscall_filter, c->syscall_whitelist, syscall_filter_sets + SYSCALL_FILTER_SET_SETUID);
|
r = seccomp_filter_set_add(c->syscall_filter, c->syscall_allow_list, syscall_filter_sets + SYSCALL_FILTER_SET_SETUID);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1483,7 +1483,7 @@ static int apply_address_families(const Unit* u, const ExecContext *c) {
|
||||||
if (skip_seccomp_unavailable(u, "RestrictAddressFamilies="))
|
if (skip_seccomp_unavailable(u, "RestrictAddressFamilies="))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return seccomp_restrict_address_families(c->address_families, c->address_families_whitelist);
|
return seccomp_restrict_address_families(c->address_families, c->address_families_allow_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) {
|
static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) {
|
||||||
|
@ -2667,7 +2667,9 @@ static int apply_mount_namespace(
|
||||||
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
|
needs_sandboxing ? context->protect_home : PROTECT_HOME_NO,
|
||||||
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
|
needs_sandboxing ? context->protect_system : PROTECT_SYSTEM_NO,
|
||||||
context->mount_flags,
|
context->mount_flags,
|
||||||
context->root_hash, context->root_hash_size, context->root_hash_path, context->root_verity,
|
context->root_hash, context->root_hash_size, context->root_hash_path,
|
||||||
|
context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
|
||||||
|
context->root_verity,
|
||||||
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
||||||
error_path);
|
error_path);
|
||||||
|
|
||||||
|
@ -4200,6 +4202,9 @@ void exec_context_done(ExecContext *c) {
|
||||||
c->root_hash = mfree(c->root_hash);
|
c->root_hash = mfree(c->root_hash);
|
||||||
c->root_hash_size = 0;
|
c->root_hash_size = 0;
|
||||||
c->root_hash_path = mfree(c->root_hash_path);
|
c->root_hash_path = mfree(c->root_hash_path);
|
||||||
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
c->root_verity = mfree(c->root_verity);
|
c->root_verity = mfree(c->root_verity);
|
||||||
c->tty_path = mfree(c->tty_path);
|
c->tty_path = mfree(c->tty_path);
|
||||||
c->syslog_identifier = mfree(c->syslog_identifier);
|
c->syslog_identifier = mfree(c->syslog_identifier);
|
||||||
|
@ -4615,6 +4620,17 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
if (c->root_hash_path)
|
if (c->root_hash_path)
|
||||||
fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
|
fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
|
||||||
|
|
||||||
|
if (c->root_hash_sig) {
|
||||||
|
_cleanup_free_ char *encoded = NULL;
|
||||||
|
ssize_t len;
|
||||||
|
len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
|
||||||
|
if (len)
|
||||||
|
fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->root_hash_sig_path)
|
||||||
|
fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
|
||||||
|
|
||||||
if (c->root_verity)
|
if (c->root_verity)
|
||||||
fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
|
fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
|
||||||
|
|
||||||
|
@ -4918,7 +4934,7 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
||||||
"%sSystemCallFilter: ",
|
"%sSystemCallFilter: ",
|
||||||
prefix);
|
prefix);
|
||||||
|
|
||||||
if (!c->syscall_whitelist)
|
if (!c->syscall_allow_list)
|
||||||
fputc('~', f);
|
fputc('~', f);
|
||||||
|
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
|
|
|
@ -155,9 +155,9 @@ struct ExecContext {
|
||||||
char **unset_environment;
|
char **unset_environment;
|
||||||
|
|
||||||
struct rlimit *rlimit[_RLIMIT_MAX];
|
struct rlimit *rlimit[_RLIMIT_MAX];
|
||||||
char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path;
|
char *working_directory, *root_directory, *root_image, *root_verity, *root_hash_path, *root_hash_sig_path;
|
||||||
void *root_hash;
|
void *root_hash, *root_hash_sig;
|
||||||
size_t root_hash_size;
|
size_t root_hash_size, root_hash_sig_size;
|
||||||
bool working_directory_missing_ok:1;
|
bool working_directory_missing_ok:1;
|
||||||
bool working_directory_home:1;
|
bool working_directory_home:1;
|
||||||
|
|
||||||
|
@ -287,9 +287,9 @@ struct ExecContext {
|
||||||
Hashmap *syscall_filter;
|
Hashmap *syscall_filter;
|
||||||
Set *syscall_archs;
|
Set *syscall_archs;
|
||||||
int syscall_errno;
|
int syscall_errno;
|
||||||
bool syscall_whitelist:1;
|
bool syscall_allow_list:1;
|
||||||
|
|
||||||
bool address_families_whitelist:1;
|
bool address_families_allow_list:1;
|
||||||
Set *address_families;
|
Set *address_families;
|
||||||
|
|
||||||
char *network_namespace_path;
|
char *network_namespace_path;
|
||||||
|
|
|
@ -24,6 +24,7 @@ m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
|
||||||
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
|
$1.RootDirectory, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_directory)
|
||||||
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
|
$1.RootImage, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_image)
|
||||||
$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
|
$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
|
||||||
|
$1.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof($1, exec_context)
|
||||||
$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
|
$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
|
||||||
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
|
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
|
||||||
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
|
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
|
||||||
|
|
|
@ -1472,6 +1472,66 @@ int config_parse_exec_root_hash(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int config_parse_exec_root_hash_sig(
|
||||||
|
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) {
|
||||||
|
|
||||||
|
_cleanup_free_ void *roothash_sig_decoded = NULL;
|
||||||
|
char *value;
|
||||||
|
ExecContext *c = data;
|
||||||
|
size_t roothash_sig_decoded_size = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(data);
|
||||||
|
assert(filename);
|
||||||
|
assert(line);
|
||||||
|
assert(rvalue);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
/* Reset if the empty string is assigned */
|
||||||
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path_is_absolute(rvalue)) {
|
||||||
|
/* We have the path to a roothash signature to load and decode, eg: RootHashSignature=/foo/bar.roothash.p7s */
|
||||||
|
_cleanup_free_ char *p = NULL;
|
||||||
|
|
||||||
|
p = strdup(rvalue);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(c->root_hash_sig_path, p);
|
||||||
|
c->root_hash_sig = mfree(c->root_hash_sig);
|
||||||
|
c->root_hash_sig_size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(value = startswith(rvalue, "base64:")))
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature=, not a path but doesn't start with 'base64:', ignoring: %s", rvalue);
|
||||||
|
|
||||||
|
/* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
|
||||||
|
r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to decode RootHashSignature=, ignoring: %s", rvalue);
|
||||||
|
|
||||||
|
free_and_replace(c->root_hash_sig, roothash_sig_decoded);
|
||||||
|
c->root_hash_sig_size = roothash_sig_decoded_size;
|
||||||
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int config_parse_exec_cpu_affinity(const char *unit,
|
int config_parse_exec_cpu_affinity(const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
|
@ -3017,7 +3077,7 @@ int config_parse_syscall_filter(
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
/* Empty assignment resets the list */
|
/* Empty assignment resets the list */
|
||||||
c->syscall_filter = hashmap_free(c->syscall_filter);
|
c->syscall_filter = hashmap_free(c->syscall_filter);
|
||||||
c->syscall_whitelist = false;
|
c->syscall_allow_list = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3033,15 +3093,15 @@ int config_parse_syscall_filter(
|
||||||
|
|
||||||
if (invert)
|
if (invert)
|
||||||
/* Allow everything but the ones listed */
|
/* Allow everything but the ones listed */
|
||||||
c->syscall_whitelist = false;
|
c->syscall_allow_list = false;
|
||||||
else {
|
else {
|
||||||
/* Allow nothing but the ones listed */
|
/* Allow nothing but the ones listed */
|
||||||
c->syscall_whitelist = true;
|
c->syscall_allow_list = true;
|
||||||
|
|
||||||
/* Accept default syscalls if we are on a whitelist */
|
/* Accept default syscalls if we are on a allow_list */
|
||||||
r = seccomp_parse_syscall_filter(
|
r = seccomp_parse_syscall_filter(
|
||||||
"@default", -1, c->syscall_filter,
|
"@default", -1, c->syscall_filter,
|
||||||
SECCOMP_PARSE_PERMISSIVE|SECCOMP_PARSE_WHITELIST,
|
SECCOMP_PARSE_PERMISSIVE|SECCOMP_PARSE_ALLOW_LIST,
|
||||||
unit,
|
unit,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -3074,7 +3134,7 @@ int config_parse_syscall_filter(
|
||||||
name, num, c->syscall_filter,
|
name, num, c->syscall_filter,
|
||||||
SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
|
SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
|
||||||
(invert ? SECCOMP_PARSE_INVERT : 0)|
|
(invert ? SECCOMP_PARSE_INVERT : 0)|
|
||||||
(c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
|
(c->syscall_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0),
|
||||||
unit, filename, line);
|
unit, filename, line);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -3189,7 +3249,7 @@ int config_parse_address_families(
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
/* Empty assignment resets the list */
|
/* Empty assignment resets the list */
|
||||||
c->address_families = set_free(c->address_families);
|
c->address_families = set_free(c->address_families);
|
||||||
c->address_families_whitelist = false;
|
c->address_families_allow_list = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3203,7 +3263,7 @@ int config_parse_address_families(
|
||||||
if (!c->address_families)
|
if (!c->address_families)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
c->address_families_whitelist = !invert;
|
c->address_families_allow_list = !invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = rvalue;;) {
|
for (p = rvalue;;) {
|
||||||
|
@ -3231,7 +3291,7 @@ int config_parse_address_families(
|
||||||
/* If we previously wanted to forbid an address family and now
|
/* If we previously wanted to forbid an address family and now
|
||||||
* we want to allow it, then just remove it from the list.
|
* we want to allow it, then just remove it from the list.
|
||||||
*/
|
*/
|
||||||
if (!invert == c->address_families_whitelist) {
|
if (!invert == c->address_families_allow_list) {
|
||||||
r = set_put(c->address_families, INT_TO_PTR(af));
|
r = set_put(c->address_families, INT_TO_PTR(af));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
@ -3427,13 +3487,12 @@ int config_parse_memory_limit(
|
||||||
uint64_t bytes = CGROUP_LIMIT_MAX;
|
uint64_t bytes = CGROUP_LIMIT_MAX;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (STR_IN_SET(lvalue, "DefaultMemoryLow",
|
if (isempty(rvalue) && STR_IN_SET(lvalue, "DefaultMemoryLow",
|
||||||
"DefaultMemoryMin",
|
"DefaultMemoryMin",
|
||||||
"MemoryLow",
|
"MemoryLow",
|
||||||
"MemoryMin"))
|
"MemoryMin"))
|
||||||
bytes = CGROUP_LIMIT_MIN;
|
bytes = CGROUP_LIMIT_MIN;
|
||||||
|
else if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
|
||||||
if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
|
|
||||||
|
|
||||||
r = parse_permille(rvalue);
|
r = parse_permille(rvalue);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|
|
@ -45,6 +45,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_sched_prio);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_cpu_affinity);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_secure_bits);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_root_hash_sig);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
|
CONFIG_PARSER_PROTOTYPE(config_parse_capability_set);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
|
CONFIG_PARSER_PROTOTYPE(config_parse_exec_mount_flags);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
|
CONFIG_PARSER_PROTOTYPE(config_parse_timer);
|
||||||
|
|
|
@ -1067,7 +1067,7 @@ static int apply_mount(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_read_only(const MountEntry *m, char **blacklist, FILE *proc_self_mountinfo) {
|
static int make_read_only(const MountEntry *m, char **deny_list, FILE *proc_self_mountinfo) {
|
||||||
unsigned long new_flags = 0, flags_mask = 0;
|
unsigned long new_flags = 0, flags_mask = 0;
|
||||||
bool submounts = false;
|
bool submounts = false;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -1096,7 +1096,7 @@ static int make_read_only(const MountEntry *m, char **blacklist, FILE *proc_self
|
||||||
mount_entry_read_only(m) &&
|
mount_entry_read_only(m) &&
|
||||||
!IN_SET(m->mode, EMPTY_DIR, TMPFS);
|
!IN_SET(m->mode, EMPTY_DIR, TMPFS);
|
||||||
if (submounts)
|
if (submounts)
|
||||||
r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, blacklist, proc_self_mountinfo);
|
r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, deny_list, proc_self_mountinfo);
|
||||||
else
|
else
|
||||||
r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo);
|
r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo);
|
||||||
|
|
||||||
|
@ -1260,6 +1260,9 @@ int setup_namespace(
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *root_hash_path,
|
const char *root_hash_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
const char *root_verity,
|
const char *root_verity,
|
||||||
DissectImageFlags dissect_image_flags,
|
DissectImageFlags dissect_image_flags,
|
||||||
char **error_path) {
|
char **error_path) {
|
||||||
|
@ -1268,7 +1271,7 @@ int setup_namespace(
|
||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
_cleanup_free_ void *root_hash_decoded = NULL;
|
_cleanup_free_ void *root_hash_decoded = NULL;
|
||||||
_cleanup_free_ char *verity_data = NULL;
|
_cleanup_free_ char *verity_data = NULL, *hash_sig_path = NULL;
|
||||||
MountEntry *m = NULL, *mounts = NULL;
|
MountEntry *m = NULL, *mounts = NULL;
|
||||||
size_t n_mounts;
|
size_t n_mounts;
|
||||||
bool require_prefix = false;
|
bool require_prefix = false;
|
||||||
|
@ -1299,7 +1302,7 @@ int setup_namespace(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to create loop device for root image: %m");
|
return log_debug_errno(r, "Failed to create loop device for root image: %m");
|
||||||
|
|
||||||
r = verity_metadata_load(root_image, root_hash_path, root_hash ? NULL : &root_hash_decoded, root_hash ? NULL : &root_hash_size, root_verity ? NULL : &verity_data);
|
r = verity_metadata_load(root_image, root_hash_path, root_hash ? NULL : &root_hash_decoded, root_hash ? NULL : &root_hash_size, root_verity ? NULL : &verity_data, root_hash_sig || root_hash_sig_path ? NULL : &hash_sig_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to load root hash: %m");
|
return log_debug_errno(r, "Failed to load root hash: %m");
|
||||||
dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
dissect_image_flags |= root_verity || verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
|
@ -1308,7 +1311,7 @@ int setup_namespace(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to dissect image: %m");
|
return log_debug_errno(r, "Failed to dissect image: %m");
|
||||||
|
|
||||||
r = dissected_image_decrypt(dissected_image, NULL, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, dissect_image_flags, &decrypted_image);
|
r = dissected_image_decrypt(dissected_image, NULL, root_hash ?: root_hash_decoded, root_hash_size, root_verity ?: verity_data, root_hash_sig_path ?: hash_sig_path, root_hash_sig, root_hash_sig_size, dissect_image_flags, &decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
|
return log_debug_errno(r, "Failed to decrypt dissected image: %m");
|
||||||
}
|
}
|
||||||
|
@ -1538,7 +1541,7 @@ int setup_namespace(
|
||||||
|
|
||||||
if (n_mounts > 0) {
|
if (n_mounts > 0) {
|
||||||
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
||||||
_cleanup_free_ char **blacklist = NULL;
|
_cleanup_free_ char **deny_list = NULL;
|
||||||
size_t j;
|
size_t j;
|
||||||
|
|
||||||
/* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
|
/* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
|
||||||
|
@ -1591,19 +1594,19 @@ int setup_namespace(
|
||||||
normalize_mounts(root, mounts, &n_mounts);
|
normalize_mounts(root, mounts, &n_mounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a blacklist we can pass to bind_mount_recursive() */
|
/* Create a deny list we can pass to bind_mount_recursive() */
|
||||||
blacklist = new(char*, n_mounts+1);
|
deny_list = new(char*, n_mounts+1);
|
||||||
if (!blacklist) {
|
if (!deny_list) {
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
for (j = 0; j < n_mounts; j++)
|
for (j = 0; j < n_mounts; j++)
|
||||||
blacklist[j] = (char*) mount_entry_path(mounts+j);
|
deny_list[j] = (char*) mount_entry_path(mounts+j);
|
||||||
blacklist[j] = NULL;
|
deny_list[j] = NULL;
|
||||||
|
|
||||||
/* Second round, flip the ro bits if necessary. */
|
/* Second round, flip the ro bits if necessary. */
|
||||||
for (m = mounts; m < mounts + n_mounts; ++m) {
|
for (m = mounts; m < mounts + n_mounts; ++m) {
|
||||||
r = make_read_only(m, blacklist, proc_self_mountinfo);
|
r = make_read_only(m, deny_list, proc_self_mountinfo);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (error_path && mount_entry_path(m))
|
if (error_path && mount_entry_path(m))
|
||||||
*error_path = strdup(mount_entry_path(m));
|
*error_path = strdup(mount_entry_path(m));
|
||||||
|
|
|
@ -91,6 +91,9 @@ int setup_namespace(
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *root_hash_path,
|
const char *root_hash_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
const char *root_verity,
|
const char *root_verity,
|
||||||
DissectImageFlags dissected_image_flags,
|
DissectImageFlags dissected_image_flags,
|
||||||
char **error_path);
|
char **error_path);
|
||||||
|
|
|
@ -39,7 +39,7 @@ static bool arg_enabled = true;
|
||||||
static bool arg_read_crypttab = true;
|
static bool arg_read_crypttab = true;
|
||||||
static const char *arg_crypttab = NULL;
|
static const char *arg_crypttab = NULL;
|
||||||
static const char *arg_runtime_directory = NULL;
|
static const char *arg_runtime_directory = NULL;
|
||||||
static bool arg_whitelist = false;
|
static bool arg_allow_list = false;
|
||||||
static Hashmap *arg_disks = NULL;
|
static Hashmap *arg_disks = NULL;
|
||||||
static char *arg_default_options = NULL;
|
static char *arg_default_options = NULL;
|
||||||
static char *arg_default_keyfile = NULL;
|
static char *arg_default_keyfile = NULL;
|
||||||
|
@ -495,7 +495,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||||
if (!d)
|
if (!d)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
d->create = arg_whitelist = true;
|
d->create = arg_allow_list = true;
|
||||||
|
|
||||||
} else if (streq(key, "luks.options")) {
|
} else if (streq(key, "luks.options")) {
|
||||||
|
|
||||||
|
@ -559,7 +559,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||||
if (!d)
|
if (!d)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
d->create = arg_whitelist = true;
|
d->create = arg_allow_list = true;
|
||||||
|
|
||||||
free_and_replace(d->name, uuid_value);
|
free_and_replace(d->name, uuid_value);
|
||||||
} else
|
} else
|
||||||
|
@ -622,7 +622,7 @@ static int add_crypttab_devices(void) {
|
||||||
if (uuid)
|
if (uuid)
|
||||||
d = hashmap_get(arg_disks, uuid);
|
d = hashmap_get(arg_disks, uuid);
|
||||||
|
|
||||||
if (arg_whitelist && !d) {
|
if (arg_allow_list && !d) {
|
||||||
log_info("Not creating device '%s' because it was not specified on the kernel command line.", name);
|
log_info("Not creating device '%s' because it was not specified on the kernel command line.", name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,14 @@ static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DI
|
||||||
static void *arg_root_hash = NULL;
|
static void *arg_root_hash = NULL;
|
||||||
static char *arg_verity_data = NULL;
|
static char *arg_verity_data = NULL;
|
||||||
static size_t arg_root_hash_size = 0;
|
static size_t arg_root_hash_size = 0;
|
||||||
|
static char *arg_root_hash_sig_path = NULL;
|
||||||
|
static void *arg_root_hash_sig = NULL;
|
||||||
|
static size_t arg_root_hash_sig_size = 0;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep);
|
||||||
|
|
||||||
static void help(void) {
|
static void help(void) {
|
||||||
printf("%s [OPTIONS...] IMAGE\n"
|
printf("%s [OPTIONS...] IMAGE\n"
|
||||||
|
@ -43,6 +48,10 @@ static void help(void) {
|
||||||
" --fsck=BOOL Run fsck before mounting\n"
|
" --fsck=BOOL Run fsck before mounting\n"
|
||||||
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
|
" --discard=MODE Choose 'discard' mode (disabled, loop, all, crypto)\n"
|
||||||
" --root-hash=HASH Specify root hash for verity\n"
|
" --root-hash=HASH Specify root hash for verity\n"
|
||||||
|
" --root-hash-sig=SIG Specify pkcs7 signature of root hash for verity\n"
|
||||||
|
" as a DER encoded PKCS7, either as a path to a file\n"
|
||||||
|
" or as an ASCII base64 encoded string prefixed by\n"
|
||||||
|
" 'base64:'\n"
|
||||||
" --verity-data=PATH Specify data file with hash tree for verity if it is\n"
|
" --verity-data=PATH Specify data file with hash tree for verity if it is\n"
|
||||||
" not embedded in IMAGE\n",
|
" not embedded in IMAGE\n",
|
||||||
program_invocation_short_name,
|
program_invocation_short_name,
|
||||||
|
@ -57,6 +66,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_ROOT_HASH,
|
ARG_ROOT_HASH,
|
||||||
ARG_FSCK,
|
ARG_FSCK,
|
||||||
ARG_VERITY_DATA,
|
ARG_VERITY_DATA,
|
||||||
|
ARG_ROOT_HASH_SIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -68,6 +78,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
{ "root-hash", required_argument, NULL, ARG_ROOT_HASH },
|
||||||
{ "fsck", required_argument, NULL, ARG_FSCK },
|
{ "fsck", required_argument, NULL, ARG_FSCK },
|
||||||
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
||||||
|
{ "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -140,6 +151,31 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_ROOT_HASH_SIG: {
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
if ((value = startswith(optarg, "base64:"))) {
|
||||||
|
void *p;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
r = unbase64mem(value, strlen(value), &p, &l);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
||||||
|
|
||||||
|
free_and_replace(arg_root_hash_sig, p);
|
||||||
|
arg_root_hash_sig_size = l;
|
||||||
|
arg_root_hash_sig_path = mfree(arg_root_hash_sig_path);
|
||||||
|
} else {
|
||||||
|
r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
arg_root_hash_sig = mfree(arg_root_hash_sig);
|
||||||
|
arg_root_hash_sig_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ARG_FSCK:
|
case ARG_FSCK:
|
||||||
r = parse_boolean(optarg);
|
r = parse_boolean(optarg);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -202,7 +238,8 @@ static int run(int argc, char *argv[]) {
|
||||||
return log_error_errno(r, "Failed to set up loopback device: %m");
|
return log_error_errno(r, "Failed to set up loopback device: %m");
|
||||||
|
|
||||||
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
||||||
arg_verity_data ? NULL : &arg_verity_data);
|
arg_verity_data ? NULL : &arg_verity_data,
|
||||||
|
arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
return log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
arg_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
arg_flags |= arg_verity_data ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0;
|
||||||
|
@ -279,7 +316,7 @@ static int run(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case ACTION_MOUNT:
|
case ACTION_MOUNT:
|
||||||
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_flags, &di);
|
r = dissected_image_decrypt_interactively(m, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, arg_flags, &di);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -1,106 +1,36 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <stdio.h>
|
||||||
#include <sched.h>
|
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "fuzz.h"
|
#include "fuzz.h"
|
||||||
#include "log.h"
|
|
||||||
#include "mkdir.h"
|
|
||||||
#include "rm-rf.h"
|
|
||||||
#include "string-util.h"
|
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
#include "tmpfile-util.h"
|
||||||
#include "udev-rules.h"
|
#include "udev-rules.h"
|
||||||
|
|
||||||
static struct fakefs {
|
|
||||||
const char *target;
|
|
||||||
bool ignore_mount_error;
|
|
||||||
bool is_mounted;
|
|
||||||
} fakefss[] = {
|
|
||||||
{ "/sys", false, false },
|
|
||||||
{ "/dev", false, false },
|
|
||||||
{ "/run", false, false },
|
|
||||||
{ "/etc", false, false },
|
|
||||||
{ UDEVLIBEXECDIR "/rules.d", true, false },
|
|
||||||
};
|
|
||||||
|
|
||||||
static int setup_mount_namespace(void) {
|
|
||||||
static thread_local bool is_namespaced = false;
|
|
||||||
|
|
||||||
if (is_namespaced)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (unshare(CLONE_NEWNS) < 0)
|
|
||||||
return log_error_errno(errno, "Failed to call unshare(): %m");
|
|
||||||
|
|
||||||
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
|
|
||||||
return log_error_errno(errno, "Failed to mount / as private: %m");
|
|
||||||
|
|
||||||
is_namespaced = true;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int setup_fake_filesystems(const char *runtime_dir) {
|
|
||||||
for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) {
|
|
||||||
if (mount(runtime_dir, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
|
|
||||||
log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to mount %s: %m", fakefss[i].target);
|
|
||||||
if (!fakefss[i].ignore_mount_error)
|
|
||||||
return -errno;
|
|
||||||
} else
|
|
||||||
fakefss[i].is_mounted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cleanup_fake_filesystems(const char *runtime_dir) {
|
|
||||||
for (unsigned i = 0; i < ELEMENTSOF(fakefss); i++) {
|
|
||||||
if (!fakefss[i].is_mounted)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (umount(fakefss[i].target) < 0) {
|
|
||||||
log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "Failed to umount %s: %m", fakefss[i].target);
|
|
||||||
if (!fakefss[i].ignore_mount_error)
|
|
||||||
return -errno;
|
|
||||||
} else
|
|
||||||
fakefss[i].is_mounted = false;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
_cleanup_(udev_rules_freep) UdevRules *rules = NULL;
|
_cleanup_(udev_rules_freep) UdevRules *rules = NULL;
|
||||||
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
FILE *f = NULL;
|
_cleanup_(unlink_tempfilep) char filename[] = "/tmp/fuzz-udev-rules.XXXXXX";
|
||||||
|
int r;
|
||||||
(void) setup_mount_namespace();
|
|
||||||
|
|
||||||
assert_se(runtime_dir = setup_fake_runtime_dir());
|
|
||||||
|
|
||||||
if (setup_fake_filesystems(runtime_dir) < 0) {
|
|
||||||
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
|
||||||
return EXIT_TEST_SKIP;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!getenv("SYSTEMD_LOG_LEVEL")) {
|
if (!getenv("SYSTEMD_LOG_LEVEL")) {
|
||||||
log_set_max_level_realm(LOG_REALM_UDEV, LOG_CRIT);
|
log_set_max_level_realm(LOG_REALM_UDEV, LOG_CRIT);
|
||||||
log_set_max_level_realm(LOG_REALM_SYSTEMD, LOG_CRIT);
|
log_set_max_level_realm(LOG_REALM_SYSTEMD, LOG_CRIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_se(mkdir_p("/etc/udev/rules.d", 0755) >= 0);
|
assert_se(fmkostemp_safe(filename, "r+", &f) == 0);
|
||||||
f = fopen("/etc/udev/rules.d/fuzz.rules", "we");
|
|
||||||
assert_se(f);
|
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
assert_se(fwrite(data, size, 1, f) == 1);
|
assert_se(fwrite(data, size, 1, f) == 1);
|
||||||
assert_se(fclose(f) == 0);
|
fflush(f);
|
||||||
|
|
||||||
assert_se(udev_rules_new(&rules, RESOLVE_NAME_EARLY) == 0);
|
assert_se(rules = udev_rules_new(RESOLVE_NAME_EARLY));
|
||||||
|
r = udev_rules_parse_file(rules, filename);
|
||||||
|
log_info_errno(r, "Parsing %s: %m", filename);
|
||||||
|
assert_se(IN_SET(r,
|
||||||
|
0, /* OK */
|
||||||
|
-ENOBUFS /* line length exceeded */));
|
||||||
|
|
||||||
assert_se(cleanup_fake_filesystems(runtime_dir) >= 0);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,8 +154,8 @@ size_t util_replace_whitespace(const char *str, char *to, size_t len) {
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
|
/* allow chars in allow list, plain ascii, hex-escaping and valid utf8 */
|
||||||
size_t util_replace_chars(char *str, const char *white) {
|
size_t util_replace_chars(char *str, const char *allow) {
|
||||||
size_t i = 0, replaced = 0;
|
size_t i = 0, replaced = 0;
|
||||||
|
|
||||||
assert(str);
|
assert(str);
|
||||||
|
@ -163,7 +163,7 @@ size_t util_replace_chars(char *str, const char *white) {
|
||||||
while (str[i] != '\0') {
|
while (str[i] != '\0') {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
if (whitelisted_char_for_devnode(str[i], white)) {
|
if (allow_listed_char_for_devnode(str[i], allow)) {
|
||||||
i++;
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,7 @@ size_t util_replace_chars(char *str, const char *white) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if space is allowed, replace whitespace with ordinary space */
|
/* if space is allowed, replace whitespace with ordinary space */
|
||||||
if (isspace(str[i]) && white && strchr(white, ' ')) {
|
if (isspace(str[i]) && allow && strchr(allow, ' ')) {
|
||||||
str[i] = ' ';
|
str[i] = ' ';
|
||||||
i++;
|
i++;
|
||||||
replaced++;
|
replaced++;
|
||||||
|
|
|
@ -601,10 +601,10 @@ static int manager_count_external_displays(Manager *m) {
|
||||||
if (sd_device_get_sysname(d, &nn) < 0)
|
if (sd_device_get_sysname(d, &nn) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore internal displays: the type is encoded in the sysfs name, as the second dash separated item
|
/* Ignore internal displays: the type is encoded in the sysfs name, as the second dash
|
||||||
* (the first is the card name, the last the connector number). We implement a blacklist of external
|
* separated item (the first is the card name, the last the connector number). We implement a
|
||||||
* displays here, rather than a whitelist of internal ones, to ensure we don't block suspends too
|
* deny list of external displays here, rather than an allow list of internal ones, to ensure
|
||||||
* eagerly. */
|
* we don't block suspends too eagerly. */
|
||||||
dash = strchr(nn, '-');
|
dash = strchr(nn, '-');
|
||||||
if (!dash)
|
if (!dash)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -364,7 +364,7 @@ static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handl
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
callback(netdev->manager->rtnl, m, link);
|
callback(netdev->manager->rtnl, m, link);
|
||||||
} else {
|
} else {
|
||||||
/* the netdev is not yet read, save this request for when it is */
|
/* the netdev is not yet ready, save this request for when it is */
|
||||||
netdev_join_callback *cb;
|
netdev_join_callback *cb;
|
||||||
|
|
||||||
cb = new(netdev_join_callback, 1);
|
cb = new(netdev_join_callback, 1);
|
||||||
|
|
|
@ -1051,7 +1051,7 @@ static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp_server_is_black_listed(Link *link, sd_dhcp_client *client) {
|
static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) {
|
||||||
sd_dhcp_lease *lease;
|
sd_dhcp_lease *lease;
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
int r;
|
int r;
|
||||||
|
@ -1068,10 +1068,10 @@ static int dhcp_server_is_black_listed(Link *link, sd_dhcp_client *client) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_debug_errno(link, r, "Failed to get DHCP server ip address: %m");
|
return log_link_debug_errno(link, r, "Failed to get DHCP server ip address: %m");
|
||||||
|
|
||||||
if (set_contains(link->network->dhcp_black_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
|
if (set_contains(link->network->dhcp_deny_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
|
||||||
log_struct(LOG_DEBUG,
|
log_struct(LOG_DEBUG,
|
||||||
LOG_LINK_INTERFACE(link),
|
LOG_LINK_INTERFACE(link),
|
||||||
LOG_LINK_MESSAGE(link, "DHCPv4 ip '%u.%u.%u.%u' found in black listed ip addresses, ignoring offer",
|
LOG_LINK_MESSAGE(link, "DHCPv4 ip '%u.%u.%u.%u' found in deny-listed ip addresses, ignoring offer",
|
||||||
ADDRESS_FMT_VAL(addr)));
|
ADDRESS_FMT_VAL(addr)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1163,7 +1163,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SD_DHCP_CLIENT_EVENT_SELECTING:
|
case SD_DHCP_CLIENT_EVENT_SELECTING:
|
||||||
r = dhcp_server_is_black_listed(link, client);
|
r = dhcp_server_is_deny_listed(link, client);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
|
@ -1551,7 +1551,7 @@ int config_parse_dhcp_max_attempts(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_dhcp_black_listed_ip_address(
|
int config_parse_dhcp_deny_listed_ip_address(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
|
@ -1572,7 +1572,7 @@ int config_parse_dhcp_black_listed_ip_address(
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
network->dhcp_black_listed_ip = set_free(network->dhcp_black_listed_ip);
|
network->dhcp_deny_listed_ip = set_free(network->dhcp_deny_listed_ip);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1583,7 +1583,7 @@ int config_parse_dhcp_black_listed_ip_address(
|
||||||
r = extract_first_word(&p, &n, NULL, 0);
|
r = extract_first_word(&p, &n, NULL, 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"Failed to parse DHCP black listed ip address, ignoring assignment: %s",
|
"Failed to parse DHCP deny-listed IP address, ignoring assignment: %s",
|
||||||
rvalue);
|
rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1593,14 +1593,14 @@ int config_parse_dhcp_black_listed_ip_address(
|
||||||
r = in_addr_from_string(AF_INET, n, &ip);
|
r = in_addr_from_string(AF_INET, n, &ip);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"DHCP black listed ip address is invalid, ignoring assignment: %s", n);
|
"DHCP deny-listed IP address is invalid, ignoring assignment: %s", n);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = set_ensure_put(&network->dhcp_black_listed_ip, NULL, UINT32_TO_PTR(ip.in.s_addr));
|
r = set_ensure_put(&network->dhcp_deny_listed_ip, NULL, UINT32_TO_PTR(ip.in.s_addr));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"Failed to store DHCP black listed ip address '%s', ignoring assignment: %m", n);
|
"Failed to store DHCP deny-listed IP address '%s', ignoring assignment: %m", n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -23,7 +23,7 @@ int dhcp4_set_client_identifier(Link *link);
|
||||||
int dhcp4_set_promote_secondaries(Link *link);
|
int dhcp4_set_promote_secondaries(Link *link);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_black_listed_ip_address);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_deny_listed_ip_address);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_ip_service_type);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
|
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_mud_url);
|
||||||
|
|
|
@ -346,6 +346,9 @@ static void link_update_master_operstate(Link *link, NetDev *netdev) {
|
||||||
if (!netdev)
|
if (!netdev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (netdev->ifindex <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (link_get(link->manager, netdev->ifindex, &master) < 0)
|
if (link_get(link->manager, netdev->ifindex, &master) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -752,7 +755,7 @@ int link_get(Manager *m, int ifindex, Link **ret) {
|
||||||
Link *link;
|
Link *link;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(ifindex);
|
assert(ifindex > 0);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
link = hashmap_get(m->links, INT_TO_PTR(ifindex));
|
link = hashmap_get(m->links, INT_TO_PTR(ifindex));
|
||||||
|
|
|
@ -1272,6 +1272,9 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
|
||||||
if (r < 0 && r != -ENODATA) {
|
if (r < 0 && r != -ENODATA) {
|
||||||
log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
|
log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (tmp->oif <= 0) {
|
||||||
|
log_warning("rtnl: received nexthop message with invalid ifindex %d, ignoring.", tmp->oif);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = link_get(m, tmp->oif, &link);
|
r = link_get(m, tmp->oif, &link);
|
||||||
|
|
|
@ -723,12 +723,12 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||||
|
|
||||||
if (set_contains(link->network->ndisc_black_listed_prefix, &a.in6)) {
|
if (set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) {
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING) {
|
||||||
_cleanup_free_ char *b = NULL;
|
_cleanup_free_ char *b = NULL;
|
||||||
|
|
||||||
(void) in_addr_to_string(AF_INET6, &a, &b);
|
(void) in_addr_to_string(AF_INET6, &a, &b);
|
||||||
log_link_debug(link, "Prefix '%s' is black listed, ignoring", strna(b));
|
log_link_debug(link, "Prefix '%s' is deny-listed, ignoring", strna(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -915,7 +915,7 @@ DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||||
IPv6Token,
|
IPv6Token,
|
||||||
free);
|
free);
|
||||||
|
|
||||||
int config_parse_ndisc_black_listed_prefix(
|
int config_parse_ndisc_deny_listed_prefix(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
|
@ -937,7 +937,7 @@ int config_parse_ndisc_black_listed_prefix(
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
network->ndisc_black_listed_prefix = set_free_free(network->ndisc_black_listed_prefix);
|
network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -949,7 +949,7 @@ int config_parse_ndisc_black_listed_prefix(
|
||||||
r = extract_first_word(&p, &n, NULL, 0);
|
r = extract_first_word(&p, &n, NULL, 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"Failed to parse NDISC black listed prefix, ignoring assignment: %s",
|
"Failed to parse NDISC deny-listed prefix, ignoring assignment: %s",
|
||||||
rvalue);
|
rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -959,18 +959,18 @@ int config_parse_ndisc_black_listed_prefix(
|
||||||
r = in_addr_from_string(AF_INET6, n, &ip);
|
r = in_addr_from_string(AF_INET6, n, &ip);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||||
"NDISC black listed prefix is invalid, ignoring assignment: %s", n);
|
"NDISC deny-listed prefix is invalid, ignoring assignment: %s", n);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_contains(network->ndisc_black_listed_prefix, &ip.in6))
|
if (set_contains(network->ndisc_deny_listed_prefix, &ip.in6))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
a = newdup(struct in6_addr, &ip.in6, 1);
|
a = newdup(struct in6_addr, &ip.in6, 1);
|
||||||
if (!a)
|
if (!a)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
r = set_ensure_consume(&network->ndisc_black_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a));
|
r = set_ensure_consume(&network->ndisc_deny_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ int ndisc_configure(Link *link);
|
||||||
void ndisc_vacuum(Link *link);
|
void ndisc_vacuum(Link *link);
|
||||||
void ndisc_flush(Link *link);
|
void ndisc_flush(Link *link);
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_black_listed_prefix);
|
CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_deny_listed_prefix);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
|
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client);
|
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client);
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,8 @@ DHCPv4.IAID, config_parse_iaid,
|
||||||
DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
|
DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port)
|
||||||
DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release)
|
DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release)
|
||||||
DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline)
|
DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline)
|
||||||
DHCPv4.BlackList, config_parse_dhcp_black_listed_ip_address, 0, 0
|
DHCPv4.DenyList, config_parse_dhcp_deny_listed_ip_address, 0, 0
|
||||||
|
DHCPv4.BlackList, config_parse_dhcp_deny_listed_ip_address, 0, 0
|
||||||
DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type, 0, offsetof(Network, ip_service_type)
|
DHCPv4.IPServiceType, config_parse_dhcp_ip_service_type, 0, offsetof(Network, ip_service_type)
|
||||||
DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
|
DHCPv4.SendOption, config_parse_dhcp_send_option, AF_INET, offsetof(Network, dhcp_client_send_options)
|
||||||
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
|
DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options)
|
||||||
|
@ -214,7 +215,8 @@ IPv6AcceptRA.UseDNS, config_parse_bool,
|
||||||
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
||||||
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
|
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
|
||||||
IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0
|
IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0
|
||||||
IPv6AcceptRA.BlackList, config_parse_ndisc_black_listed_prefix, 0, 0
|
IPv6AcceptRA.DenyList, config_parse_ndisc_deny_listed_prefix, 0, 0
|
||||||
|
IPv6AcceptRA.BlackList, config_parse_ndisc_deny_listed_prefix, 0, 0
|
||||||
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
|
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
|
||||||
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
|
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
|
||||||
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit[SD_DHCP_LEASE_DNS].emit)
|
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit[SD_DHCP_LEASE_DNS].emit)
|
||||||
|
|
|
@ -662,7 +662,7 @@ static Network *network_free(Network *network) {
|
||||||
free(network->dhcp_mudurl);
|
free(network->dhcp_mudurl);
|
||||||
strv_free(network->dhcp_user_class);
|
strv_free(network->dhcp_user_class);
|
||||||
free(network->dhcp_hostname);
|
free(network->dhcp_hostname);
|
||||||
set_free(network->dhcp_black_listed_ip);
|
set_free(network->dhcp_deny_listed_ip);
|
||||||
set_free(network->dhcp_request_options);
|
set_free(network->dhcp_request_options);
|
||||||
set_free(network->dhcp6_request_options);
|
set_free(network->dhcp6_request_options);
|
||||||
free(network->mac);
|
free(network->mac);
|
||||||
|
@ -681,7 +681,7 @@ static Network *network_free(Network *network) {
|
||||||
|
|
||||||
ordered_set_free_free(network->router_search_domains);
|
ordered_set_free_free(network->router_search_domains);
|
||||||
free(network->router_dns);
|
free(network->router_dns);
|
||||||
set_free_free(network->ndisc_black_listed_prefix);
|
set_free_free(network->ndisc_deny_listed_prefix);
|
||||||
|
|
||||||
free(network->bridge_name);
|
free(network->bridge_name);
|
||||||
free(network->bond_name);
|
free(network->bond_name);
|
||||||
|
|
|
@ -129,7 +129,7 @@ struct Network {
|
||||||
bool dhcp_send_decline;
|
bool dhcp_send_decline;
|
||||||
DHCPUseDomains dhcp_use_domains;
|
DHCPUseDomains dhcp_use_domains;
|
||||||
sd_ipv4acd *dhcp_acd;
|
sd_ipv4acd *dhcp_acd;
|
||||||
Set *dhcp_black_listed_ip;
|
Set *dhcp_deny_listed_ip;
|
||||||
Set *dhcp_request_options;
|
Set *dhcp_request_options;
|
||||||
OrderedHashmap *dhcp_client_send_options;
|
OrderedHashmap *dhcp_client_send_options;
|
||||||
OrderedHashmap *dhcp_client_send_vendor_options;
|
OrderedHashmap *dhcp_client_send_vendor_options;
|
||||||
|
@ -241,7 +241,7 @@ struct Network {
|
||||||
DHCPUseDomains ipv6_accept_ra_use_domains;
|
DHCPUseDomains ipv6_accept_ra_use_domains;
|
||||||
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client;
|
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client;
|
||||||
uint32_t ipv6_accept_ra_route_table;
|
uint32_t ipv6_accept_ra_route_table;
|
||||||
Set *ndisc_black_listed_prefix;
|
Set *ndisc_deny_listed_prefix;
|
||||||
OrderedHashmap *ipv6_tokens;
|
OrderedHashmap *ipv6_tokens;
|
||||||
|
|
||||||
IPv6PrivacyExtensions ipv6_privacy_extensions;
|
IPv6PrivacyExtensions ipv6_privacy_extensions;
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
* spec should say what to do with unknown props
|
* spec should say what to do with unknown props
|
||||||
* /bin/mount regarding NFS and FUSE required?
|
* /bin/mount regarding NFS and FUSE required?
|
||||||
* what does terminal=false mean?
|
* what does terminal=false mean?
|
||||||
* sysctl inside or outside? whitelisting?
|
* sysctl inside or outside? allow-listing?
|
||||||
* swapiness typo -> swappiness
|
* swapiness typo -> swappiness
|
||||||
*
|
*
|
||||||
* Unsupported:
|
* Unsupported:
|
||||||
|
@ -1029,39 +1029,40 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!data.allow) {
|
if (!data.allow) {
|
||||||
/* The fact that OCI allows 'deny' entries makes really no sense, as 'allow' vs. 'deny' for the
|
/* The fact that OCI allows 'deny' entries makes really no sense, as 'allow'
|
||||||
* devices cgroup controller is really not about whitelisting and blacklisting but about adding
|
* vs. 'deny' for the devices cgroup controller is really not about allow-listing and
|
||||||
* and removing entries from the whitelist. Since we always start out with an empty whitelist
|
* deny-listing but about adding and removing entries from the allow list. Since we
|
||||||
* we hence ignore the whole thing, as removing entries which don't exist make no sense. We'll
|
* always start out with an empty allow list we hence ignore the whole thing, as
|
||||||
* log about this, since this is really borked in the spec, with one exception: the entry
|
* removing entries which don't exist make no sense. We'll log about this, since this
|
||||||
* that's supposed to drop the kernel's default we ignore silently */
|
* is really borked in the spec, with one exception: the entry that's supposed to
|
||||||
|
* drop the kernel's default we ignore silently */
|
||||||
|
|
||||||
if (!data.r || !data.w || !data.m || data.type != 0 || data.major != (unsigned) -1 || data.minor != (unsigned) -1)
|
if (!data.r || !data.w || !data.m || data.type != 0 || data.major != (unsigned) -1 || data.minor != (unsigned) -1)
|
||||||
json_log(v, flags|JSON_WARNING, 0, "Devices cgroup whitelist with arbitrary 'allow' entries not supported, ignoring.");
|
json_log(v, flags|JSON_WARNING, 0, "Devices cgroup allow list with arbitrary 'allow' entries not supported, ignoring.");
|
||||||
|
|
||||||
/* We ignore the 'deny' entry as for us that's implied */
|
/* We ignore the 'deny' entry as for us that's implied */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.r && !data.w && !data.m) {
|
if (!data.r && !data.w && !data.m) {
|
||||||
json_log(v, flags|LOG_WARNING, 0, "Device cgroup whitelist entry with no effect found, ignoring.");
|
json_log(v, flags|LOG_WARNING, 0, "Device cgroup allow list entry with no effect found, ignoring.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.minor != (unsigned) -1 && data.major == (unsigned) -1)
|
if (data.minor != (unsigned) -1 && data.major == (unsigned) -1)
|
||||||
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"Device cgroup whitelist entries with minors but no majors not supported.");
|
"Device cgroup allow list entries with minors but no majors not supported.");
|
||||||
|
|
||||||
if (data.major != (unsigned) -1 && data.type == 0)
|
if (data.major != (unsigned) -1 && data.type == 0)
|
||||||
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"Device cgroup whitelist entries with majors but no device node type not supported.");
|
"Device cgroup allow list entries with majors but no device node type not supported.");
|
||||||
|
|
||||||
if (data.type == 0) {
|
if (data.type == 0) {
|
||||||
if (data.r && data.w && data.m) /* a catchall whitelist entry means we are looking at a noop */
|
if (data.r && data.w && data.m) /* a catchall allow list entry means we are looking at a noop */
|
||||||
noop = true;
|
noop = true;
|
||||||
else
|
else
|
||||||
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"Device cgroup whitelist entries with no type not supported.");
|
"Device cgroup allow list entries with no type not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
a = reallocarray(list, n_list + 1, sizeof(struct device_data));
|
a = reallocarray(list, n_list + 1, sizeof(struct device_data));
|
||||||
|
|
|
@ -25,13 +25,13 @@ static int seccomp_add_default_syscall_filter(
|
||||||
scmp_filter_ctx ctx,
|
scmp_filter_ctx ctx,
|
||||||
uint32_t arch,
|
uint32_t arch,
|
||||||
uint64_t cap_list_retain,
|
uint64_t cap_list_retain,
|
||||||
char **syscall_whitelist,
|
char **syscall_allow_list,
|
||||||
char **syscall_blacklist) {
|
char **syscall_deny_list) {
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
uint64_t capability;
|
uint64_t capability;
|
||||||
const char* name;
|
const char* name;
|
||||||
} whitelist[] = {
|
} allow_list[] = {
|
||||||
/* Let's use set names where we can */
|
/* Let's use set names where we can */
|
||||||
{ 0, "@aio" },
|
{ 0, "@aio" },
|
||||||
{ 0, "@basic-io" },
|
{ 0, "@basic-io" },
|
||||||
|
@ -142,17 +142,17 @@ static int seccomp_add_default_syscall_filter(
|
||||||
char **p;
|
char **p;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
for (size_t i = 0; i < ELEMENTSOF(whitelist); i++) {
|
for (size_t i = 0; i < ELEMENTSOF(allow_list); i++) {
|
||||||
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
|
if (allow_list[i].capability != 0 && (cap_list_retain & (1ULL << allow_list[i].capability)) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = seccomp_add_syscall_filter_item(ctx, whitelist[i].name, SCMP_ACT_ALLOW, syscall_blacklist, false);
|
r = seccomp_add_syscall_filter_item(ctx, allow_list[i].name, SCMP_ACT_ALLOW, syscall_deny_list, false);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to add syscall filter item %s: %m", whitelist[i].name);
|
return log_error_errno(r, "Failed to add syscall filter item %s: %m", allow_list[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
STRV_FOREACH(p, syscall_whitelist) {
|
STRV_FOREACH(p, syscall_allow_list) {
|
||||||
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, true);
|
r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_deny_list, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
|
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
|
||||||
*p, seccomp_arch_to_string(arch));
|
*p, seccomp_arch_to_string(arch));
|
||||||
|
@ -161,7 +161,7 @@ static int seccomp_add_default_syscall_filter(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
|
int setup_seccomp(uint64_t cap_list_retain, char **syscall_allow_list, char **syscall_deny_list) {
|
||||||
uint32_t arch;
|
uint32_t arch;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -173,13 +173,13 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **sys
|
||||||
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
|
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
|
||||||
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
|
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
|
||||||
|
|
||||||
log_debug("Applying whitelist on architecture: %s", seccomp_arch_to_string(arch));
|
log_debug("Applying allow list on architecture: %s", seccomp_arch_to_string(arch));
|
||||||
|
|
||||||
r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ERRNO(EPERM));
|
r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ERRNO(EPERM));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to allocate seccomp object: %m");
|
return log_error_errno(r, "Failed to allocate seccomp object: %m");
|
||||||
|
|
||||||
r = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain, syscall_whitelist, syscall_blacklist);
|
r = seccomp_add_default_syscall_filter(seccomp, arch, cap_list_retain, syscall_allow_list, syscall_deny_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **sys
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist) {
|
int setup_seccomp(uint64_t cap_list_retain, char **syscall_allow_list, char **syscall_deny_list) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
int setup_seccomp(uint64_t cap_list_retain, char **syscall_whitelist, char **syscall_blacklist);
|
int setup_seccomp(uint64_t cap_list_retain, char **syscall_allow_ist, char **syscall_deny_list);
|
||||||
|
|
|
@ -129,8 +129,8 @@ Settings* settings_free(Settings *s) {
|
||||||
free(s->pivot_root_new);
|
free(s->pivot_root_new);
|
||||||
free(s->pivot_root_old);
|
free(s->pivot_root_old);
|
||||||
free(s->working_directory);
|
free(s->working_directory);
|
||||||
strv_free(s->syscall_whitelist);
|
strv_free(s->syscall_allow_list);
|
||||||
strv_free(s->syscall_blacklist);
|
strv_free(s->syscall_deny_list);
|
||||||
rlimit_free_all(s->rlimit);
|
rlimit_free_all(s->rlimit);
|
||||||
free(s->hostname);
|
free(s->hostname);
|
||||||
cpu_set_reset(&s->cpu_set);
|
cpu_set_reset(&s->cpu_set);
|
||||||
|
@ -689,9 +689,9 @@ int config_parse_syscall_filter(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (negative)
|
if (negative)
|
||||||
r = strv_extend(&settings->syscall_blacklist, word);
|
r = strv_extend(&settings->syscall_deny_list, word);
|
||||||
else
|
else
|
||||||
r = strv_extend(&settings->syscall_whitelist, word);
|
r = strv_extend(&settings->syscall_allow_list, word);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,8 +165,8 @@ typedef struct Settings {
|
||||||
UserNamespaceMode userns_mode;
|
UserNamespaceMode userns_mode;
|
||||||
uid_t uid_shift, uid_range;
|
uid_t uid_shift, uid_range;
|
||||||
bool notify_ready;
|
bool notify_ready;
|
||||||
char **syscall_whitelist;
|
char **syscall_allow_list;
|
||||||
char **syscall_blacklist;
|
char **syscall_deny_list;
|
||||||
struct rlimit *rlimit[_RLIMIT_MAX];
|
struct rlimit *rlimit[_RLIMIT_MAX];
|
||||||
char *hostname;
|
char *hostname;
|
||||||
int no_new_privileges;
|
int no_new_privileges;
|
||||||
|
|
|
@ -200,9 +200,12 @@ static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS
|
||||||
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
|
static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_TMPFS_TMP;
|
||||||
static void *arg_root_hash = NULL;
|
static void *arg_root_hash = NULL;
|
||||||
static char *arg_verity_data = NULL;
|
static char *arg_verity_data = NULL;
|
||||||
|
static char *arg_root_hash_sig_path = NULL;
|
||||||
|
static void *arg_root_hash_sig = NULL;
|
||||||
|
static size_t arg_root_hash_sig_size = 0;
|
||||||
static size_t arg_root_hash_size = 0;
|
static size_t arg_root_hash_size = 0;
|
||||||
static char **arg_syscall_whitelist = NULL;
|
static char **arg_syscall_allow_list = NULL;
|
||||||
static char **arg_syscall_blacklist = NULL;
|
static char **arg_syscall_deny_list = NULL;
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
static scmp_filter_ctx arg_seccomp = NULL;
|
static scmp_filter_ctx arg_seccomp = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -244,8 +247,10 @@ STATIC_DESTRUCTOR_REGISTER(arg_property_message, sd_bus_message_unrefp);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_verity_data, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_syscall_whitelist, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig_path, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_sig, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_syscall_allow_list, strv_freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_syscall_deny_list, strv_freep);
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_seccomp, seccomp_releasep);
|
STATIC_DESTRUCTOR_REGISTER(arg_seccomp, seccomp_releasep);
|
||||||
#endif
|
#endif
|
||||||
|
@ -305,6 +310,10 @@ static int help(void) {
|
||||||
" --read-only Mount the root directory read-only\n"
|
" --read-only Mount the root directory read-only\n"
|
||||||
" --volatile[=MODE] Run the system in volatile mode\n"
|
" --volatile[=MODE] Run the system in volatile mode\n"
|
||||||
" --root-hash=HASH Specify verity root hash for root disk image\n"
|
" --root-hash=HASH Specify verity root hash for root disk image\n"
|
||||||
|
" --root-hash-sig=SIG Specify pkcs7 signature of root hash for verity\n"
|
||||||
|
" as a DER encoded PKCS7, either as a path to a file\n"
|
||||||
|
" or as an ASCII base64 encoded string prefixed by\n"
|
||||||
|
" 'base64:'\n"
|
||||||
" --verity-data=PATH Specify hash device for verity\n"
|
" --verity-data=PATH Specify hash device for verity\n"
|
||||||
" --pivot-root=PATH[:PATH]\n"
|
" --pivot-root=PATH[:PATH]\n"
|
||||||
" Pivot root to given directory in the container\n\n"
|
" Pivot root to given directory in the container\n\n"
|
||||||
|
@ -667,6 +676,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_OCI_BUNDLE,
|
ARG_OCI_BUNDLE,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
ARG_VERITY_DATA,
|
ARG_VERITY_DATA,
|
||||||
|
ARG_ROOT_HASH_SIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct option options[] = {
|
static const struct option options[] = {
|
||||||
|
@ -733,6 +743,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE },
|
{ "oci-bundle", required_argument, NULL, ARG_OCI_BUNDLE },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
{ "verity-data", required_argument, NULL, ARG_VERITY_DATA },
|
||||||
|
{ "root-hash-sig", required_argument, NULL, ARG_ROOT_HASH_SIG },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1327,6 +1338,31 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_ROOT_HASH_SIG: {
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
if ((value = startswith(optarg, "base64:"))) {
|
||||||
|
void *p;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
r = unbase64mem(value, strlen(value), &p, &l);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", optarg);
|
||||||
|
|
||||||
|
free_and_replace(arg_root_hash_sig, p);
|
||||||
|
arg_root_hash_sig_size = l;
|
||||||
|
arg_root_hash_sig_path = mfree(arg_root_hash_sig_path);
|
||||||
|
} else {
|
||||||
|
r = parse_path_argument_and_warn(optarg, false, &arg_root_hash_sig_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
arg_root_hash_sig = mfree(arg_root_hash_sig);
|
||||||
|
arg_root_hash_sig_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ARG_SYSTEM_CALL_FILTER: {
|
case ARG_SYSTEM_CALL_FILTER: {
|
||||||
bool negative;
|
bool negative;
|
||||||
const char *items;
|
const char *items;
|
||||||
|
@ -1346,9 +1382,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return log_error_errno(r, "Failed to parse system call filter: %m");
|
return log_error_errno(r, "Failed to parse system call filter: %m");
|
||||||
|
|
||||||
if (negative)
|
if (negative)
|
||||||
r = strv_extend(&arg_syscall_blacklist, word);
|
r = strv_extend(&arg_syscall_deny_list, word);
|
||||||
else
|
else
|
||||||
r = strv_extend(&arg_syscall_whitelist, word);
|
r = strv_extend(&arg_syscall_allow_list, word);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
@ -2175,10 +2211,11 @@ static int setup_dev_console(const char *console) {
|
||||||
static int setup_keyring(void) {
|
static int setup_keyring(void) {
|
||||||
key_serial_t keyring;
|
key_serial_t keyring;
|
||||||
|
|
||||||
/* Allocate a new session keyring for the container. This makes sure the keyring of the session systemd-nspawn
|
/* Allocate a new session keyring for the container. This makes sure the keyring of the session
|
||||||
* was invoked from doesn't leak into the container. Note that by default we block keyctl() and request_key()
|
* systemd-nspawn was invoked from doesn't leak into the container. Note that by default we block
|
||||||
* anyway via seccomp so doing this operation isn't strictly necessary, but in case people explicitly whitelist
|
* keyctl() and request_key() anyway via seccomp so doing this operation isn't strictly necessary,
|
||||||
* these system calls let's make sure we don't leak anything into the container. */
|
* but in case people explicitly allow-list these system calls let's make sure we don't leak anything
|
||||||
|
* into the container. */
|
||||||
|
|
||||||
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
|
keyring = keyctl(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
|
||||||
if (keyring == -1) {
|
if (keyring == -1) {
|
||||||
|
@ -3089,7 +3126,7 @@ static int inner_child(
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist);
|
r = setup_seccomp(arg_caps_retain, arg_syscall_allow_list, arg_syscall_deny_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -3954,11 +3991,11 @@ static int merge_settings(Settings *settings, const char *path) {
|
||||||
|
|
||||||
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
|
if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
|
||||||
|
|
||||||
if (!arg_settings_trusted && !strv_isempty(settings->syscall_whitelist))
|
if (!arg_settings_trusted && !strv_isempty(settings->syscall_allow_list))
|
||||||
log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path);
|
log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path);
|
||||||
else {
|
else {
|
||||||
strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist);
|
strv_free_and_replace(arg_syscall_allow_list, settings->syscall_allow_list);
|
||||||
strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist);
|
strv_free_and_replace(arg_syscall_deny_list, settings->syscall_deny_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
|
@ -5142,7 +5179,8 @@ static int run(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
r = verity_metadata_load(arg_image, NULL, arg_root_hash ? NULL : &arg_root_hash, &arg_root_hash_size,
|
||||||
arg_verity_data ? NULL : &arg_verity_data);
|
arg_verity_data ? NULL : &arg_verity_data,
|
||||||
|
arg_root_hash_sig_path || arg_root_hash_sig ? NULL : &arg_root_hash_sig_path);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
log_error_errno(r, "Failed to read verity artefacts for %s: %m", arg_image);
|
||||||
goto finish;
|
goto finish;
|
||||||
|
@ -5192,7 +5230,7 @@ static int run(int argc, char *argv[]) {
|
||||||
if (!arg_root_hash && dissected_image->can_verity)
|
if (!arg_root_hash && dissected_image->can_verity)
|
||||||
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
|
log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image);
|
||||||
|
|
||||||
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, 0, &decrypted_image);
|
r = dissected_image_decrypt_interactively(dissected_image, NULL, arg_root_hash, arg_root_hash_size, arg_verity_data, arg_root_hash_sig_path, arg_root_hash_sig, arg_root_hash_sig_size, 0, &decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ static int resize_crypt_luks_device(dev_t devno, const char *fstype, dev_t main_
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int maybe_resize_slave_device(const char *mountpath, dev_t main_devno) {
|
static int maybe_resize_underlying_device(const char *mountpath, dev_t main_devno) {
|
||||||
_cleanup_free_ char *fstype = NULL, *devpath = NULL;
|
_cleanup_free_ char *fstype = NULL, *devpath = NULL;
|
||||||
dev_t devno;
|
dev_t devno;
|
||||||
int r;
|
int r;
|
||||||
|
@ -213,7 +213,7 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
|
return log_error_errno(r, "Failed to determine block device of \"%s\": %m", arg_target);
|
||||||
|
|
||||||
r = maybe_resize_slave_device(arg_target, devno);
|
r = maybe_resize_underlying_device(arg_target, devno);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ static void test_parse_etc_hosts(void) {
|
||||||
"1::2::3 multi.colon\n"
|
"1::2::3 multi.colon\n"
|
||||||
|
|
||||||
"::0 some.where some.other\n"
|
"::0 some.where some.other\n"
|
||||||
"0.0.0.0 black.listed\n"
|
"0.0.0.0 deny.listed\n"
|
||||||
"::5\t\t\t \tsome.where\tsome.other foobar.foo.foo\t\t\t\n"
|
"::5\t\t\t \tsome.where\tsome.other foobar.foo.foo\t\t\t\n"
|
||||||
" \n", f);
|
" \n", f);
|
||||||
assert_se(fflush_and_check(f) >= 0);
|
assert_se(fflush_and_check(f) >= 0);
|
||||||
|
@ -123,7 +123,7 @@ static void test_parse_etc_hosts(void) {
|
||||||
|
|
||||||
assert_se( set_contains(hosts.no_address, "some.where"));
|
assert_se( set_contains(hosts.no_address, "some.where"));
|
||||||
assert_se( set_contains(hosts.no_address, "some.other"));
|
assert_se( set_contains(hosts.no_address, "some.other"));
|
||||||
assert_se( set_contains(hosts.no_address, "black.listed"));
|
assert_se( set_contains(hosts.no_address, "deny.listed"));
|
||||||
assert_se(!set_contains(hosts.no_address, "foobar.foo.foo"));
|
assert_se(!set_contains(hosts.no_address, "foobar.foo.foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1173,11 +1173,11 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
|
|
||||||
if (STR_IN_SET(field, "RestrictAddressFamilies",
|
if (STR_IN_SET(field, "RestrictAddressFamilies",
|
||||||
"SystemCallFilter")) {
|
"SystemCallFilter")) {
|
||||||
int whitelist = 1;
|
int allow_list = 1;
|
||||||
const char *p = eq;
|
const char *p = eq;
|
||||||
|
|
||||||
if (*p == '~') {
|
if (*p == '~') {
|
||||||
whitelist = 0;
|
allow_list = 0;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,7 +1197,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
r = sd_bus_message_append_basic(m, 'b', &whitelist);
|
r = sd_bus_message_append_basic(m, 'b', &allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_create_error(r);
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
@ -1434,6 +1434,26 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||||
return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
|
return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(field, "RootHashSignature")) {
|
||||||
|
_cleanup_free_ void *roothash_sig_decoded = NULL;
|
||||||
|
char *value;
|
||||||
|
size_t roothash_sig_decoded_size = 0;
|
||||||
|
|
||||||
|
/* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
|
||||||
|
if (path_is_absolute(eq))
|
||||||
|
return bus_append_string(m, "RootHashSignaturePath", eq);
|
||||||
|
|
||||||
|
if (!(value = startswith(eq, "base64:")))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
|
||||||
|
|
||||||
|
/* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
|
||||||
|
r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
|
||||||
|
|
||||||
|
return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1223,6 +1223,9 @@ static int verity_partition(
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *verity_data,
|
const char *verity_data,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage *d) {
|
DecryptedImage *d) {
|
||||||
|
|
||||||
|
@ -1267,6 +1270,24 @@ static int verity_partition(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (root_hash_sig || root_hash_sig_path) {
|
||||||
|
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||||
|
if (root_hash_sig)
|
||||||
|
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||||
|
else {
|
||||||
|
_cleanup_free_ char *hash_sig = NULL;
|
||||||
|
size_t hash_sig_size;
|
||||||
|
|
||||||
|
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, &hash_sig, &hash_sig_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, hash_sig, hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()");
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
|
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -1287,6 +1308,9 @@ int dissected_image_decrypt(
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *verity_data,
|
const char *verity_data,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage **ret) {
|
DecryptedImage **ret) {
|
||||||
|
|
||||||
|
@ -1333,7 +1357,7 @@ int dissected_image_decrypt(
|
||||||
|
|
||||||
k = PARTITION_VERITY_OF(i);
|
k = PARTITION_VERITY_OF(i);
|
||||||
if (k >= 0) {
|
if (k >= 0) {
|
||||||
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, flags, d);
|
r = verity_partition(p, m->partitions + k, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags, d);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1359,6 +1383,9 @@ int dissected_image_decrypt_interactively(
|
||||||
const void *root_hash,
|
const void *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
const char *verity_data,
|
const char *verity_data,
|
||||||
|
const char *root_hash_sig_path,
|
||||||
|
const void *root_hash_sig,
|
||||||
|
size_t root_hash_sig_size,
|
||||||
DissectImageFlags flags,
|
DissectImageFlags flags,
|
||||||
DecryptedImage **ret) {
|
DecryptedImage **ret) {
|
||||||
|
|
||||||
|
@ -1369,7 +1396,7 @@ int dissected_image_decrypt_interactively(
|
||||||
n--;
|
n--;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, flags, ret);
|
r = dissected_image_decrypt(m, passphrase, root_hash, root_hash_size, verity_data, root_hash_sig_path, root_hash_sig, root_hash_sig_size, flags, ret);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == -EKEYREJECTED)
|
if (r == -EKEYREJECTED)
|
||||||
|
@ -1421,8 +1448,8 @@ int decrypted_image_relinquish(DecryptedImage *d) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data) {
|
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig) {
|
||||||
_cleanup_free_ char *verity_filename = NULL;
|
_cleanup_free_ char *verity_filename = NULL, *roothashsig_filename = NULL;
|
||||||
_cleanup_free_ void *roothash_decoded = NULL;
|
_cleanup_free_ void *roothash_decoded = NULL;
|
||||||
size_t roothash_decoded_size = 0;
|
size_t roothash_decoded_size = 0;
|
||||||
int r;
|
int r;
|
||||||
|
@ -1437,6 +1464,8 @@ int verity_metadata_load(const char *image, const char *root_hash_path, void **r
|
||||||
*ret_roothash_size = 0;
|
*ret_roothash_size = 0;
|
||||||
if (ret_verity_data)
|
if (ret_verity_data)
|
||||||
*ret_verity_data = NULL;
|
*ret_verity_data = NULL;
|
||||||
|
if (ret_roothashsig)
|
||||||
|
*ret_roothashsig = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1461,6 +1490,29 @@ int verity_metadata_load(const char *image, const char *root_hash_path, void **r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret_roothashsig) {
|
||||||
|
char *e;
|
||||||
|
|
||||||
|
/* Follow naming convention recommended by the relevant RFC:
|
||||||
|
* https://tools.ietf.org/html/rfc5751#section-3.2.1 */
|
||||||
|
roothashsig_filename = new(char, strlen(image) + STRLEN(".roothash.p7s") + 1);
|
||||||
|
if (!roothashsig_filename)
|
||||||
|
return -ENOMEM;
|
||||||
|
strcpy(roothashsig_filename, image);
|
||||||
|
e = endswith(roothashsig_filename, ".raw");
|
||||||
|
if (e)
|
||||||
|
strcpy(e, ".roothash.p7s");
|
||||||
|
else
|
||||||
|
strcat(roothashsig_filename, ".roothash.p7s");
|
||||||
|
|
||||||
|
r = access(roothashsig_filename, R_OK);
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
return -errno;
|
||||||
|
roothashsig_filename = mfree(roothashsig_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ret_roothash) {
|
if (ret_roothash) {
|
||||||
_cleanup_free_ char *text = NULL;
|
_cleanup_free_ char *text = NULL;
|
||||||
assert(ret_roothash_size);
|
assert(ret_roothash_size);
|
||||||
|
@ -1507,6 +1559,8 @@ int verity_metadata_load(const char *image, const char *root_hash_path, void **r
|
||||||
}
|
}
|
||||||
if (ret_verity_data)
|
if (ret_verity_data)
|
||||||
*ret_verity_data = TAKE_PTR(verity_filename);
|
*ret_verity_data = TAKE_PTR(verity_filename);
|
||||||
|
if (roothashsig_filename)
|
||||||
|
*ret_roothashsig = TAKE_PTR(roothashsig_filename);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,8 +87,8 @@ int dissect_image_and_warn(int fd, const char *name, const void *root_hash, size
|
||||||
DissectedImage* dissected_image_unref(DissectedImage *m);
|
DissectedImage* dissected_image_unref(DissectedImage *m);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
|
||||||
|
|
||||||
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DecryptedImage **ret);
|
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, DissectImageFlags flags, DecryptedImage **ret);
|
||||||
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, DissectImageFlags flags, DecryptedImage **ret);
|
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, const char *verity_data, const char *root_hash_sig_path, const void *root_hash_sig, size_t root_hash_sig_size, DissectImageFlags flags, DecryptedImage **ret);
|
||||||
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
|
int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
|
||||||
|
|
||||||
int dissected_image_acquire_metadata(DissectedImage *m);
|
int dissected_image_acquire_metadata(DissectedImage *m);
|
||||||
|
@ -100,6 +100,6 @@ int decrypted_image_relinquish(DecryptedImage *d);
|
||||||
const char* partition_designator_to_string(int i) _const_;
|
const char* partition_designator_to_string(int i) _const_;
|
||||||
int partition_designator_from_string(const char *name) _pure_;
|
int partition_designator_from_string(const char *name) _pure_;
|
||||||
|
|
||||||
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data);
|
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig);
|
||||||
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
|
|
|
@ -573,19 +573,22 @@ static int output_short(
|
||||||
if (config_file &&
|
if (config_file &&
|
||||||
message_len >= config_file_len &&
|
message_len >= config_file_len &&
|
||||||
memcmp(message, config_file, config_file_len) == 0 &&
|
memcmp(message, config_file, config_file_len) == 0 &&
|
||||||
IN_SET(message[config_file_len], ':', ' ', '\0') &&
|
(message_len == config_file_len || IN_SET(message[config_file_len], ':', ' ')) &&
|
||||||
(!highlight || highlight_shifted[0] == 0 || highlight_shifted[0] > config_file_len)) {
|
(!highlight || highlight_shifted[0] == 0 || highlight_shifted[0] > config_file_len)) {
|
||||||
|
|
||||||
_cleanup_free_ char *t = NULL, *urlified = NULL;
|
_cleanup_free_ char *t = NULL, *urlified = NULL;
|
||||||
|
|
||||||
t = strndup(config_file, config_file_len);
|
t = strndup(config_file, config_file_len);
|
||||||
if (t && terminal_urlify_path(t, NULL, &urlified) >= 0) {
|
if (t && terminal_urlify_path(t, NULL, &urlified) >= 0) {
|
||||||
size_t shift = strlen(urlified) - config_file_len;
|
size_t urlified_len = strlen(urlified);
|
||||||
|
size_t shift = urlified_len - config_file_len;
|
||||||
char *joined;
|
char *joined;
|
||||||
|
|
||||||
joined = strjoin(urlified, message + config_file_len);
|
joined = realloc(urlified, message_len + shift);
|
||||||
if (joined) {
|
if (joined) {
|
||||||
|
memcpy(joined + urlified_len, message + config_file_len, message_len - config_file_len);
|
||||||
free_and_replace(message, joined);
|
free_and_replace(message, joined);
|
||||||
|
TAKE_PTR(urlified);
|
||||||
message_len += shift;
|
message_len += shift;
|
||||||
if (highlight) {
|
if (highlight) {
|
||||||
highlight_shifted[0] += shift;
|
highlight_shifted[0] += shift;
|
||||||
|
|
|
@ -51,7 +51,7 @@ int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose)
|
||||||
"Inserted module '%s'", kmod_module_get_name(mod));
|
"Inserted module '%s'", kmod_module_get_name(mod));
|
||||||
else if (err == KMOD_PROBE_APPLY_BLACKLIST)
|
else if (err == KMOD_PROBE_APPLY_BLACKLIST)
|
||||||
log_full(verbose ? LOG_INFO : LOG_DEBUG,
|
log_full(verbose ? LOG_INFO : LOG_DEBUG,
|
||||||
"Module '%s' is blacklisted", kmod_module_get_name(mod));
|
"Module '%s' is deny-listed", kmod_module_get_name(mod));
|
||||||
else {
|
else {
|
||||||
assert(err < 0);
|
assert(err < 0);
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ int bind_remount_recursive_with_mountinfo(
|
||||||
const char *prefix,
|
const char *prefix,
|
||||||
unsigned long new_flags,
|
unsigned long new_flags,
|
||||||
unsigned long flags_mask,
|
unsigned long flags_mask,
|
||||||
char **blacklist,
|
char **deny_list,
|
||||||
FILE *proc_self_mountinfo) {
|
FILE *proc_self_mountinfo) {
|
||||||
|
|
||||||
_cleanup_set_free_free_ Set *done = NULL;
|
_cleanup_set_free_free_ Set *done = NULL;
|
||||||
|
@ -154,8 +154,8 @@ int bind_remount_recursive_with_mountinfo(
|
||||||
* do not have any effect on future submounts that might get propagated, they might be writable. This includes
|
* do not have any effect on future submounts that might get propagated, they might be writable. This includes
|
||||||
* future submounts that have been triggered via autofs.
|
* future submounts that have been triggered via autofs.
|
||||||
*
|
*
|
||||||
* If the "blacklist" parameter is specified it may contain a list of subtrees to exclude from the
|
* If the "deny_list" parameter is specified it may contain a list of subtrees to exclude from the
|
||||||
* remount operation. Note that we'll ignore the blacklist for the top-level path. */
|
* remount operation. Note that we'll ignore the deny list for the top-level path. */
|
||||||
|
|
||||||
simplified = strdup(prefix);
|
simplified = strdup(prefix);
|
||||||
if (!simplified)
|
if (!simplified)
|
||||||
|
@ -203,13 +203,13 @@ int bind_remount_recursive_with_mountinfo(
|
||||||
if (!path_startswith(path, simplified))
|
if (!path_startswith(path, simplified))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Ignore this mount if it is blacklisted, but only if it isn't the top-level mount
|
/* Ignore this mount if it is deny-listed, but only if it isn't the top-level mount
|
||||||
* we shall operate on. */
|
* we shall operate on. */
|
||||||
if (!path_equal(path, simplified)) {
|
if (!path_equal(path, simplified)) {
|
||||||
bool blacklisted = false;
|
bool deny_listed = false;
|
||||||
char **i;
|
char **i;
|
||||||
|
|
||||||
STRV_FOREACH(i, blacklist) {
|
STRV_FOREACH(i, deny_list) {
|
||||||
if (path_equal(*i, simplified))
|
if (path_equal(*i, simplified))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -217,13 +217,13 @@ int bind_remount_recursive_with_mountinfo(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (path_startswith(path, *i)) {
|
if (path_startswith(path, *i)) {
|
||||||
blacklisted = true;
|
deny_listed = true;
|
||||||
log_debug("Not remounting %s blacklisted by %s, called for %s",
|
log_debug("Not remounting %s deny-listed by %s, called for %s",
|
||||||
path, *i, simplified);
|
path, *i, simplified);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (blacklisted)
|
if (deny_listed)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +314,7 @@ int bind_remount_recursive(
|
||||||
const char *prefix,
|
const char *prefix,
|
||||||
unsigned long new_flags,
|
unsigned long new_flags,
|
||||||
unsigned long flags_mask,
|
unsigned long flags_mask,
|
||||||
char **blacklist) {
|
char **deny_list) {
|
||||||
|
|
||||||
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -323,7 +323,7 @@ int bind_remount_recursive(
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return bind_remount_recursive_with_mountinfo(prefix, new_flags, flags_mask, blacklist, proc_self_mountinfo);
|
return bind_remount_recursive_with_mountinfo(prefix, new_flags, flags_mask, deny_list, proc_self_mountinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bind_remount_one_with_mountinfo(
|
int bind_remount_one_with_mountinfo(
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
|
|
||||||
int repeat_unmount(const char *path, int flags);
|
int repeat_unmount(const char *path, int flags);
|
||||||
int umount_recursive(const char *target, int flags);
|
int umount_recursive(const char *target, int flags);
|
||||||
int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist);
|
int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **deny_list);
|
||||||
int bind_remount_recursive_with_mountinfo(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist, FILE *proc_self_mountinfo);
|
int bind_remount_recursive_with_mountinfo(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **deny_list, FILE *proc_self_mountinfo);
|
||||||
int bind_remount_one_with_mountinfo(const char *path, unsigned long new_flags, unsigned long flags_mask, FILE *proc_self_mountinfo);
|
int bind_remount_one_with_mountinfo(const char *path, unsigned long new_flags, unsigned long flags_mask, FILE *proc_self_mountinfo);
|
||||||
|
|
||||||
int mount_move_root(const char *path);
|
int mount_move_root(const char *path);
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
const uint32_t seccomp_local_archs[] = {
|
const uint32_t seccomp_local_archs[] = {
|
||||||
|
|
||||||
/* Note: always list the native arch we are compiled as last, so that users can blacklist seccomp(), but our own calls to it still succeed */
|
/* Note: always list the native arch we are compiled as last, so that users can deny-list seccomp(), but our own calls to it still succeed */
|
||||||
|
|
||||||
#if defined(__x86_64__) && defined(__ILP32__)
|
#if defined(__x86_64__) && defined(__ILP32__)
|
||||||
SCMP_ARCH_X86,
|
SCMP_ARCH_X86,
|
||||||
|
@ -1112,7 +1112,7 @@ int seccomp_parse_syscall_filter(
|
||||||
|
|
||||||
/* If we previously wanted to forbid a syscall and now
|
/* If we previously wanted to forbid a syscall and now
|
||||||
* we want to allow it, then remove it from the list. */
|
* we want to allow it, then remove it from the list. */
|
||||||
if (!(flags & SECCOMP_PARSE_INVERT) == !!(flags & SECCOMP_PARSE_WHITELIST)) {
|
if (!(flags & SECCOMP_PARSE_INVERT) == !!(flags & SECCOMP_PARSE_ALLOW_LIST)) {
|
||||||
r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
|
r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
switch (r) {
|
switch (r) {
|
||||||
|
@ -1315,7 +1315,7 @@ int seccomp_protect_syslog(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
|
int seccomp_restrict_address_families(Set *address_families, bool allow_list) {
|
||||||
uint32_t arch;
|
uint32_t arch;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
@ -1362,13 +1362,13 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (whitelist) {
|
if (allow_list) {
|
||||||
int af, first = 0, last = 0;
|
int af, first = 0, last = 0;
|
||||||
void *afp;
|
void *afp;
|
||||||
|
|
||||||
/* If this is a whitelist, we first block the address families that are out of range and then
|
/* If this is an allow list, we first block the address families that are out of
|
||||||
* everything that is not in the set. First, we find the lowest and highest address family in
|
* range and then everything that is not in the set. First, we find the lowest and
|
||||||
* the set. */
|
* highest address family in the set. */
|
||||||
|
|
||||||
SET_FOREACH(afp, address_families, i) {
|
SET_FOREACH(afp, address_families, i) {
|
||||||
af = PTR_TO_INT(afp);
|
af = PTR_TO_INT(afp);
|
||||||
|
@ -1448,9 +1448,8 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist) {
|
||||||
} else {
|
} else {
|
||||||
void *af;
|
void *af;
|
||||||
|
|
||||||
/* If this is a blacklist, then generate one rule for
|
/* If this is a deny list, then generate one rule for each address family that are
|
||||||
* each address family that are then combined in OR
|
* then combined in OR checks. */
|
||||||
* checks. */
|
|
||||||
|
|
||||||
SET_FOREACH(af, address_families, i) {
|
SET_FOREACH(af, address_families, i) {
|
||||||
|
|
||||||
|
@ -1506,11 +1505,11 @@ int seccomp_restrict_realtime(void) {
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* Go through all policies with lower values than that, and block them -- unless they appear in the
|
/* Go through all policies with lower values than that, and block them -- unless they appear in the
|
||||||
* whitelist. */
|
* allow list. */
|
||||||
for (p = 0; p < max_policy; p++) {
|
for (p = 0; p < max_policy; p++) {
|
||||||
bool good = false;
|
bool good = false;
|
||||||
|
|
||||||
/* Check if this is in the whitelist. */
|
/* Check if this is in the allow list. */
|
||||||
for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
|
for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
|
||||||
if (permitted_policies[i] == p) {
|
if (permitted_policies[i] == p) {
|
||||||
good = true;
|
good = true;
|
||||||
|
@ -1533,8 +1532,8 @@ int seccomp_restrict_realtime(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Blacklist all other policies, i.e. the ones with higher values. Note that all comparisons are
|
/* Deny-list all other policies, i.e. the ones with higher values. Note that all comparisons
|
||||||
* unsigned here, hence no need no check for < 0 values. */
|
* are unsigned here, hence no need no check for < 0 values. */
|
||||||
r = seccomp_rule_add_exact(
|
r = seccomp_rule_add_exact(
|
||||||
seccomp,
|
seccomp,
|
||||||
SCMP_ACT_ERRNO(EPERM),
|
SCMP_ACT_ERRNO(EPERM),
|
||||||
|
|
|
@ -66,7 +66,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u
|
||||||
|
|
||||||
typedef enum SeccompParseFlags {
|
typedef enum SeccompParseFlags {
|
||||||
SECCOMP_PARSE_INVERT = 1 << 0,
|
SECCOMP_PARSE_INVERT = 1 << 0,
|
||||||
SECCOMP_PARSE_WHITELIST = 1 << 1,
|
SECCOMP_PARSE_ALLOW_LIST = 1 << 1,
|
||||||
SECCOMP_PARSE_LOG = 1 << 2,
|
SECCOMP_PARSE_LOG = 1 << 2,
|
||||||
SECCOMP_PARSE_PERMISSIVE = 1 << 3,
|
SECCOMP_PARSE_PERMISSIVE = 1 << 3,
|
||||||
} SeccompParseFlags;
|
} SeccompParseFlags;
|
||||||
|
@ -83,7 +83,7 @@ int seccomp_restrict_archs(Set *archs);
|
||||||
int seccomp_restrict_namespaces(unsigned long retain);
|
int seccomp_restrict_namespaces(unsigned long retain);
|
||||||
int seccomp_protect_sysctl(void);
|
int seccomp_protect_sysctl(void);
|
||||||
int seccomp_protect_syslog(void);
|
int seccomp_protect_syslog(void);
|
||||||
int seccomp_restrict_address_families(Set *address_families, bool whitelist);
|
int seccomp_restrict_address_families(Set *address_families, bool allow_list);
|
||||||
int seccomp_restrict_realtime(void);
|
int seccomp_restrict_realtime(void);
|
||||||
int seccomp_memory_deny_write_execute(void);
|
int seccomp_memory_deny_write_execute(void);
|
||||||
int seccomp_lock_personality(unsigned long personality);
|
int seccomp_lock_personality(unsigned long personality);
|
||||||
|
|
|
@ -4819,13 +4819,13 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
|
|
||||||
} else if (STR_IN_SET(name, "SystemCallFilter", "RestrictAddressFamilies")) {
|
} else if (STR_IN_SET(name, "SystemCallFilter", "RestrictAddressFamilies")) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
int whitelist;
|
int allow_list;
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(m, 'r', "bas");
|
r = sd_bus_message_enter_container(m, 'r', "bas");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_parse_error(r);
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
r = sd_bus_message_read(m, "b", &whitelist);
|
r = sd_bus_message_read(m, "b", &allow_list);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_parse_error(r);
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
|
@ -4837,7 +4837,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return bus_log_parse_error(r);
|
return bus_log_parse_error(r);
|
||||||
|
|
||||||
if (all || whitelist || !strv_isempty(l)) {
|
if (all || allow_list || !strv_isempty(l)) {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
char **i;
|
char **i;
|
||||||
|
|
||||||
|
@ -4846,7 +4846,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
fputc('=', stdout);
|
fputc('=', stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!whitelist)
|
if (!allow_list)
|
||||||
fputc('~', stdout);
|
fputc('~', stdout);
|
||||||
|
|
||||||
STRV_FOREACH(i, l) {
|
STRV_FOREACH(i, l) {
|
||||||
|
@ -5188,7 +5188,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
} else if (contents[0] == SD_BUS_TYPE_BYTE && streq(name, "StandardInputData")) {
|
} else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "StandardInputData", "RootHashSignature")) {
|
||||||
_cleanup_free_ char *h = NULL;
|
_cleanup_free_ char *h = NULL;
|
||||||
const void *p;
|
const void *p;
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
|
|
@ -24,7 +24,7 @@ static void test_policy_closed(const char *cgroup_path, BPFProgram **installed_p
|
||||||
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_CLOSED, true);
|
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_CLOSED, true);
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_whitelist_static(prog, cgroup_path);
|
r = bpf_devices_allow_list_static(prog, cgroup_path);
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_CLOSED, true, cgroup_path, installed_prog);
|
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_CLOSED, true, cgroup_path, installed_prog);
|
||||||
|
@ -62,13 +62,13 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p
|
||||||
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
|
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_whitelist_device(prog, cgroup_path, "/dev/null", "rw");
|
r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/null", "rw");
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_whitelist_device(prog, cgroup_path, "/dev/random", "r");
|
r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/random", "r");
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_whitelist_device(prog, cgroup_path, "/dev/zero", "w");
|
r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/zero", "w");
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
|
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
|
||||||
|
@ -129,7 +129,7 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p
|
||||||
assert_se(wrong == 0);
|
assert_se(wrong == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_policy_whitelist_major(const char *pattern, const char *cgroup_path, BPFProgram **installed_prog) {
|
static void test_policy_allow_list_major(const char *pattern, const char *cgroup_path, BPFProgram **installed_prog) {
|
||||||
_cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
|
_cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
|
||||||
unsigned wrong = 0;
|
unsigned wrong = 0;
|
||||||
int r;
|
int r;
|
||||||
|
@ -139,7 +139,7 @@ static void test_policy_whitelist_major(const char *pattern, const char *cgroup_
|
||||||
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
|
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_whitelist_major(prog, cgroup_path, pattern, 'c', "rw");
|
r = bpf_devices_allow_list_major(prog, cgroup_path, pattern, 'c', "rw");
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
|
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
|
||||||
|
@ -188,7 +188,7 @@ static void test_policy_whitelist_major(const char *pattern, const char *cgroup_
|
||||||
assert_se(wrong == 0);
|
assert_se(wrong == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_policy_whitelist_major_star(char type, const char *cgroup_path, BPFProgram **installed_prog) {
|
static void test_policy_allow_list_major_star(char type, const char *cgroup_path, BPFProgram **installed_prog) {
|
||||||
_cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
|
_cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
|
||||||
unsigned wrong = 0;
|
unsigned wrong = 0;
|
||||||
int r;
|
int r;
|
||||||
|
@ -198,7 +198,7 @@ static void test_policy_whitelist_major_star(char type, const char *cgroup_path,
|
||||||
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
|
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_whitelist_major(prog, cgroup_path, "*", type, "rw");
|
r = bpf_devices_allow_list_major(prog, cgroup_path, "*", type, "rw");
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
|
r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
|
||||||
|
@ -230,7 +230,7 @@ static void test_policy_empty(bool add_mismatched, const char *cgroup_path, BPFP
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
|
||||||
if (add_mismatched) {
|
if (add_mismatched) {
|
||||||
r = bpf_devices_whitelist_major(prog, cgroup_path, "foobarxxx", 'c', "rw");
|
r = bpf_devices_allow_list_major(prog, cgroup_path, "foobarxxx", 'c', "rw");
|
||||||
assert_se(r < 0);
|
assert_se(r < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,11 +287,11 @@ int main(int argc, char *argv[]) {
|
||||||
test_policy_closed(cgroup, &prog);
|
test_policy_closed(cgroup, &prog);
|
||||||
test_policy_strict(cgroup, &prog);
|
test_policy_strict(cgroup, &prog);
|
||||||
|
|
||||||
test_policy_whitelist_major("mem", cgroup, &prog);
|
test_policy_allow_list_major("mem", cgroup, &prog);
|
||||||
test_policy_whitelist_major("1", cgroup, &prog);
|
test_policy_allow_list_major("1", cgroup, &prog);
|
||||||
|
|
||||||
test_policy_whitelist_major_star('c', cgroup, &prog);
|
test_policy_allow_list_major_star('c', cgroup, &prog);
|
||||||
test_policy_whitelist_major_star('b', cgroup, &prog);
|
test_policy_allow_list_major_star('b', cgroup, &prog);
|
||||||
|
|
||||||
test_policy_empty(false, cgroup, &prog);
|
test_policy_empty(false, cgroup, &prog);
|
||||||
test_policy_empty(true, cgroup, &prog);
|
test_policy_empty(true, cgroup, &prog);
|
||||||
|
|
|
@ -467,7 +467,7 @@ static void test_exec_restrictnamespaces(Manager *m) {
|
||||||
test(__func__, m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
test(__func__, m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
|
||||||
test(__func__, m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
test(__func__, m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-mnt-deny-list.service", 1, CLD_EXITED);
|
||||||
test(__func__, m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
test(__func__, m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
test(__func__, m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
test(__func__, m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#include "tmpfile-util.h"
|
#include "tmpfile-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
|
|
||||||
|
/* Nontrivial value serves as a placeholder to check that parsing function (didn't) change it */
|
||||||
|
#define CGROUP_LIMIT_DUMMY 3
|
||||||
|
|
||||||
static int test_unit_file_get_set(void) {
|
static int test_unit_file_get_set(void) {
|
||||||
int r;
|
int r;
|
||||||
Hashmap *h;
|
Hashmap *h;
|
||||||
|
@ -773,6 +776,62 @@ static void test_unit_dump_config_items(void) {
|
||||||
unit_dump_config_items(stdout);
|
unit_dump_config_items(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_config_parse_memory_limit(void) {
|
||||||
|
/* int config_parse_memory_limit(
|
||||||
|
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) */
|
||||||
|
CGroupContext c;
|
||||||
|
struct limit_test {
|
||||||
|
const char *limit;
|
||||||
|
const char *value;
|
||||||
|
uint64_t *result;
|
||||||
|
uint64_t expected;
|
||||||
|
} limit_tests[]= {
|
||||||
|
{ "MemoryMin", "", &c.memory_min, CGROUP_LIMIT_MIN },
|
||||||
|
{ "MemoryMin", "0", &c.memory_min, CGROUP_LIMIT_MIN },
|
||||||
|
{ "MemoryMin", "10", &c.memory_min, 10 },
|
||||||
|
{ "MemoryMin", "infinity", &c.memory_min, CGROUP_LIMIT_MAX },
|
||||||
|
{ "MemoryLow", "", &c.memory_low, CGROUP_LIMIT_MIN },
|
||||||
|
{ "MemoryLow", "0", &c.memory_low, CGROUP_LIMIT_MIN },
|
||||||
|
{ "MemoryLow", "10", &c.memory_low, 10 },
|
||||||
|
{ "MemoryLow", "infinity", &c.memory_low, CGROUP_LIMIT_MAX },
|
||||||
|
{ "MemoryHigh", "", &c.memory_high, CGROUP_LIMIT_MAX },
|
||||||
|
{ "MemoryHigh", "0", &c.memory_high, CGROUP_LIMIT_DUMMY },
|
||||||
|
{ "MemoryHigh", "10", &c.memory_high, 10 },
|
||||||
|
{ "MemoryHigh", "infinity", &c.memory_high, CGROUP_LIMIT_MAX },
|
||||||
|
{ "MemoryMax", "", &c.memory_max, CGROUP_LIMIT_MAX },
|
||||||
|
{ "MemoryMax", "0", &c.memory_max, CGROUP_LIMIT_DUMMY },
|
||||||
|
{ "MemoryMax", "10", &c.memory_max, 10 },
|
||||||
|
{ "MemoryMax", "infinity", &c.memory_max, CGROUP_LIMIT_MAX },
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
for (i = 0; i < ELEMENTSOF(limit_tests); i++) {
|
||||||
|
c.memory_min = CGROUP_LIMIT_DUMMY;
|
||||||
|
c.memory_low = CGROUP_LIMIT_DUMMY;
|
||||||
|
c.memory_high = CGROUP_LIMIT_DUMMY;
|
||||||
|
c.memory_max = CGROUP_LIMIT_DUMMY;
|
||||||
|
r = config_parse_memory_limit(NULL, "fake", 1, "section", 1,
|
||||||
|
limit_tests[i].limit, 1,
|
||||||
|
limit_tests[i].value, &c, NULL);
|
||||||
|
log_info("%s=%s\t%"PRIu64"==%"PRIu64"\n",
|
||||||
|
limit_tests[i].limit, limit_tests[i].value,
|
||||||
|
*limit_tests[i].result, limit_tests[i].expected);
|
||||||
|
assert_se(r >= 0);
|
||||||
|
assert_se(*limit_tests[i].result == limit_tests[i].expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
|
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -793,6 +852,7 @@ int main(int argc, char *argv[]) {
|
||||||
test_config_parse_pass_environ();
|
test_config_parse_pass_environ();
|
||||||
TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
|
TEST_REQ_RUNNING_SYSTEMD(test_install_printf());
|
||||||
test_unit_dump_config_items();
|
test_unit_dump_config_items();
|
||||||
|
test_config_parse_memory_limit();
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,9 @@ static void test_protect_kernel_logs(void) {
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
assert_se(r == 0);
|
assert_se(r == 0);
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,9 @@ int main(int argc, char *argv[]) {
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to set up namespace: %m");
|
log_error_errno(r, "Failed to set up namespace: %m");
|
||||||
|
|
|
@ -123,7 +123,7 @@ static void test_filter_sets(void) {
|
||||||
if (pid == 0) { /* Child? */
|
if (pid == 0) { /* Child? */
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
/* If we look at the default set (or one that includes it), whitelist instead of blacklist */
|
/* If we look at the default set (or one that includes it), allow-list instead of deny-list */
|
||||||
if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE))
|
if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE))
|
||||||
r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true);
|
r = seccomp_load_syscall_filter_set(SCMP_ACT_ERRNO(EUCLEAN), syscall_filter_sets + i, SCMP_ACT_ALLOW, true);
|
||||||
else
|
else
|
||||||
|
|
|
@ -87,7 +87,7 @@ static int run(int argc, char *argv[]) {
|
||||||
action = argv[1];
|
action = argv[1];
|
||||||
devpath = argv[2];
|
devpath = argv[2];
|
||||||
|
|
||||||
assert_se(udev_rules_new(&rules, RESOLVE_NAME_EARLY) == 0);
|
assert_se(udev_rules_load(&rules, RESOLVE_NAME_EARLY) == 0);
|
||||||
|
|
||||||
const char *syspath = strjoina("/sys", devpath);
|
const char *syspath = strjoina("/sys", devpath);
|
||||||
r = device_new_from_synthetic_event(&dev, syspath, action);
|
r = device_new_from_synthetic_event(&dev, syspath, action);
|
||||||
|
|
|
@ -2405,8 +2405,7 @@ static bool should_include_path(const char *path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no matches, so we should include this path only if we
|
/* no matches, so we should include this path only if we have no allow list at all */
|
||||||
* have no whitelist at all */
|
|
||||||
if (strv_isempty(arg_include_prefixes))
|
if (strv_isempty(arg_include_prefixes))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -1175,7 +1175,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_file(UdevRules *rules, const char *filename) {
|
int udev_rules_parse_file(UdevRules *rules, const char *filename) {
|
||||||
_cleanup_free_ char *continuation = NULL, *name = NULL;
|
_cleanup_free_ char *continuation = NULL, *name = NULL;
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
UdevRuleFile *rule_file;
|
UdevRuleFile *rule_file;
|
||||||
|
@ -1278,30 +1278,41 @@ static int parse_file(UdevRules *rules, const char *filename) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing) {
|
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing) {
|
||||||
_cleanup_(udev_rules_freep) UdevRules *rules = NULL;
|
|
||||||
_cleanup_strv_free_ char **files = NULL;
|
|
||||||
char **f;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(resolve_name_timing >= 0 && resolve_name_timing < _RESOLVE_NAME_TIMING_MAX);
|
assert(resolve_name_timing >= 0 && resolve_name_timing < _RESOLVE_NAME_TIMING_MAX);
|
||||||
|
|
||||||
rules = new(UdevRules, 1);
|
UdevRules *rules = new(UdevRules, 1);
|
||||||
if (!rules)
|
if (!rules)
|
||||||
return -ENOMEM;
|
return NULL;
|
||||||
|
|
||||||
*rules = (UdevRules) {
|
*rules = (UdevRules) {
|
||||||
.resolve_name_timing = resolve_name_timing,
|
.resolve_name_timing = resolve_name_timing,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing) {
|
||||||
|
_cleanup_(udev_rules_freep) UdevRules *rules = NULL;
|
||||||
|
_cleanup_strv_free_ char **files = NULL;
|
||||||
|
char **f;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
rules = udev_rules_new(resolve_name_timing);
|
||||||
|
if (!rules)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
(void) udev_rules_check_timestamp(rules);
|
(void) udev_rules_check_timestamp(rules);
|
||||||
|
|
||||||
r = conf_files_list_strv(&files, ".rules", NULL, 0, RULES_DIRS);
|
r = conf_files_list_strv(&files, ".rules", NULL, 0, RULES_DIRS);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to enumerate rules files: %m");
|
return log_debug_errno(r, "Failed to enumerate rules files: %m");
|
||||||
|
|
||||||
STRV_FOREACH(f, files)
|
STRV_FOREACH(f, files) {
|
||||||
(void) parse_file(rules, *f);
|
r = udev_rules_parse_file(rules, *f);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug_errno(r, "Failed to read rules file %s, ignoring: %m", *f);
|
||||||
|
}
|
||||||
|
|
||||||
*ret_rules = TAKE_PTR(rules);
|
*ret_rules = TAKE_PTR(rules);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -16,7 +16,9 @@ typedef enum {
|
||||||
_ESCAPE_TYPE_INVALID = -1
|
_ESCAPE_TYPE_INVALID = -1
|
||||||
} UdevRuleEscapeType;
|
} UdevRuleEscapeType;
|
||||||
|
|
||||||
int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing);
|
int udev_rules_parse_file(UdevRules *rules, const char *filename);
|
||||||
|
UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing);
|
||||||
|
int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing);
|
||||||
UdevRules *udev_rules_free(UdevRules *rules);
|
UdevRules *udev_rules_free(UdevRules *rules);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free);
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ int test_main(int argc, char *argv[], void *userdata) {
|
||||||
|
|
||||||
udev_builtin_init();
|
udev_builtin_init();
|
||||||
|
|
||||||
r = udev_rules_new(&rules, arg_resolve_name_timing);
|
r = udev_rules_load(&rules, arg_resolve_name_timing);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to read udev rules: %m");
|
log_error_errno(r, "Failed to read udev rules: %m");
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -925,7 +925,7 @@ static void event_queue_start(Manager *manager) {
|
||||||
udev_builtin_init();
|
udev_builtin_init();
|
||||||
|
|
||||||
if (!manager->rules) {
|
if (!manager->rules) {
|
||||||
r = udev_rules_new(&manager->rules, arg_resolve_name_timing);
|
r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_warning_errno(r, "Failed to read udev rules: %m");
|
log_warning_errno(r, "Failed to read udev rules: %m");
|
||||||
return;
|
return;
|
||||||
|
@ -1787,7 +1787,7 @@ static int main_loop(Manager *manager) {
|
||||||
|
|
||||||
udev_builtin_init();
|
udev_builtin_init();
|
||||||
|
|
||||||
r = udev_rules_new(&manager->rules, arg_resolve_name_timing);
|
r = udev_rules_load(&manager->rules, arg_resolve_name_timing);
|
||||||
if (!manager->rules)
|
if (!manager->rules)
|
||||||
return log_error_errno(r, "Failed to read udev rules: %m");
|
return log_error_errno(r, "Failed to read udev rules: %m");
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "crypt-util.h"
|
#include "crypt-util.h"
|
||||||
|
#include "fileio.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
|
@ -29,7 +31,7 @@ static int help(void) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH\n"
|
printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH [ROOTHASHSIG]\n"
|
||||||
"%s detach VOLUME\n\n"
|
"%s detach VOLUME\n\n"
|
||||||
"Attaches or detaches an integrity protected block device.\n"
|
"Attaches or detaches an integrity protected block device.\n"
|
||||||
"\nSee the %s for details.\n"
|
"\nSee the %s for details.\n"
|
||||||
|
@ -87,6 +89,27 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to configure data device: %m");
|
return log_error_errno(r, "Failed to configure data device: %m");
|
||||||
|
|
||||||
|
if (argc > 6) {
|
||||||
|
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||||
|
_cleanup_free_ char *hash_sig = NULL;
|
||||||
|
size_t hash_sig_size;
|
||||||
|
char *value;
|
||||||
|
|
||||||
|
if ((value = startswith(argv[6], "base64:"))) {
|
||||||
|
r = unbase64mem(value, strlen(value), (void *)&hash_sig, &hash_sig_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
|
||||||
|
} else {
|
||||||
|
r = read_full_file_full(AT_FDCWD, argv[6], 0, &hash_sig, &hash_sig_size);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to read root hash signature: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
r = crypt_activate_by_signed_key(cd, argv[2], m, l, hash_sig, hash_sig_size, CRYPT_ACTIVATE_READONLY);
|
||||||
|
#else
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature %s requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()", argv[6]);
|
||||||
|
#endif
|
||||||
|
} else
|
||||||
r = crypt_activate_by_volume_key(cd, argv[2], m, l, CRYPT_ACTIVATE_READONLY);
|
r = crypt_activate_by_volume_key(cd, argv[2], m, l, CRYPT_ACTIVATE_READONLY);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to set up verity device: %m");
|
return log_error_errno(r, "Failed to set up verity device: %m");
|
||||||
|
|
Binary file not shown.
|
@ -96,6 +96,7 @@ ClientIdentifier=
|
||||||
ListenPort=
|
ListenPort=
|
||||||
UseTimezone=
|
UseTimezone=
|
||||||
RouteTable=
|
RouteTable=
|
||||||
|
DenyList=
|
||||||
BlackList=
|
BlackList=
|
||||||
RequestOptions=
|
RequestOptions=
|
||||||
SendRelease=
|
SendRelease=
|
||||||
|
@ -279,6 +280,7 @@ UseDNS=
|
||||||
DHCPv6Client=
|
DHCPv6Client=
|
||||||
UseAutonomousPrefix=
|
UseAutonomousPrefix=
|
||||||
UseOnLinkPrefix=
|
UseOnLinkPrefix=
|
||||||
|
DenyList=
|
||||||
BlackList=
|
BlackList=
|
||||||
[DHCPServer]
|
[DHCPServer]
|
||||||
EmitNTP=
|
EmitNTP=
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[IPv6AcceptRA]
|
[IPv6AcceptRA]
|
||||||
BlackList=70:: 70::
|
DenyList=70:: 70::
|
File diff suppressed because one or more lines are too long
|
@ -197,6 +197,7 @@ RootDirectory=
|
||||||
RootDirectoryStartOnly=
|
RootDirectoryStartOnly=
|
||||||
RootImage=
|
RootImage=
|
||||||
RootHash=
|
RootHash=
|
||||||
|
RootHashSignature=
|
||||||
RootVerity=
|
RootVerity=
|
||||||
RuntimeMaxSec=
|
RuntimeMaxSec=
|
||||||
SELinuxContextFromNet=
|
SELinuxContextFromNet=
|
||||||
|
|
|
@ -6,7 +6,7 @@ set -u
|
||||||
|
|
||||||
REPO_ROOT=${REPO_ROOT:-$(pwd)}
|
REPO_ROOT=${REPO_ROOT:-$(pwd)}
|
||||||
|
|
||||||
sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse' >>/etc/apt/sources.list"
|
sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted universe multiverse' >>/etc/apt/sources.list"
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
sudo apt-get build-dep systemd -y
|
sudo apt-get build-dep systemd -y
|
||||||
sudo apt-get install -y ninja-build python3-pip python3-setuptools quota
|
sudo apt-get install -y ninja-build python3-pip python3-setuptools quota
|
||||||
|
@ -19,18 +19,3 @@ export PATH="$HOME/.local/bin/:$PATH"
|
||||||
tools/oss-fuzz.sh
|
tools/oss-fuzz.sh
|
||||||
./out/fuzz-unit-file -max_total_time=5
|
./out/fuzz-unit-file -max_total_time=5
|
||||||
git clean -dxff
|
git clean -dxff
|
||||||
|
|
||||||
git clone https://github.com/google/oss-fuzz /tmp/oss-fuzz
|
|
||||||
cd /tmp/oss-fuzz
|
|
||||||
sudo ./infra/helper.py pull_images
|
|
||||||
|
|
||||||
# docker doesn't like colons in filenames so let's create a directory
|
|
||||||
# whose name can be consumed by the -v option.
|
|
||||||
# https://github.com/google/oss-fuzz/issues/2428
|
|
||||||
t=$(mktemp -d)
|
|
||||||
sudo mount --bind "$REPO_ROOT" "$t"
|
|
||||||
|
|
||||||
# helper.py is wrapped in script to trick it into thinking it's "interactive"
|
|
||||||
# See https://github.com/systemd/systemd/pull/12542#issuecomment-491563572
|
|
||||||
sudo script -e -c "./infra/helper.py build_fuzzers --clean --sanitizer=memory systemd $t"
|
|
||||||
sudo script -e -c "./infra/helper.py check_build --sanitizer=memory -e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd"
|
|
||||||
|
|
Loading…
Reference in New Issue