mirror of
https://git.proxmox.com/git/systemd
synced 2025-10-25 16:32:56 +00:00
New upstream version 251.2
This commit is contained in:
parent
5249429fa0
commit
cfd0f7785c
@ -686,7 +686,7 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--luks-cipher=</option><replaceable>CIPHER</replaceable></term>
|
<term><option>--luks-cipher=</option><replaceable>CIPHER</replaceable></term>
|
||||||
<term><option>--luks-cipher-mode=</option><replaceable>MODE</replaceable></term>
|
<term><option>--luks-cipher-mode=</option><replaceable>MODE</replaceable></term>
|
||||||
<term><option>--luks-volume-key-size=</option><replaceable>BITS</replaceable></term>
|
<term><option>--luks-volume-key-size=</option><replaceable>BYTES</replaceable></term>
|
||||||
<term><option>--luks-pbkdf-type=</option><replaceable>TYPE</replaceable></term>
|
<term><option>--luks-pbkdf-type=</option><replaceable>TYPE</replaceable></term>
|
||||||
<term><option>--luks-pbkdf-hash-algorithm=</option><replaceable>ALGORITHM</replaceable></term>
|
<term><option>--luks-pbkdf-hash-algorithm=</option><replaceable>ALGORITHM</replaceable></term>
|
||||||
<term><option>--luks-pbkdf-time-cost=</option><replaceable>SECONDS</replaceable></term>
|
<term><option>--luks-pbkdf-time-cost=</option><replaceable>SECONDS</replaceable></term>
|
||||||
@ -696,7 +696,12 @@
|
|||||||
<listitem><para>Configures various cryptographic parameters for the LUKS2 storage mechanism. See
|
<listitem><para>Configures various cryptographic parameters for the LUKS2 storage mechanism. See
|
||||||
<citerefentry
|
<citerefentry
|
||||||
project='man-pages'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
project='man-pages'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
for details on the specific attributes.</para></listitem>
|
for details on the specific attributes.</para>
|
||||||
|
|
||||||
|
<para>Note that <command>homectl</command> uses bytes for key size, like
|
||||||
|
<filename>/proc/crypto</filename>, but <citerefentry
|
||||||
|
project='man-pages'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||||
|
uses bits.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|||||||
@ -121,7 +121,7 @@
|
|||||||
will be stored as an EFI variable in that case, overriding this option.
|
will be stored as an EFI variable in that case, overriding this option.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>If set to <literal>menu-hidden</literal> or <literal>0</literal> no menu
|
<para>If set to <literal>menu-hidden</literal> or <literal>0</literal> (the default) no menu
|
||||||
is shown and the default entry will be booted immediately. The menu can be shown
|
is shown and the default entry will be booted immediately. The menu can be shown
|
||||||
by pressing and holding a key before systemd-boot is launched. Setting this to
|
by pressing and holding a key before systemd-boot is launched. Setting this to
|
||||||
<literal>menu-force</literal> disables the timeout while always showing the menu.</para>
|
<literal>menu-force</literal> disables the timeout while always showing the menu.</para>
|
||||||
@ -211,7 +211,7 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>beep</term>
|
<term>beep</term>
|
||||||
|
|
||||||
<listitem><para>Beep n times when the n-th entry in the boot menu is shown (default disabled).
|
<listitem><para>Takes a boolean argument. If timeout enabled beep every second, otherwise beep n times when n-th entry in boot menu is selected (default disabled).
|
||||||
Currently, only x86 is supported, where it uses the PC speaker.</para></listitem>
|
Currently, only x86 is supported, where it uses the PC speaker.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|||||||
18
man/sd_bus_error-example.c
Normal file
18
man/sd_bus_error-example.c
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* SPDX-License-Identifier: CC0-1.0 */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sd-bus.h>
|
||||||
|
|
||||||
|
int writer_with_negative_errno_return(int fd, sd_bus_error *error) {
|
||||||
|
const char *message = "Hello, World!\n";
|
||||||
|
|
||||||
|
ssize_t n = write(fd, message, strlen(message));
|
||||||
|
if (n >= 0)
|
||||||
|
return n; /* On success, return the number of bytes written, possibly 0. */
|
||||||
|
|
||||||
|
/* On error, initialize the error structure, and also propagate the errno
|
||||||
|
* value that write(2) set for us. */
|
||||||
|
return sd_bus_error_set_errnof(error, errno, "Failed to write to fd %i: %m", fd);
|
||||||
|
}
|
||||||
@ -246,10 +246,15 @@
|
|||||||
values in <parameter>e</parameter>, if <parameter>e</parameter> has been set with an error value before.
|
values in <parameter>e</parameter>, if <parameter>e</parameter> has been set with an error value before.
|
||||||
Otherwise, it will return immediately. If the strings in <parameter>e</parameter> were set using
|
Otherwise, it will return immediately. If the strings in <parameter>e</parameter> were set using
|
||||||
<function>sd_bus_error_set_const()</function>, they will be shared. Otherwise, they will be
|
<function>sd_bus_error_set_const()</function>, they will be shared. Otherwise, they will be
|
||||||
copied. Returns a converted <varname>errno</varname>-like, negative error code or <constant>0</constant>.
|
copied. Before this call, <parameter>dst</parameter> must be unset, i.e. either freshly initialized with
|
||||||
Before this call, <parameter>dst</parameter> must be unset, i.e. either freshly initialized with
|
|
||||||
<constant>NULL</constant> or reset using <function>sd_bus_error_free()</function>.</para>
|
<constant>NULL</constant> or reset using <function>sd_bus_error_free()</function>.</para>
|
||||||
|
|
||||||
|
<para><function>sd_bus_error_copy()</function> generally returns <constant>0</constant> or a negative
|
||||||
|
<varname>errno</varname>-like value based on the input parameter <parameter>e</parameter>:
|
||||||
|
<constant>0</constant> if it was unset and a negative integer if it was set to some error, similarly to
|
||||||
|
<function>sd_bus_error_set()</function>. It may however also return an error generated internally, for
|
||||||
|
example <constant>-ENOMEM</constant> if a memory allocation fails.</para>
|
||||||
|
|
||||||
<para><function>sd_bus_error_move()</function> is similar to <function>sd_bus_error_copy()</function>,
|
<para><function>sd_bus_error_move()</function> is similar to <function>sd_bus_error_copy()</function>,
|
||||||
but will move any error information from <parameter>e</parameter> into <parameter>dst</parameter>,
|
but will move any error information from <parameter>e</parameter> into <parameter>dst</parameter>,
|
||||||
resetting the former. This function cannot fail, as no new memory is allocated. Note that if
|
resetting the former. This function cannot fail, as no new memory is allocated. Note that if
|
||||||
@ -286,6 +291,18 @@
|
|||||||
to <constant>NULL</constant>. The structure may be reused afterwards.</para>
|
to <constant>NULL</constant>. The structure may be reused afterwards.</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Reference ownership</title>
|
||||||
|
|
||||||
|
<para><structname>sd_bus_error</structname> is not reference-counted. Users should destroy resources held
|
||||||
|
by it by calling <function>sd_bus_error_free()</function>. Usually, error structures are allocated on the
|
||||||
|
stack or passed in as function parameters, but they may also be allocated dynamically, in which case it
|
||||||
|
is the duty of the caller to <citerefentry
|
||||||
|
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry> the memory
|
||||||
|
held by the structure itself after freeing its contents with
|
||||||
|
<function>sd_bus_error_free()</function>.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Return Value</title>
|
<title>Return Value</title>
|
||||||
|
|
||||||
@ -297,7 +314,8 @@
|
|||||||
<function>sd_bus_error_set_errnofv()</function>, return <constant>0</constant> when the specified error
|
<function>sd_bus_error_set_errnofv()</function>, return <constant>0</constant> when the specified error
|
||||||
value is <constant>0</constant>, and a negative errno-like value corresponding to the
|
value is <constant>0</constant>, and a negative errno-like value corresponding to the
|
||||||
<parameter>error</parameter> parameter otherwise. If an error occurs internally, one of the negative
|
<parameter>error</parameter> parameter otherwise. If an error occurs internally, one of the negative
|
||||||
error values listed below will be returned.</para>
|
error values listed below will be returned. This allows those functions to be conveniently used in a
|
||||||
|
<constant>return</constant> statement, see the example below.</para>
|
||||||
|
|
||||||
<para><function>sd_bus_error_get_errno()</function> returns
|
<para><function>sd_bus_error_get_errno()</function> returns
|
||||||
<constant>false</constant> when <parameter>e</parameter> is
|
<constant>false</constant> when <parameter>e</parameter> is
|
||||||
@ -305,7 +323,9 @@
|
|||||||
<parameter>e->name</parameter> otherwise.</para>
|
<parameter>e->name</parameter> otherwise.</para>
|
||||||
|
|
||||||
<para><function>sd_bus_error_copy()</function> and <function>sd_bus_error_move()</function> return a
|
<para><function>sd_bus_error_copy()</function> and <function>sd_bus_error_move()</function> return a
|
||||||
negative error value converted from the source error, and zero if the error has not been set.</para>
|
negative error value converted from the source error, and zero if the error has not been set. This
|
||||||
|
allows those functions to be conveniently used in a <constant>return</constant> statement, see the
|
||||||
|
example below.</para>
|
||||||
|
|
||||||
<para><function>sd_bus_error_is_set()</function> returns a
|
<para><function>sd_bus_error_is_set()</function> returns a
|
||||||
non-zero value when <parameter>e</parameter> and the
|
non-zero value when <parameter>e</parameter> and the
|
||||||
@ -316,32 +336,18 @@
|
|||||||
<function>sd_bus_error_has_names_sentinel()</function> return a non-zero value when <parameter>e</parameter> is
|
<function>sd_bus_error_has_names_sentinel()</function> return a non-zero value when <parameter>e</parameter> is
|
||||||
non-<constant>NULL</constant> and the <structfield>name</structfield> field is equal to one of the given
|
non-<constant>NULL</constant> and the <structfield>name</structfield> field is equal to one of the given
|
||||||
names, zero otherwise.</para>
|
names, zero otherwise.</para>
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1>
|
|
||||||
<title>Reference ownership</title>
|
|
||||||
<para><structname>sd_bus_error</structname> is not reference
|
|
||||||
counted. Users should destroy resources held by it by calling
|
|
||||||
<function>sd_bus_error_free()</function>. Usually, error structures
|
|
||||||
are allocated on the stack or passed in as function parameters,
|
|
||||||
but they may also be allocated dynamically, in which case it is
|
|
||||||
the duty of the caller to <citerefentry
|
|
||||||
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
|
||||||
the memory held by the structure itself after freeing its contents
|
|
||||||
with <function>sd_bus_error_free()</function>.</para>
|
|
||||||
|
|
||||||
<refsect2>
|
<refsect2>
|
||||||
<title>Errors</title>
|
<title>Errors</title>
|
||||||
|
|
||||||
<para>Returned errors may indicate the following problems:</para>
|
<para>Return value may indicate the following problems in the invocation of the function itself:</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><constant>-EINVAL</constant></term>
|
<term><constant>-EINVAL</constant></term>
|
||||||
|
|
||||||
<listitem><para>Error was already set in <structname>sd_bus_error</structname> structure when one
|
<listitem><para>Error was already set in the <structname>sd_bus_error</structname> structure when
|
||||||
the error-setting functions was called.</para></listitem>
|
one the error-setting functions was called.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -350,9 +356,29 @@
|
|||||||
<listitem><para>Memory allocation failed.</para></listitem>
|
<listitem><para>Memory allocation failed.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
|
<para>On success, <function>sd_bus_error_set()</function>, <function>sd_bus_error_setf()</function>,
|
||||||
|
<function>sd_bus_error_set_const()</function>, <function>sd_bus_error_set_errno()</function>,
|
||||||
|
<function>sd_bus_error_set_errnof()</function>, <function>sd_bus_error_set_errnofv()</function>,
|
||||||
|
<function>sd_bus_error_copy()</function>, and <function>sd_bus_error_move()</function> will return a
|
||||||
|
negative converted <varname>errno</varname>-style value, or <constant>0</constant> if the error
|
||||||
|
parameter is <constant>NULL</constant> or unset. D-Bus errors are converted to the integral
|
||||||
|
<varname>errno</varname>-style value, and the mapping mechanism is extensible, see the discussion
|
||||||
|
above. This effectively means that almost any negative <varname>errno</varname>-style value can be
|
||||||
|
returned.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Examples</title>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Using the negative return value to propagate an error</title>
|
||||||
|
|
||||||
|
<programlisting><xi:include href="sd_bus_error-example.c" parse="text" /></programlisting>
|
||||||
|
</example>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<xi:include href="libsystemd-pkgconfig.xml" />
|
<xi:include href="libsystemd-pkgconfig.xml" />
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<refnamediv>
|
<refnamediv>
|
||||||
<refname>shutdown</refname>
|
<refname>shutdown</refname>
|
||||||
<refpurpose>Halt, power-off or reboot the machine</refpurpose>
|
<refpurpose>Halt, power off or reboot the machine</refpurpose>
|
||||||
</refnamediv>
|
</refnamediv>
|
||||||
|
|
||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
@ -33,8 +33,7 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para><command>shutdown</command> may be used to halt, power-off
|
<para><command>shutdown</command> may be used to halt, power off, or reboot the machine.</para>
|
||||||
or reboot the machine.</para>
|
|
||||||
|
|
||||||
<para>The first argument may be a time string (which is usually
|
<para>The first argument may be a time string (which is usually
|
||||||
<literal>now</literal>). Optionally, this may be followed by a
|
<literal>now</literal>). Optionally, this may be followed by a
|
||||||
@ -81,47 +80,41 @@
|
|||||||
<term><option>-P</option></term>
|
<term><option>-P</option></term>
|
||||||
<term><option>--poweroff</option></term>
|
<term><option>--poweroff</option></term>
|
||||||
|
|
||||||
<listitem><para>Power-off the machine (the
|
<listitem><para>Power the machine off (the default).</para></listitem>
|
||||||
default).</para></listitem>
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-r</option></term>
|
<term><option>-r</option></term>
|
||||||
<term><option>--reboot</option></term>
|
<term><option>--reboot</option></term>
|
||||||
|
|
||||||
<listitem><para>Reboot the
|
<listitem><para>Reboot the machine.</para></listitem>
|
||||||
machine.</para></listitem>
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-h</option></term>
|
<term><option>-h</option></term>
|
||||||
|
|
||||||
<listitem><para>Equivalent to <option>--poweroff</option>,
|
<listitem><para>The same as <option>--poweroff</option>, but does not override the action to take if
|
||||||
unless <option>--halt</option> is specified.</para></listitem>
|
it is "halt". E.g. <command>shutdown --reboot -h</command> means "poweroff", but <command>shutdown
|
||||||
|
--halt -h</command> means "halt".</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-k</option></term>
|
<term><option>-k</option></term>
|
||||||
|
|
||||||
<listitem><para>Do not halt, power-off, reboot, just write
|
<listitem><para>Do not halt, power off, or reboot, but just write the wall message.</para></listitem>
|
||||||
wall message.</para></listitem>
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--no-wall</option></term>
|
<term><option>--no-wall</option></term>
|
||||||
|
|
||||||
<listitem><para>Do not send wall
|
<listitem><para>Do not send wall message before halt, power off, or reboot.</para></listitem>
|
||||||
message before
|
|
||||||
halt, power-off, reboot.</para></listitem>
|
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>-c</option></term>
|
<term><option>-c</option></term>
|
||||||
|
|
||||||
<listitem><para>Cancel a pending shutdown. This may be used
|
<listitem><para>Cancel a pending shutdown. This may be used to cancel the effect of an invocation of
|
||||||
to cancel the effect of an invocation of
|
<command>shutdown</command> with a time argument that is not <literal>+0</literal> or
|
||||||
<command>shutdown</command> with a time argument that is not
|
|
||||||
<literal>+0</literal> or
|
|
||||||
<literal>now</literal>.</para></listitem>
|
<literal>now</literal>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,8 @@
|
|||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>systemd-creds</command>
|
<command>systemd-creds</command>
|
||||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||||
|
<arg choice="plain">COMMAND</arg>
|
||||||
|
<arg choice="opt" rep="repeat">ARGS</arg>
|
||||||
</cmdsynopsis>
|
</cmdsynopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
|||||||
@ -26,10 +26,9 @@
|
|||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Description</title>
|
<title>Description</title>
|
||||||
|
|
||||||
<para>A unit configuration file whose name ends in
|
<para>A unit configuration file whose name ends in <literal>.automount</literal> encodes information
|
||||||
<literal>.automount</literal> encodes information about a file
|
about a file system automount point controlled and supervised by systemd. Automount units may be used to
|
||||||
system automount point controlled and supervised by
|
implement on-demand mounting as well as parallelized mounting of file systems.</para>
|
||||||
systemd.</para>
|
|
||||||
|
|
||||||
<para>This man page lists the configuration options specific to
|
<para>This man page lists the configuration options specific to
|
||||||
this unit type. See
|
this unit type. See
|
||||||
@ -55,9 +54,6 @@
|
|||||||
accesses <filename>/home/lennart</filename> the mount unit
|
accesses <filename>/home/lennart</filename> the mount unit
|
||||||
<filename>home-lennart.mount</filename> will be activated.</para>
|
<filename>home-lennart.mount</filename> will be activated.</para>
|
||||||
|
|
||||||
<para>Automount units may be used to implement on-demand mounting
|
|
||||||
as well as parallelized mounting of file systems.</para>
|
|
||||||
|
|
||||||
<para>Note that automount units are separate from the mount itself, so you
|
<para>Note that automount units are separate from the mount itself, so you
|
||||||
should not set <varname>After=</varname> or <varname>Requires=</varname>
|
should not set <varname>After=</varname> or <varname>Requires=</varname>
|
||||||
for mount dependencies here. For example, you should not set
|
for mount dependencies here. For example, you should not set
|
||||||
@ -65,8 +61,11 @@
|
|||||||
filesystems. Doing so may result in an ordering cycle.</para>
|
filesystems. Doing so may result in an ordering cycle.</para>
|
||||||
|
|
||||||
<para>Note that automount support on Linux is privileged, automount units are hence only available in the
|
<para>Note that automount support on Linux is privileged, automount units are hence only available in the
|
||||||
system service manager (and root's user service manager), but not in unprivileged user's service
|
system service manager (and root's user service manager), but not in unprivileged users' service
|
||||||
manager.</para>
|
managers.</para>
|
||||||
|
|
||||||
|
<para>Note that automount units should not be nested. (The establishment of the inner automount point
|
||||||
|
would unconditionally pin the outer mount point, defeating its purpose.)</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -78,12 +77,12 @@
|
|||||||
<para>The following dependencies are implicitly added:</para>
|
<para>The following dependencies are implicitly added:</para>
|
||||||
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem><para>If an automount unit is beneath another mount unit in the
|
<listitem><para>If an automount unit is beneath another mount unit in the file system hierarchy, a
|
||||||
file system hierarchy, both a requirement and an ordering
|
requirement and ordering dependencies are created to the on the unit higher in the hierarchy.
|
||||||
dependency between both units are created automatically.</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>An implicit <varname>Before=</varname> dependency is created
|
<listitem><para>An implicit <varname>Before=</varname> dependency is created between an automount
|
||||||
between an automount unit and the mount unit it activates.</para></listitem>
|
unit and the mount unit it activates.</para></listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
@ -161,6 +160,7 @@
|
|||||||
creating these directories. Takes an access mode in octal
|
creating these directories. Takes an access mode in octal
|
||||||
notation. Defaults to 0755.</para></listitem>
|
notation. Defaults to 0755.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>TimeoutIdleSec=</varname></term>
|
<term><varname>TimeoutIdleSec=</varname></term>
|
||||||
<listitem><para>Configures an idle timeout. Once the mount has been
|
<listitem><para>Configures an idle timeout. Once the mount has been
|
||||||
|
|||||||
@ -357,20 +357,29 @@ int cg_kill(
|
|||||||
Set *s,
|
Set *s,
|
||||||
cg_kill_log_func_t log_kill,
|
cg_kill_log_func_t log_kill,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
int r;
|
|
||||||
|
int r, ret;
|
||||||
|
|
||||||
r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.procs");
|
r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.procs");
|
||||||
if (r < 0 || sig != SIGKILL)
|
if (r < 0 || sig != SIGKILL)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
ret = r;
|
||||||
|
|
||||||
/* Only in case of killing with SIGKILL and when using cgroupsv2, kill remaining threads manually as
|
/* Only in case of killing with SIGKILL and when using cgroupsv2, kill remaining threads manually as
|
||||||
a workaround for kernel bug. It was fixed in 5.2-rc5 (c03cd7738a83), backported to 4.19.66
|
a workaround for kernel bug. It was fixed in 5.2-rc5 (c03cd7738a83), backported to 4.19.66
|
||||||
(4340d175b898) and 4.14.138 (feb6b123b7dd). */
|
(4340d175b898) and 4.14.138 (feb6b123b7dd). */
|
||||||
r = cg_unified_controller(controller);
|
r = cg_unified_controller(controller);
|
||||||
if (r <= 0)
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads");
|
||||||
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.threads");
|
return r > 0 || ret > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cg_kill_kernel_sigkill(const char *controller, const char *path) {
|
int cg_kill_kernel_sigkill(const char *controller, const char *path) {
|
||||||
|
|||||||
@ -543,7 +543,7 @@ int bpf_firewall_compile(Unit *u) {
|
|||||||
return supported;
|
return supported;
|
||||||
if (supported == BPF_FIREWALL_UNSUPPORTED)
|
if (supported == BPF_FIREWALL_UNSUPPORTED)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"BPF firewalling not supported on this manager, proceeding without.");
|
"bpf-firewall: BPF firewalling not supported, proceeding without.");
|
||||||
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE)
|
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE)
|
||||||
/* If BPF_F_ALLOW_MULTI is not supported we don't support any BPF magic on inner nodes (i.e. on slice
|
/* If BPF_F_ALLOW_MULTI is not supported we don't support any BPF magic on inner nodes (i.e. on slice
|
||||||
* units), since that would mean leaf nodes couldn't do any BPF anymore at all. Under the assumption
|
* units), since that would mean leaf nodes couldn't do any BPF anymore at all. Under the assumption
|
||||||
@ -551,7 +551,7 @@ int bpf_firewall_compile(Unit *u) {
|
|||||||
* consistent with old systemd behaviour from before v238, where BPF wasn't supported in inner nodes at
|
* consistent with old systemd behaviour from before v238, where BPF wasn't supported in inner nodes at
|
||||||
* all, either. */
|
* all, either. */
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units.");
|
"bpf-firewall: BPF_F_ALLOW_MULTI is not supported, not doing BPF firewall on slice units.");
|
||||||
|
|
||||||
/* If BPF_F_ALLOW_MULTI flag is supported program name is also supported (both were added to v4.15
|
/* If BPF_F_ALLOW_MULTI flag is supported program name is also supported (both were added to v4.15
|
||||||
* kernel). */
|
* kernel). */
|
||||||
@ -582,24 +582,24 @@ int bpf_firewall_compile(Unit *u) {
|
|||||||
|
|
||||||
r = bpf_firewall_prepare_access_maps(u, ACCESS_ALLOWED, &u->ipv4_allow_map_fd, &u->ipv6_allow_map_fd, &ip_allow_any);
|
r = bpf_firewall_prepare_access_maps(u, ACCESS_ALLOWED, &u->ipv4_allow_map_fd, &u->ipv6_allow_map_fd, &ip_allow_any);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Preparation of eBPF allow maps failed: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Preparation of BPF allow maps failed: %m");
|
||||||
|
|
||||||
r = bpf_firewall_prepare_access_maps(u, ACCESS_DENIED, &u->ipv4_deny_map_fd, &u->ipv6_deny_map_fd, &ip_deny_any);
|
r = bpf_firewall_prepare_access_maps(u, ACCESS_DENIED, &u->ipv4_deny_map_fd, &u->ipv6_deny_map_fd, &ip_deny_any);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Preparation of eBPF deny maps failed: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Preparation of BPF deny maps failed: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = bpf_firewall_prepare_accounting_maps(u, cc->ip_accounting, &u->ip_accounting_ingress_map_fd, &u->ip_accounting_egress_map_fd);
|
r = bpf_firewall_prepare_accounting_maps(u, cc->ip_accounting, &u->ip_accounting_ingress_map_fd, &u->ip_accounting_egress_map_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Preparation of eBPF accounting maps failed: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Preparation of BPF accounting maps failed: %m");
|
||||||
|
|
||||||
r = bpf_firewall_compile_bpf(u, ingress_name, true, &u->ip_bpf_ingress, ip_allow_any, ip_deny_any);
|
r = bpf_firewall_compile_bpf(u, ingress_name, true, &u->ip_bpf_ingress, ip_allow_any, ip_deny_any);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Compilation for ingress BPF program failed: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Compilation of ingress BPF program failed: %m");
|
||||||
|
|
||||||
r = bpf_firewall_compile_bpf(u, egress_name, false, &u->ip_bpf_egress, ip_allow_any, ip_deny_any);
|
r = bpf_firewall_compile_bpf(u, egress_name, false, &u->ip_bpf_egress, ip_allow_any, ip_deny_any);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Compilation for egress BPF program failed: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Compilation of egress BPF program failed: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -613,15 +613,15 @@ static int load_bpf_progs_from_fs_to_set(Unit *u, char **filter_paths, Set **set
|
|||||||
|
|
||||||
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &prog);
|
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &prog);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Can't allocate CGROUP SKB BPF program: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Allocation of SKB BPF program failed: %m");
|
||||||
|
|
||||||
r = bpf_program_load_from_bpf_fs(prog, *bpf_fs_path);
|
r = bpf_program_load_from_bpf_fs(prog, *bpf_fs_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Loading of ingress BPF program %s failed: %m", *bpf_fs_path);
|
return log_unit_error_errno(u, r, "bpf-firewall: Loading of ingress BPF program %s failed: %m", *bpf_fs_path);
|
||||||
|
|
||||||
r = set_ensure_consume(set, &bpf_program_hash_ops, TAKE_PTR(prog));
|
r = set_ensure_consume(set, &bpf_program_hash_ops, TAKE_PTR(prog));
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Can't add program to BPF program set: %m");
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -645,7 +645,8 @@ int bpf_firewall_load_custom(Unit *u) {
|
|||||||
return supported;
|
return supported;
|
||||||
|
|
||||||
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI)
|
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs.");
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"bpf-firewall: BPF_F_ALLOW_MULTI not supported, cannot attach custom BPF programs.");
|
||||||
|
|
||||||
r = load_bpf_progs_from_fs_to_set(u, cc->ip_filters_ingress, &u->ip_bpf_custom_ingress);
|
r = load_bpf_progs_from_fs_to_set(u, cc->ip_filters_ingress, &u->ip_bpf_custom_ingress);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -671,7 +672,7 @@ static int attach_custom_bpf_progs(Unit *u, const char *path, int attach_type, S
|
|||||||
SET_FOREACH_MOVE(prog, *set_installed, *set) {
|
SET_FOREACH_MOVE(prog, *set_installed, *set) {
|
||||||
r = bpf_program_cgroup_attach(prog, attach_type, path, BPF_F_ALLOW_MULTI);
|
r = bpf_program_cgroup_attach(prog, attach_type, path, BPF_F_ALLOW_MULTI);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Attaching custom egress BPF program to cgroup %s failed: %m", path);
|
return log_unit_error_errno(u, r, "bpf-firewall: Attaching custom egress BPF program to cgroup %s failed: %m", path);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -697,16 +698,19 @@ int bpf_firewall_install(Unit *u) {
|
|||||||
if (supported < 0)
|
if (supported < 0)
|
||||||
return supported;
|
return supported;
|
||||||
if (supported == BPF_FIREWALL_UNSUPPORTED)
|
if (supported == BPF_FIREWALL_UNSUPPORTED)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF firewalling not supported on this manager, proceeding without.");
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"bpf-firewall: BPF firewalling not supported, proceeding without.");
|
||||||
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE)
|
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE)
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units.");
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"bpf-firewall: BPF_F_ALLOW_MULTI not supported, not doing BPF firewall on slice units.");
|
||||||
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI &&
|
if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI &&
|
||||||
(!set_isempty(u->ip_bpf_custom_ingress) || !set_isempty(u->ip_bpf_custom_egress)))
|
(!set_isempty(u->ip_bpf_custom_ingress) || !set_isempty(u->ip_bpf_custom_egress)))
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs.");
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"bpf-firewall: BPF_F_ALLOW_MULTI not supported, cannot attach custom BPF programs.");
|
||||||
|
|
||||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &path);
|
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to determine cgroup path: %m");
|
return log_unit_error_errno(u, r, "bpf-firewall: Failed to determine cgroup path: %m");
|
||||||
|
|
||||||
flags = supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI ? BPF_F_ALLOW_MULTI : 0;
|
flags = supported == BPF_FIREWALL_SUPPORTED_WITH_MULTI ? BPF_F_ALLOW_MULTI : 0;
|
||||||
|
|
||||||
@ -728,7 +732,8 @@ int bpf_firewall_install(Unit *u) {
|
|||||||
if (u->ip_bpf_egress) {
|
if (u->ip_bpf_egress) {
|
||||||
r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, flags);
|
r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, flags);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Attaching egress BPF program to cgroup %s failed: %m", path);
|
return log_unit_error_errno(u, r,
|
||||||
|
"bpf-firewall: Attaching egress BPF program to cgroup %s failed: %m", path);
|
||||||
|
|
||||||
/* Remember that this BPF program is installed now. */
|
/* Remember that this BPF program is installed now. */
|
||||||
u->ip_bpf_egress_installed = TAKE_PTR(u->ip_bpf_egress);
|
u->ip_bpf_egress_installed = TAKE_PTR(u->ip_bpf_egress);
|
||||||
@ -737,7 +742,8 @@ int bpf_firewall_install(Unit *u) {
|
|||||||
if (u->ip_bpf_ingress) {
|
if (u->ip_bpf_ingress) {
|
||||||
r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, flags);
|
r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, flags);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Attaching ingress BPF program to cgroup %s failed: %m", path);
|
return log_unit_error_errno(u, r,
|
||||||
|
"bpf-firewall: Attaching ingress BPF program to cgroup %s failed: %m", path);
|
||||||
|
|
||||||
u->ip_bpf_ingress_installed = TAKE_PTR(u->ip_bpf_ingress);
|
u->ip_bpf_ingress_installed = TAKE_PTR(u->ip_bpf_ingress);
|
||||||
}
|
}
|
||||||
@ -824,11 +830,11 @@ int bpf_firewall_supported(void) {
|
|||||||
|
|
||||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Can't determine whether the unified hierarchy is used: %m");
|
return log_error_errno(r, "bpf-firewall: Can't determine whether the unified hierarchy is used: %m");
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
|
log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN),
|
||||||
"Not running with unified cgroups, BPF firewalling is not supported.");
|
"bpf-firewall: Not running with unified cgroup hierarchy, BPF firewalling is not supported.");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,21 +842,21 @@ int bpf_firewall_supported(void) {
|
|||||||
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &program);
|
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &program);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(r, "Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m");
|
log_debug_errno(r, "bpf-firewall: Can't allocate CGROUP SKB BPF program, BPF firewalling is not supported: %m");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = bpf_program_add_instructions(program, trivial, ELEMENTSOF(trivial));
|
r = bpf_program_add_instructions(program, trivial, ELEMENTSOF(trivial));
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(r, "Can't add trivial instructions to CGROUP SKB BPF program, BPF firewalling is not supported: %m");
|
log_debug_errno(r, "bpf-firewall: Can't add trivial instructions to CGROUP SKB BPF program, BPF firewalling is not supported: %m");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = bpf_program_load_kernel(program, NULL, 0);
|
r = bpf_program_load_kernel(program, NULL, 0);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(r, "Can't load kernel CGROUP SKB BPF program, BPF firewalling is not supported: %m");
|
log_debug_errno(r, "bpf-firewall: Can't load kernel CGROUP SKB BPF program, BPF firewalling is not supported: %m");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,7 +880,7 @@ int bpf_firewall_supported(void) {
|
|||||||
if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
|
if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
|
||||||
if (errno != EBADF) {
|
if (errno != EBADF) {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(errno, "Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m");
|
log_debug_errno(errno, "bpf-firewall: Didn't get EBADF from BPF_PROG_DETACH, BPF firewalling is not supported: %m");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,7 +888,7 @@ int bpf_firewall_supported(void) {
|
|||||||
} else {
|
} else {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(SYNTHETIC_ERRNO(EBADE),
|
log_debug_errno(SYNTHETIC_ERRNO(EBADE),
|
||||||
"Wut? Kernel accepted our invalid BPF_PROG_DETACH call? "
|
"bpf-firewall: Wut? Kernel accepted our invalid BPF_PROG_DETACH call? "
|
||||||
"Something is weird, assuming BPF firewalling is broken and hence not supported.");
|
"Something is weird, assuming BPF firewalling is broken and hence not supported.");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
@ -902,20 +908,20 @@ int bpf_firewall_supported(void) {
|
|||||||
|
|
||||||
if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
|
if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
|
||||||
if (errno == EBADF) {
|
if (errno == EBADF) {
|
||||||
log_debug_errno(errno, "Got EBADF when using BPF_F_ALLOW_MULTI, which indicates it is supported. Yay!");
|
log_debug_errno(errno, "bpf-firewall: Got EBADF when using BPF_F_ALLOW_MULTI, which indicates it is supported. Yay!");
|
||||||
return supported = BPF_FIREWALL_SUPPORTED_WITH_MULTI;
|
return supported = BPF_FIREWALL_SUPPORTED_WITH_MULTI;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errno == EINVAL)
|
if (errno == EINVAL)
|
||||||
log_debug_errno(errno, "Got EINVAL error when using BPF_F_ALLOW_MULTI, which indicates it's not supported.");
|
log_debug_errno(errno, "bpf-firewall: Got EINVAL error when using BPF_F_ALLOW_MULTI, which indicates it's not supported.");
|
||||||
else
|
else
|
||||||
log_debug_errno(errno, "Got unexpected error when using BPF_F_ALLOW_MULTI, assuming it's not supported: %m");
|
log_debug_errno(errno, "bpf-firewall: Got unexpected error when using BPF_F_ALLOW_MULTI, assuming it's not supported: %m");
|
||||||
|
|
||||||
return supported = BPF_FIREWALL_SUPPORTED;
|
return supported = BPF_FIREWALL_SUPPORTED;
|
||||||
} else {
|
} else {
|
||||||
bpf_firewall_unsupported_reason =
|
bpf_firewall_unsupported_reason =
|
||||||
log_debug_errno(SYNTHETIC_ERRNO(EBADE),
|
log_debug_errno(SYNTHETIC_ERRNO(EBADE),
|
||||||
"Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? "
|
"bpf-firewall: Wut? Kernel accepted our invalid BPF_PROG_ATTACH+BPF_F_ALLOW_MULTI call? "
|
||||||
"Something is weird, assuming BPF firewalling is broken and hence not supported.");
|
"Something is weird, assuming BPF firewalling is broken and hence not supported.");
|
||||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,7 +63,7 @@ static int attach_programs(Unit *u, const char *path, Hashmap* foreign_by_key, u
|
|||||||
HASHMAP_FOREACH_KEY(prog, key, foreign_by_key) {
|
HASHMAP_FOREACH_KEY(prog, key, foreign_by_key) {
|
||||||
r = bpf_program_cgroup_attach(prog, key->attach_type, path, attach_flags);
|
r = bpf_program_cgroup_attach(prog, key->attach_type, path, attach_flags);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Attaching foreign BPF program to cgroup %s failed: %m", path);
|
return log_unit_error_errno(u, r, "bpf-foreign: Attaching foreign BPF program to cgroup %s failed: %m", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -89,31 +89,31 @@ static int bpf_foreign_prepare(
|
|||||||
r = path_is_fs_type(bpffs_path, BPF_FS_MAGIC);
|
r = path_is_fs_type(bpffs_path, BPF_FS_MAGIC);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r,
|
return log_unit_error_errno(u, r,
|
||||||
"Failed to determine filesystem type of %s: %m", bpffs_path);
|
"bpf-foreign: Failed to determine filesystem type of %s: %m", bpffs_path);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Path in BPF filesystem is expected.");
|
"bpf-foreign: Path in BPF filesystem is expected.");
|
||||||
|
|
||||||
r = bpf_program_new_from_bpffs_path(bpffs_path, &prog);
|
r = bpf_program_new_from_bpffs_path(bpffs_path, &prog);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to create foreign BPFProgram: %m");
|
return log_unit_error_errno(u, r, "bpf-foreign: Failed to create foreign BPF program: %m");
|
||||||
|
|
||||||
r = bpf_program_get_id_by_fd(prog->kernel_fd, &prog_id);
|
r = bpf_program_get_id_by_fd(prog->kernel_fd, &prog_id);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to get BPF program id by fd: %m");
|
return log_unit_error_errno(u, r, "bpf-foreign: Failed to get BPF program id from fd: %m");
|
||||||
|
|
||||||
r = bpf_foreign_key_new(prog_id, attach_type, &key);
|
r = bpf_foreign_key_new(prog_id, attach_type, &key);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r,
|
return log_unit_error_errno(u, r,
|
||||||
"Failed to create foreign BPF program key from path '%s': %m", bpffs_path);
|
"bpf-foreign: Failed to create foreign BPF program key from path '%s': %m", bpffs_path);
|
||||||
|
|
||||||
r = hashmap_ensure_put(&u->bpf_foreign_by_key, &bpf_foreign_by_key_hash_ops, key, prog);
|
r = hashmap_ensure_put(&u->bpf_foreign_by_key, &bpf_foreign_by_key_hash_ops, key, prog);
|
||||||
if (r == -EEXIST) {
|
if (r == -EEXIST) {
|
||||||
log_unit_warning_errno(u, r, "Foreign BPF program already exists, ignoring: %m");
|
log_unit_warning_errno(u, r, "bpf-foreign: Foreign BPF program already exists, ignoring: %m");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to put foreign BPFProgram into map: %m");
|
return log_unit_error_errno(u, r, "bpf-foreign: Failed to put foreign BPF program into map: %m");
|
||||||
|
|
||||||
TAKE_PTR(key);
|
TAKE_PTR(key);
|
||||||
TAKE_PTR(prog);
|
TAKE_PTR(prog);
|
||||||
@ -134,17 +134,17 @@ int bpf_foreign_install(Unit *u) {
|
|||||||
|
|
||||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to get cgroup path: %m");
|
return log_unit_error_errno(u, r, "bpf-foreign: Failed to get cgroup path: %m");
|
||||||
|
|
||||||
LIST_FOREACH(programs, p, cc->bpf_foreign_programs) {
|
LIST_FOREACH(programs, p, cc->bpf_foreign_programs) {
|
||||||
r = bpf_foreign_prepare(u, p->attach_type, p->bpffs_path);
|
r = bpf_foreign_prepare(u, p->attach_type, p->bpffs_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to prepare foreign BPF hashmap: %m");
|
return log_unit_error_errno(u, r, "bpf-foreign: Failed to prepare foreign BPF hashmap: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = attach_programs(u, cgroup_path, u->bpf_foreign_by_key, BPF_F_ALLOW_MULTI);
|
r = attach_programs(u, cgroup_path, u->bpf_foreign_by_key, BPF_F_ALLOW_MULTI);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to install foreign BPF programs: %m");
|
return log_unit_error_errno(u, r, "bpf-foreign: Failed to install foreign BPF programs: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
/* libbpf, clang and llc compile time dependencies are satisfied */
|
/* libbpf, clang and llc compile time dependencies are satisfied */
|
||||||
#include "bpf-dlopen.h"
|
#include "bpf-dlopen.h"
|
||||||
#include "bpf-link.h"
|
#include "bpf-link.h"
|
||||||
|
#include "bpf-util.h"
|
||||||
#include "bpf/restrict_fs/restrict-fs-skel.h"
|
#include "bpf/restrict_fs/restrict-fs-skel.h"
|
||||||
|
|
||||||
#define CGROUP_HASH_SIZE_MAX 2048
|
#define CGROUP_HASH_SIZE_MAX 2048
|
||||||
@ -61,29 +62,29 @@ static int prepare_restrict_fs_bpf(struct restrict_fs_bpf **ret_obj) {
|
|||||||
|
|
||||||
obj = restrict_fs_bpf__open();
|
obj = restrict_fs_bpf__open();
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return log_error_errno(errno, "Failed to open BPF object: %m");
|
return log_error_errno(errno, "bpf-lsm: Failed to open BPF object: %m");
|
||||||
|
|
||||||
/* TODO Maybe choose a number based on runtime information? */
|
/* TODO Maybe choose a number based on runtime information? */
|
||||||
r = sym_bpf_map__resize(obj->maps.cgroup_hash, CGROUP_HASH_SIZE_MAX);
|
r = sym_bpf_map__resize(obj->maps.cgroup_hash, CGROUP_HASH_SIZE_MAX);
|
||||||
assert(r <= 0);
|
assert(r <= 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to resize BPF map '%s': %m",
|
return log_error_errno(r, "bpf-lsm: Failed to resize BPF map '%s': %m",
|
||||||
sym_bpf_map__name(obj->maps.cgroup_hash));
|
sym_bpf_map__name(obj->maps.cgroup_hash));
|
||||||
|
|
||||||
/* Dummy map to satisfy the verifier */
|
/* Dummy map to satisfy the verifier */
|
||||||
inner_map_fd = sym_bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint32_t), 128, 0);
|
inner_map_fd = sym_bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint32_t), 128, 0);
|
||||||
if (inner_map_fd < 0)
|
if (inner_map_fd < 0)
|
||||||
return log_error_errno(errno, "Failed to create BPF map: %m");
|
return log_error_errno(errno, "bpf-lsm: Failed to create BPF map: %m");
|
||||||
|
|
||||||
r = sym_bpf_map__set_inner_map_fd(obj->maps.cgroup_hash, inner_map_fd);
|
r = sym_bpf_map__set_inner_map_fd(obj->maps.cgroup_hash, inner_map_fd);
|
||||||
assert(r <= 0);
|
assert(r <= 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to set inner map fd: %m");
|
return log_error_errno(r, "bpf-lsm: Failed to set inner map fd: %m");
|
||||||
|
|
||||||
r = restrict_fs_bpf__load(obj);
|
r = restrict_fs_bpf__load(obj);
|
||||||
assert(r <= 0);
|
assert(r <= 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to load BPF object");
|
return log_error_errno(r, "bpf-lsm: Failed to load BPF object: %m");
|
||||||
|
|
||||||
*ret_obj = TAKE_PTR(obj);
|
*ret_obj = TAKE_PTR(obj);
|
||||||
|
|
||||||
@ -103,7 +104,7 @@ static int mac_bpf_use(void) {
|
|||||||
r = read_one_line_file("/sys/kernel/security/lsm", &lsm_list);
|
r = read_one_line_file("/sys/kernel/security/lsm", &lsm_list);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (r != -ENOENT)
|
if (r != -ENOENT)
|
||||||
log_notice_errno(r, "Failed to read /sys/kernel/security/lsm, assuming bpf is unavailable: %m");
|
log_notice_errno(r, "bpf-lsm: Failed to read /sys/kernel/security/lsm, assuming bpf is unavailable: %m");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ static int mac_bpf_use(void) {
|
|||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_notice_errno(r, "Failed to parse /sys/kernel/security/lsm, assuming bpf is unavailable: %m");
|
log_notice_errno(r, "bpf-lsm: Failed to parse /sys/kernel/security/lsm, assuming bpf is unavailable: %m");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,33 +136,18 @@ bool lsm_bpf_supported(bool initialize) {
|
|||||||
if (!initialize)
|
if (!initialize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
r = dlopen_bpf();
|
if (!cgroup_bpf_supported())
|
||||||
if (r < 0) {
|
|
||||||
log_info_errno(r, "Failed to open libbpf, LSM BPF is not supported: %m");
|
|
||||||
return (supported = false);
|
return (supported = false);
|
||||||
}
|
|
||||||
|
|
||||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
|
||||||
if (r < 0) {
|
|
||||||
log_warning_errno(r, "Can't determine whether the unified hierarchy is used: %m");
|
|
||||||
return (supported = false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r == 0) {
|
|
||||||
log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
|
||||||
"Not running with unified cgroup hierarchy, LSM BPF is not supported");
|
|
||||||
return (supported = false);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = mac_bpf_use();
|
r = mac_bpf_use();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_warning_errno(r, "Can't determine whether the BPF LSM module is used: %m");
|
log_warning_errno(r, "bpf-lsm: Can't determine whether the BPF LSM module is used: %m");
|
||||||
return (supported = false);
|
return (supported = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"BPF LSM hook not enabled in the kernel, LSM BPF not supported");
|
"bpf-lsm: BPF LSM hook not enabled in the kernel, BPF LSM not supported");
|
||||||
return (supported = false);
|
return (supported = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +157,7 @@ bool lsm_bpf_supported(bool initialize) {
|
|||||||
|
|
||||||
if (!bpf_can_link_lsm_program(obj->progs.restrict_filesystems)) {
|
if (!bpf_can_link_lsm_program(obj->progs.restrict_filesystems)) {
|
||||||
log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"Failed to link BPF program. Assuming BPF is not available");
|
"bpf-lsm: Failed to link program; assuming BPF LSM is not available");
|
||||||
return (supported = false);
|
return (supported = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,10 +178,10 @@ int lsm_bpf_setup(Manager *m) {
|
|||||||
link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems);
|
link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems);
|
||||||
r = sym_libbpf_get_error(link);
|
r = sym_libbpf_get_error(link);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_error_errno(r, "Failed to link '%s' LSM BPF program: %m",
|
return log_error_errno(r, "bpf-lsm: Failed to link '%s' LSM BPF program: %m",
|
||||||
sym_bpf_program__name(obj->progs.restrict_filesystems));
|
sym_bpf_program__name(obj->progs.restrict_filesystems));
|
||||||
|
|
||||||
log_info("LSM BPF program attached");
|
log_info("bpf-lsm: LSM BPF program attached");
|
||||||
|
|
||||||
obj->links.restrict_filesystems = TAKE_PTR(link);
|
obj->links.restrict_filesystems = TAKE_PTR(link);
|
||||||
m->restrict_fs = TAKE_PTR(obj);
|
m->restrict_fs = TAKE_PTR(obj);
|
||||||
@ -214,7 +200,7 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, bool allo
|
|||||||
|
|
||||||
if (!u->manager->restrict_fs)
|
if (!u->manager->restrict_fs)
|
||||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Restrict filesystems BPF object is not set, BPF LSM setup has failed?");
|
"bpf-lsm: BPF LSM object is not installed, has setup failed?");
|
||||||
|
|
||||||
int inner_map_fd = sym_bpf_create_map(
|
int inner_map_fd = sym_bpf_create_map(
|
||||||
BPF_MAP_TYPE_HASH,
|
BPF_MAP_TYPE_HASH,
|
||||||
@ -223,39 +209,39 @@ int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, bool allo
|
|||||||
128, /* Should be enough for all filesystem types */
|
128, /* Should be enough for all filesystem types */
|
||||||
0);
|
0);
|
||||||
if (inner_map_fd < 0)
|
if (inner_map_fd < 0)
|
||||||
return log_unit_error_errno(u, errno, "Failed to create inner LSM map: %m");
|
return log_unit_error_errno(u, errno, "bpf-lsm: Failed to create inner BPF map: %m");
|
||||||
|
|
||||||
int outer_map_fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash);
|
int outer_map_fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash);
|
||||||
if (outer_map_fd < 0)
|
if (outer_map_fd < 0)
|
||||||
return log_unit_error_errno(u, errno, "Failed to get BPF map fd: %m");
|
return log_unit_error_errno(u, errno, "bpf-lsm: Failed to get BPF map fd: %m");
|
||||||
|
|
||||||
if (sym_bpf_map_update_elem(outer_map_fd, &u->cgroup_id, &inner_map_fd, BPF_ANY) != 0)
|
if (sym_bpf_map_update_elem(outer_map_fd, &u->cgroup_id, &inner_map_fd, BPF_ANY) != 0)
|
||||||
return log_unit_error_errno(u, errno, "Error populating LSM BPF map: %m");
|
return log_unit_error_errno(u, errno, "bpf-lsm: Error populating BPF map: %m");
|
||||||
|
|
||||||
uint32_t allow = allow_list;
|
uint32_t allow = allow_list;
|
||||||
|
|
||||||
/* Use key 0 to store whether this is an allow list or a deny list */
|
/* Use key 0 to store whether this is an allow list or a deny list */
|
||||||
if (sym_bpf_map_update_elem(inner_map_fd, &zero, &allow, BPF_ANY) != 0)
|
if (sym_bpf_map_update_elem(inner_map_fd, &zero, &allow, BPF_ANY) != 0)
|
||||||
return log_unit_error_errno(u, errno, "Error initializing BPF map: %m");
|
return log_unit_error_errno(u, errno, "bpf-lsm: Error initializing map: %m");
|
||||||
|
|
||||||
SET_FOREACH(fs, filesystems) {
|
SET_FOREACH(fs, filesystems) {
|
||||||
r = fs_type_from_string(fs, &magic);
|
r = fs_type_from_string(fs, &magic);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_unit_warning(u, "Invalid filesystem name '%s', ignoring.", fs);
|
log_unit_warning(u, "bpf-lsm: Invalid filesystem name '%s', ignoring.", fs);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_unit_debug(u, "Restricting filesystem access to '%s'", fs);
|
log_unit_debug(u, "bpf-lsm: Restricting filesystem access to '%s'", fs);
|
||||||
|
|
||||||
for (int i = 0; i < FILESYSTEM_MAGIC_MAX; i++) {
|
for (int i = 0; i < FILESYSTEM_MAGIC_MAX; i++) {
|
||||||
if (magic[i] == 0)
|
if (magic[i] == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (sym_bpf_map_update_elem(inner_map_fd, &magic[i], &dummy_value, BPF_ANY) != 0) {
|
if (sym_bpf_map_update_elem(inner_map_fd, &magic[i], &dummy_value, BPF_ANY) != 0) {
|
||||||
r = log_unit_error_errno(u, errno, "Failed to update BPF map: %m");
|
r = log_unit_error_errno(u, errno, "bpf-lsm: Failed to update BPF map: %m");
|
||||||
|
|
||||||
if (sym_bpf_map_delete_elem(outer_map_fd, &u->cgroup_id) != 0)
|
if (sym_bpf_map_delete_elem(outer_map_fd, &u->cgroup_id) != 0)
|
||||||
log_unit_debug_errno(u, errno, "Failed to delete cgroup entry from LSM BPF map: %m");
|
log_unit_debug_errno(u, errno, "bpf-lsm: Failed to delete cgroup entry from BPF map: %m");
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -278,10 +264,10 @@ int lsm_bpf_cleanup(const Unit *u) {
|
|||||||
|
|
||||||
int fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash);
|
int fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return log_unit_error_errno(u, errno, "Failed to get BPF map fd: %m");
|
return log_unit_error_errno(u, errno, "bpf-lsm: Failed to get BPF map fd: %m");
|
||||||
|
|
||||||
if (sym_bpf_map_delete_elem(fd, &u->cgroup_id) != 0)
|
if (sym_bpf_map_delete_elem(fd, &u->cgroup_id) != 0)
|
||||||
return log_unit_debug_errno(u, errno, "Failed to delete cgroup entry from LSM BPF map: %m");
|
return log_unit_debug_errno(u, errno, "bpf-lsm: Failed to delete cgroup entry from LSM BPF map: %m");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -305,11 +291,11 @@ bool lsm_bpf_supported(bool initialize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lsm_bpf_setup(Manager *m) {
|
int lsm_bpf_setup(Manager *m) {
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set up LSM BPF: %m");
|
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to set up LSM BPF: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, const bool allow_list) {
|
int lsm_bpf_unit_restrict_filesystems(Unit *u, const Set *filesystems, const bool allow_list) {
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to restrict filesystems using LSM BPF: %m");
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "bpf-lsm: Failed to restrict filesystems using LSM BPF: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
int lsm_bpf_cleanup(const Unit *u) {
|
int lsm_bpf_cleanup(const Unit *u) {
|
||||||
@ -344,7 +330,7 @@ int lsm_bpf_parse_filesystem(
|
|||||||
set = filesystem_set_find(name);
|
set = filesystem_set_find(name);
|
||||||
if (!set) {
|
if (!set) {
|
||||||
log_syntax(unit, flags & FILESYSTEM_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0,
|
log_syntax(unit, flags & FILESYSTEM_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0,
|
||||||
"Unknown filesystem group, ignoring: %s", name);
|
"bpf-lsm: Unknown filesystem group, ignoring: %s", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,9 @@
|
|||||||
/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
|
/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
|
||||||
#include "bpf-dlopen.h"
|
#include "bpf-dlopen.h"
|
||||||
#include "bpf-link.h"
|
#include "bpf-link.h"
|
||||||
#include "bpf/socket_bind/socket-bind-skel.h"
|
#include "bpf-util.h"
|
||||||
#include "bpf/socket_bind/socket-bind-api.bpf.h"
|
#include "bpf/socket_bind/socket-bind-api.bpf.h"
|
||||||
|
#include "bpf/socket_bind/socket-bind-skel.h"
|
||||||
|
|
||||||
static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) {
|
static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) {
|
||||||
/* socket_bind_bpf__destroy handles object == NULL case */
|
/* socket_bind_bpf__destroy handles object == NULL case */
|
||||||
@ -68,27 +69,27 @@ static int prepare_socket_bind_bpf(
|
|||||||
|
|
||||||
if (allow_count > SOCKET_BIND_MAX_RULES)
|
if (allow_count > SOCKET_BIND_MAX_RULES)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
|
"bpf-socket-bind: Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
|
||||||
|
|
||||||
if (deny_count > SOCKET_BIND_MAX_RULES)
|
if (deny_count > SOCKET_BIND_MAX_RULES)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
|
"bpf-socket-bind: Maximum number of socket bind rules=%u is exceeded", SOCKET_BIND_MAX_RULES);
|
||||||
|
|
||||||
obj = socket_bind_bpf__open();
|
obj = socket_bind_bpf__open();
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "Failed to open BPF object: %m");
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "bpf-socket-bind: Failed to open BPF object: %m");
|
||||||
|
|
||||||
if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
|
if (sym_bpf_map__resize(obj->maps.sd_bind_allow, MAX(allow_count, 1u)) != 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
|
||||||
"Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow));
|
"bpf-socket-bind: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_allow));
|
||||||
|
|
||||||
if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
|
if (sym_bpf_map__resize(obj->maps.sd_bind_deny, MAX(deny_count, 1u)) != 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
|
||||||
"Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny));
|
"bpf-socket-bind: Failed to resize BPF map '%s': %m", sym_bpf_map__name(obj->maps.sd_bind_deny));
|
||||||
|
|
||||||
if (socket_bind_bpf__load(obj) != 0)
|
if (socket_bind_bpf__load(obj) != 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno,
|
||||||
"Failed to load BPF object: %m");
|
"bpf-socket-bind: Failed to load BPF object: %m");
|
||||||
|
|
||||||
allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow);
|
allow_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_allow);
|
||||||
assert(allow_map_fd >= 0);
|
assert(allow_map_fd >= 0);
|
||||||
@ -96,7 +97,7 @@ static int prepare_socket_bind_bpf(
|
|||||||
r = update_rules_map(allow_map_fd, allow);
|
r = update_rules_map(allow_map_fd, allow);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
|
||||||
"Failed to put socket bind allow rules into BPF map '%s'",
|
"bpf-socket-bind: Failed to put socket bind allow rules into BPF map '%s'",
|
||||||
sym_bpf_map__name(obj->maps.sd_bind_allow));
|
sym_bpf_map__name(obj->maps.sd_bind_allow));
|
||||||
|
|
||||||
deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny);
|
deny_map_fd = sym_bpf_map__fd(obj->maps.sd_bind_deny);
|
||||||
@ -105,7 +106,7 @@ static int prepare_socket_bind_bpf(
|
|||||||
r = update_rules_map(deny_map_fd, deny);
|
r = update_rules_map(deny_map_fd, deny);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
|
||||||
"Failed to put socket bind deny rules into BPF map '%s'",
|
"bpf-socket-bind: Failed to put socket bind deny rules into BPF map '%s'",
|
||||||
sym_bpf_map__name(obj->maps.sd_bind_deny));
|
sym_bpf_map__name(obj->maps.sd_bind_deny));
|
||||||
|
|
||||||
*ret_obj = TAKE_PTR(obj);
|
*ret_obj = TAKE_PTR(obj);
|
||||||
@ -116,25 +117,17 @@ int bpf_socket_bind_supported(void) {
|
|||||||
_cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
|
_cleanup_(socket_bind_bpf_freep) struct socket_bind_bpf *obj = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
if (!cgroup_bpf_supported())
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Can't determine whether the unified hierarchy is used: %m");
|
|
||||||
if (r == 0) {
|
|
||||||
log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dlopen_bpf() < 0)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) {
|
if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, /*ifindex=*/0)) {
|
||||||
log_debug("BPF program type cgroup_sock_addr is not supported");
|
log_debug("bpf-socket-bind: BPF program type cgroup_sock_addr is not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = prepare_socket_bind_bpf(/*unit=*/NULL, /*allow_rules=*/NULL, /*deny_rules=*/NULL, &obj);
|
r = prepare_socket_bind_bpf(/*unit=*/NULL, /*allow_rules=*/NULL, /*deny_rules=*/NULL, &obj);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_debug_errno(r, "BPF based socket_bind is not supported: %m");
|
log_debug_errno(r, "bpf-socket-bind: socket bind filtering is not supported: %m");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +147,7 @@ int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) {
|
|||||||
|
|
||||||
r = fdset_put(u->initial_socket_bind_link_fds, fd);
|
r = fdset_put(u->initial_socket_bind_link_fds, fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to put socket-bind BPF link fd %d to initial fdset", fd);
|
return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to put BPF fd %d to initial fdset", fd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -175,29 +168,29 @@ static int socket_bind_install_impl(Unit *u) {
|
|||||||
|
|
||||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to get cgroup path: %m");
|
return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to get cgroup path: %m");
|
||||||
|
|
||||||
if (!cc->socket_bind_allow && !cc->socket_bind_deny)
|
if (!cc->socket_bind_allow && !cc->socket_bind_deny)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = prepare_socket_bind_bpf(u, cc->socket_bind_allow, cc->socket_bind_deny, &obj);
|
r = prepare_socket_bind_bpf(u, cc->socket_bind_allow, cc->socket_bind_deny, &obj);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to load BPF object: %m");
|
return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to load BPF object: %m");
|
||||||
|
|
||||||
cgroup_fd = open(cgroup_path, O_RDONLY | O_CLOEXEC, 0);
|
cgroup_fd = open(cgroup_path, O_RDONLY | O_CLOEXEC, 0);
|
||||||
if (cgroup_fd < 0)
|
if (cgroup_fd < 0)
|
||||||
return log_unit_error_errno(u, errno, "Failed to open cgroup=%s for reading: %m", cgroup_path);
|
return log_unit_error_errno(u, errno, "bpf-socket-bind: Failed to open cgroup %s for reading: %m", cgroup_path);
|
||||||
|
|
||||||
ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
|
ipv4 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind4, cgroup_fd);
|
||||||
r = sym_libbpf_get_error(ipv4);
|
r = sym_libbpf_get_error(ipv4);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program: %m",
|
return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to link '%s' cgroup-bpf program: %m",
|
||||||
sym_bpf_program__name(obj->progs.sd_bind4));
|
sym_bpf_program__name(obj->progs.sd_bind4));
|
||||||
|
|
||||||
ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
|
ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
|
||||||
r = sym_libbpf_get_error(ipv6);
|
r = sym_libbpf_get_error(ipv6);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to link '%s' cgroup-bpf program: %m",
|
return log_unit_error_errno(u, r, "bpf-socket-bind: Failed to link '%s' cgroup-bpf program: %m",
|
||||||
sym_bpf_program__name(obj->progs.sd_bind6));
|
sym_bpf_program__name(obj->progs.sd_bind6));
|
||||||
|
|
||||||
u->ipv4_socket_bind_link = TAKE_PTR(ipv4);
|
u->ipv4_socket_bind_link = TAKE_PTR(ipv4);
|
||||||
@ -241,7 +234,8 @@ int bpf_socket_bind_add_initial_link_fd(Unit *u, int fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int bpf_socket_bind_install(Unit *u) {
|
int bpf_socket_bind_install(Unit *u) {
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to install socket bind: BPF framework is not supported");
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"bpf-socket-bind: Failed to install; BPF framework is not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
|
int bpf_serialize_socket_bind(Unit *u, FILE *f, FDSet *fds) {
|
||||||
|
|||||||
34
src/core/bpf-util.c
Normal file
34
src/core/bpf-util.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "bpf-dlopen.h"
|
||||||
|
#include "bpf-util.h"
|
||||||
|
#include "cgroup-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
bool cgroup_bpf_supported(void) {
|
||||||
|
static int supported = -1;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (supported >= 0)
|
||||||
|
return supported;
|
||||||
|
|
||||||
|
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
||||||
|
if (r < 0) {
|
||||||
|
log_warning_errno(r, "Can't determine whether the unified hierarchy is used: %m");
|
||||||
|
return (supported = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
log_info_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"Not running with unified cgroup hierarchy, disabling cgroup BPF features.");
|
||||||
|
return (supported = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = dlopen_bpf();
|
||||||
|
if (r < 0) {
|
||||||
|
log_info_errno(r, "Failed to open libbpf, cgroup BPF features disabled: %m");
|
||||||
|
return (supported = false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (supported = true);
|
||||||
|
}
|
||||||
5
src/core/bpf-util.h
Normal file
5
src/core/bpf-util.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
bool cgroup_bpf_supported(void);
|
||||||
@ -163,14 +163,56 @@ static int device_coldplug(Unit *u) {
|
|||||||
assert(d->state == DEVICE_DEAD);
|
assert(d->state == DEVICE_DEAD);
|
||||||
|
|
||||||
/* First, let's put the deserialized state and found mask into effect, if we have it. */
|
/* First, let's put the deserialized state and found mask into effect, if we have it. */
|
||||||
|
if (d->deserialized_state < 0)
|
||||||
if (d->deserialized_state < 0 ||
|
|
||||||
(d->deserialized_state == d->state &&
|
|
||||||
d->deserialized_found == d->found))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
d->found = d->deserialized_found;
|
Manager *m = u->manager;
|
||||||
device_set_state(d, d->deserialized_state);
|
DeviceFound found = d->deserialized_found;
|
||||||
|
DeviceState state = d->deserialized_state;
|
||||||
|
|
||||||
|
/* On initial boot, switch-root, reload, reexecute, the following happen:
|
||||||
|
* 1. MANAGER_IS_RUNNING() == false
|
||||||
|
* 2. enumerate devices: manager_enumerate() -> device_enumerate()
|
||||||
|
* Device.enumerated_found is set.
|
||||||
|
* 3. deserialize devices: manager_deserialize() -> device_deserialize()
|
||||||
|
* Device.deserialize_state and Device.deserialized_found are set.
|
||||||
|
* 4. coldplug devices: manager_coldplug() -> device_coldplug()
|
||||||
|
* deserialized properties are copied to the main properties.
|
||||||
|
* 5. MANAGER_IS_RUNNING() == true: manager_ready()
|
||||||
|
* 6. catchup devices: manager_catchup() -> device_catchup()
|
||||||
|
* Device.enumerated_found is applied to Device.found, and state is updated based on that.
|
||||||
|
*
|
||||||
|
* Notes:
|
||||||
|
* - On initial boot, no udev database exists. Hence, no devices are enumerated in the step 2.
|
||||||
|
* Also, there is no deserialized device. Device units are (a) generated based on dependencies of
|
||||||
|
* other units, or (b) generated when uevents are received.
|
||||||
|
*
|
||||||
|
* - On switch-root, the udev database may be cleared, except for devices with sticky bit, i.e.
|
||||||
|
* OPTIONS="db_persist". Hence, almost no devices are enumerated in the step 2. However, in general,
|
||||||
|
* we have several serialized devices. So, DEVICE_FOUND_UDEV bit in the deserialized_found must be
|
||||||
|
* ignored, as udev rules in initramfs and the main system are often different. If the deserialized
|
||||||
|
* state is DEVICE_PLUGGED, we need to downgrade it to DEVICE_TENTATIVE (or DEVICE_DEAD if nobody
|
||||||
|
* sees the device). Unlike the other starting mode, Manager.honor_device_enumeration == false
|
||||||
|
* (maybe, it is better to rename the flag) when device_coldplug() and device_catchup() are called.
|
||||||
|
* Hence, let's conditionalize the operations by using the flag. After switch-root, systemd-udevd
|
||||||
|
* will (re-)process all devices, and the Device.found and Device.state will be adjusted.
|
||||||
|
*
|
||||||
|
* - On reload or reexecute, we can trust enumerated_found, deserialized_found, and deserialized_state.
|
||||||
|
* Of course, deserialized parameters may be outdated, but the unit state can be adjusted later by
|
||||||
|
* device_catchup() or uevents. */
|
||||||
|
|
||||||
|
if (!m->honor_device_enumeration && !MANAGER_IS_USER(m) &&
|
||||||
|
!FLAGS_SET(d->enumerated_found, DEVICE_FOUND_UDEV)) {
|
||||||
|
found &= ~DEVICE_FOUND_UDEV; /* ignore DEVICE_FOUND_UDEV bit */
|
||||||
|
if (state == DEVICE_PLUGGED)
|
||||||
|
state = DEVICE_TENTATIVE; /* downgrade state */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->found == found && d->state == state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
d->found = found;
|
||||||
|
device_set_state(d, state);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,13 +686,9 @@ static void device_found_changed(Device *d, DeviceFound previous, DeviceFound no
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
|
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
|
||||||
Manager *m;
|
|
||||||
|
|
||||||
assert(d);
|
assert(d);
|
||||||
|
|
||||||
m = UNIT(d)->manager;
|
if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
|
||||||
|
|
||||||
if (MANAGER_IS_RUNNING(m) && (m->honor_device_enumeration || MANAGER_IS_USER(m))) {
|
|
||||||
DeviceFound n, previous;
|
DeviceFound n, previous;
|
||||||
|
|
||||||
/* When we are already running, then apply the new mask right-away, and trigger state changes
|
/* When we are already running, then apply the new mask right-away, and trigger state changes
|
||||||
|
|||||||
@ -135,6 +135,13 @@ libcore_sources = '''
|
|||||||
unit.h
|
unit.h
|
||||||
'''.split()
|
'''.split()
|
||||||
|
|
||||||
|
if conf.get('BPF_FRAMEWORK') == 1
|
||||||
|
libcore_sources += files(
|
||||||
|
'bpf-util.c',
|
||||||
|
'bpf-util.h',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
subdir('bpf')
|
subdir('bpf')
|
||||||
|
|
||||||
subdir('bpf/socket_bind')
|
subdir('bpf/socket_bind')
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include "bpf-dlopen.h"
|
#include "bpf-dlopen.h"
|
||||||
#include "bpf-link.h"
|
#include "bpf-link.h"
|
||||||
|
#include "bpf-util.h"
|
||||||
#include "bpf/restrict_ifaces/restrict-ifaces-skel.h"
|
#include "bpf/restrict_ifaces/restrict-ifaces-skel.h"
|
||||||
|
|
||||||
static struct restrict_ifaces_bpf *restrict_ifaces_bpf_free(struct restrict_ifaces_bpf *obj) {
|
static struct restrict_ifaces_bpf *restrict_ifaces_bpf_free(struct restrict_ifaces_bpf *obj) {
|
||||||
@ -34,19 +34,19 @@ static int prepare_restrict_ifaces_bpf(
|
|||||||
|
|
||||||
obj = restrict_ifaces_bpf__open();
|
obj = restrict_ifaces_bpf__open();
|
||||||
if (!obj)
|
if (!obj)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "Failed to open BPF object: %m");
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, errno, "restrict-interfaces: Failed to open BPF object: %m");
|
||||||
|
|
||||||
r = sym_bpf_map__resize(obj->maps.sd_restrictif, MAX(set_size(restrict_network_interfaces), 1u));
|
r = sym_bpf_map__resize(obj->maps.sd_restrictif, MAX(set_size(restrict_network_interfaces), 1u));
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, r,
|
||||||
"Failed to resize BPF map '%s': %m",
|
"restrict-interfaces: Failed to resize BPF map '%s': %m",
|
||||||
sym_bpf_map__name(obj->maps.sd_restrictif));
|
sym_bpf_map__name(obj->maps.sd_restrictif));
|
||||||
|
|
||||||
obj->rodata->is_allow_list = is_allow_list;
|
obj->rodata->is_allow_list = is_allow_list;
|
||||||
|
|
||||||
r = restrict_ifaces_bpf__load(obj);
|
r = restrict_ifaces_bpf__load(obj);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, r, "Failed to load BPF object: %m");
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_DEBUG, r, "restrict-interfaces: Failed to load BPF object: %m");
|
||||||
|
|
||||||
map_fd = sym_bpf_map__fd(obj->maps.sd_restrictif);
|
map_fd = sym_bpf_map__fd(obj->maps.sd_restrictif);
|
||||||
|
|
||||||
@ -56,13 +56,15 @@ static int prepare_restrict_ifaces_bpf(
|
|||||||
|
|
||||||
ifindex = rtnl_resolve_interface(&rtnl, iface);
|
ifindex = rtnl_resolve_interface(&rtnl, iface);
|
||||||
if (ifindex < 0) {
|
if (ifindex < 0) {
|
||||||
log_unit_warning_errno(u, ifindex, "Couldn't find index of network interface '%s', ignoring: %m", iface);
|
log_unit_warning_errno(u, ifindex,
|
||||||
|
"restrict-interfaces: Couldn't find index of network interface '%s', ignoring: %m",
|
||||||
|
iface);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sym_bpf_map_update_elem(map_fd, &ifindex, &dummy, BPF_ANY))
|
if (sym_bpf_map_update_elem(map_fd, &ifindex, &dummy, BPF_ANY))
|
||||||
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
|
return log_unit_full_errno(u, u ? LOG_ERR : LOG_WARNING, errno,
|
||||||
"Failed to update BPF map '%s' fd: %m",
|
"restrict-interfaces: Failed to update BPF map '%s' fd: %m",
|
||||||
sym_bpf_map__name(obj->maps.sd_restrictif));
|
sym_bpf_map__name(obj->maps.sd_restrictif));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,29 +80,21 @@ int restrict_network_interfaces_supported(void) {
|
|||||||
if (supported >= 0)
|
if (supported >= 0)
|
||||||
return supported;
|
return supported;
|
||||||
|
|
||||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
if (!cgroup_bpf_supported())
|
||||||
if (r < 0)
|
return (supported = false);
|
||||||
return log_error_errno(r, "Can't determine whether the unified hierarchy is used: %m");
|
|
||||||
if (r == 0) {
|
|
||||||
log_debug("Not running with unified cgroup hierarchy, BPF is not supported");
|
|
||||||
return supported = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dlopen_bpf() < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*ifindex=*/0)) {
|
if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*ifindex=*/0)) {
|
||||||
log_debug("BPF program type cgroup_skb is not supported");
|
log_debug("restrict-interfaces: BPF program type cgroup_skb is not supported");
|
||||||
return supported = 0;
|
return (supported = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj);
|
r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_debug_errno(r, "Failed to load BPF object: %m");
|
log_debug_errno(r, "restrict-interfaces: Failed to load BPF object: %m");
|
||||||
return supported = 0;
|
return (supported = false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return supported = bpf_can_link_program(obj->progs.sd_restrictif_i);
|
return (supported = bpf_can_link_program(obj->progs.sd_restrictif_i));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int restrict_network_interfaces_install_impl(Unit *u) {
|
static int restrict_network_interfaces_install_impl(Unit *u) {
|
||||||
@ -117,7 +111,7 @@ static int restrict_network_interfaces_install_impl(Unit *u) {
|
|||||||
|
|
||||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to get cgroup path: %m");
|
return log_unit_error_errno(u, r, "restrict-interfaces: Failed to get cgroup path: %m");
|
||||||
|
|
||||||
if (!cc->restrict_network_interfaces)
|
if (!cc->restrict_network_interfaces)
|
||||||
return 0;
|
return 0;
|
||||||
@ -136,12 +130,12 @@ static int restrict_network_interfaces_install_impl(Unit *u) {
|
|||||||
ingress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_i, cgroup_fd);
|
ingress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_i, cgroup_fd);
|
||||||
r = sym_libbpf_get_error(ingress_link);
|
r = sym_libbpf_get_error(ingress_link);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to create ingress cgroup link: %m");
|
return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create ingress cgroup link: %m");
|
||||||
|
|
||||||
egress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_e, cgroup_fd);
|
egress_link = sym_bpf_program__attach_cgroup(obj->progs.sd_restrictif_e, cgroup_fd);
|
||||||
r = sym_libbpf_get_error(egress_link);
|
r = sym_libbpf_get_error(egress_link);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to create egress cgroup link: %m");
|
return log_unit_error_errno(u, r, "restrict-interfaces: Failed to create egress cgroup link: %m");
|
||||||
|
|
||||||
u->restrict_ifaces_ingress_bpf_link = TAKE_PTR(ingress_link);
|
u->restrict_ifaces_ingress_bpf_link = TAKE_PTR(ingress_link);
|
||||||
u->restrict_ifaces_egress_bpf_link = TAKE_PTR(egress_link);
|
u->restrict_ifaces_egress_bpf_link = TAKE_PTR(egress_link);
|
||||||
@ -180,7 +174,8 @@ int restrict_network_interfaces_add_initial_link_fd(Unit *u, int fd) {
|
|||||||
|
|
||||||
r = fdset_put(u->initial_restric_ifaces_link_fds, fd);
|
r = fdset_put(u->initial_restric_ifaces_link_fds, fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd);
|
return log_unit_error_errno(u, r,
|
||||||
|
"restrict-interfaces: Failed to put restrict-ifaces-bpf-fd %d to restored fdset: %m", fd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -192,7 +187,7 @@ int restrict_network_interfaces_supported(void) {
|
|||||||
|
|
||||||
int restrict_network_interfaces_install(Unit *u) {
|
int restrict_network_interfaces_install(Unit *u) {
|
||||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
"Failed to install RestrictInterfaces: BPF programs built from source code are not supported: %m");
|
"restrict-interfaces: Failed to install; BPF programs built from source code are not supported: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
int serialize_restrict_network_interfaces(Unit *u, FILE *f, FDSet *fds) {
|
int serialize_restrict_network_interfaces(Unit *u, FILE *f, FDSet *fds) {
|
||||||
|
|||||||
@ -47,6 +47,20 @@
|
|||||||
# define SWAP64(n) (n)
|
# define SWAP64(n) (n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The condition below is from glibc's string/string-inline.c.
|
||||||
|
* See definition of _STRING_INLINE_unaligned. */
|
||||||
|
#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__)
|
||||||
|
|
||||||
|
/* To check alignment gcc has an appropriate operator. Other compilers don't. */
|
||||||
|
# if __GNUC__ >= 2
|
||||||
|
# define UNALIGNED_P(p) (((size_t) p) % __alignof__(uint32_t) != 0)
|
||||||
|
# else
|
||||||
|
# define UNALIGNED_P(p) (((size_t) p) % sizeof(uint32_t) != 0)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define UNALIGNED_P(p) false
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This array contains the bytes used to pad the buffer to the next
|
/* This array contains the bytes used to pad the buffer to the next
|
||||||
64-byte boundary. (FIPS 180-2:5.1.1) */
|
64-byte boundary. (FIPS 180-2:5.1.1) */
|
||||||
static const uint8_t fillbuf[64] = {
|
static const uint8_t fillbuf[64] = {
|
||||||
@ -94,10 +108,7 @@ void sha256_init_ctx(struct sha256_ctx *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Process the remaining bytes in the internal buffer and the usual
|
/* Process the remaining bytes in the internal buffer and the usual
|
||||||
prolog according to the standard and write the result to RESBUF.
|
prolog according to the standard and write the result to RESBUF. */
|
||||||
|
|
||||||
IMPORTANT: On some systems it is required that RESBUF is correctly
|
|
||||||
aligned for a 32 bits value. */
|
|
||||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
||||||
/* Take yet unprocessed bytes into account. */
|
/* Take yet unprocessed bytes into account. */
|
||||||
uint32_t bytes = ctx->buflen;
|
uint32_t bytes = ctx->buflen;
|
||||||
@ -122,7 +133,10 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
|||||||
|
|
||||||
/* Put result from CTX in first 32 bytes following RESBUF. */
|
/* Put result from CTX in first 32 bytes following RESBUF. */
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
|
if (UNALIGNED_P(resbuf))
|
||||||
|
memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t));
|
||||||
|
else
|
||||||
|
((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
|
||||||
|
|
||||||
return resbuf;
|
return resbuf;
|
||||||
}
|
}
|
||||||
@ -156,17 +170,6 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
|
|||||||
|
|
||||||
/* Process available complete blocks. */
|
/* Process available complete blocks. */
|
||||||
if (len >= 64) {
|
if (len >= 64) {
|
||||||
|
|
||||||
/* The condition below is from glibc's string/string-inline.c.
|
|
||||||
* See definition of _STRING_INLINE_unaligned. */
|
|
||||||
#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__)
|
|
||||||
|
|
||||||
/* To check alignment gcc has an appropriate operator. Other compilers don't. */
|
|
||||||
# if __GNUC__ >= 2
|
|
||||||
# define UNALIGNED_P(p) (((size_t) p) % __alignof__(uint32_t) != 0)
|
|
||||||
# else
|
|
||||||
# define UNALIGNED_P(p) (((size_t) p) % sizeof(uint32_t) != 0)
|
|
||||||
# endif
|
|
||||||
if (UNALIGNED_P(buffer))
|
if (UNALIGNED_P(buffer))
|
||||||
while (len > 64) {
|
while (len > 64) {
|
||||||
memcpy(ctx->buffer, buffer, 64);
|
memcpy(ctx->buffer, buffer, 64);
|
||||||
@ -174,9 +177,7 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
|
|||||||
buffer = (const char *) buffer + 64;
|
buffer = (const char *) buffer + 64;
|
||||||
len -= 64;
|
len -= 64;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
#endif
|
|
||||||
{
|
|
||||||
sha256_process_block(buffer, len & ~63, ctx);
|
sha256_process_block(buffer, len & ~63, ctx);
|
||||||
buffer = (const char *) buffer + (len & ~63);
|
buffer = (const char *) buffer + (len & ~63);
|
||||||
len &= 63;
|
len &= 63;
|
||||||
|
|||||||
@ -80,12 +80,13 @@ fi
|
|||||||
|
|
||||||
if [ "${0##*/}" = "installkernel" ]; then
|
if [ "${0##*/}" = "installkernel" ]; then
|
||||||
COMMAND=add
|
COMMAND=add
|
||||||
# make install doesn't pass any initrds
|
# kernel's install.sh invokes us as
|
||||||
no_initrds=1
|
# /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
|
||||||
|
# We ignore the last two arguments.
|
||||||
|
set -- "$1"
|
||||||
else
|
else
|
||||||
COMMAND="$1"
|
COMMAND="$1"
|
||||||
[ $# -ge 1 ] && shift
|
[ $# -ge 1 ] && shift
|
||||||
no_initrds=0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$COMMAND" = "inspect" ]; then
|
if [ "$COMMAND" = "inspect" ]; then
|
||||||
@ -320,16 +321,8 @@ case "$COMMAND" in
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for f in $PLUGINS; do
|
for f in $PLUGINS; do
|
||||||
if [ "$no_initrds" = 1 ]; then
|
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS" "$@"
|
||||||
# kernel's install.sh invokes us as
|
"$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@"
|
||||||
# /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
|
|
||||||
# We ignore the last two arguments.
|
|
||||||
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $1"
|
|
||||||
"$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$1"
|
|
||||||
else
|
|
||||||
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $*"
|
|
||||||
"$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@"
|
|
||||||
fi
|
|
||||||
|
|
||||||
err=$?
|
err=$?
|
||||||
[ $err -eq $skip_remaining ] && break
|
[ $err -eq $skip_remaining ] && break
|
||||||
@ -362,8 +355,8 @@ case "$COMMAND" in
|
|||||||
|
|
||||||
# Assert that ENTRY_DIR_ABS actually matches what we are printing here
|
# Assert that ENTRY_DIR_ABS actually matches what we are printing here
|
||||||
[ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; }
|
[ "${ENTRY_DIR_ABS%/*}" = "$KERNEL_INSTALL_BOOT_ROOT/$ENTRY_TOKEN" ] || { echo "Assertion didn't pass." >&2; exit 1; }
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Error: unknown command '$COMMAND'" >&2
|
echo "Error: unknown command '$COMMAND'" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@ -222,7 +222,8 @@ tests += [
|
|||||||
libglib,
|
libglib,
|
||||||
libgobject,
|
libgobject,
|
||||||
libgio,
|
libgio,
|
||||||
libdbus]],
|
libdbus,
|
||||||
|
libm]],
|
||||||
|
|
||||||
[files('sd-bus/test-bus-signature.c'),
|
[files('sd-bus/test-bus-signature.c'),
|
||||||
[],
|
[],
|
||||||
|
|||||||
@ -428,7 +428,7 @@ int bus_message_from_header(
|
|||||||
|
|
||||||
_cleanup_free_ sd_bus_message *m = NULL;
|
_cleanup_free_ sd_bus_message *m = NULL;
|
||||||
struct bus_header *h;
|
struct bus_header *h;
|
||||||
size_t a, label_sz;
|
size_t a, label_sz = 0; /* avoid false maybe-uninitialized warning */
|
||||||
|
|
||||||
assert(bus);
|
assert(bus);
|
||||||
assert(header || header_accessible <= 0);
|
assert(header || header_accessible <= 0);
|
||||||
@ -506,7 +506,10 @@ int bus_message_from_header(
|
|||||||
m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
|
m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
|
||||||
m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
|
m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
|
||||||
|
|
||||||
if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size)
|
assert(message_size >= sizeof(struct bus_header));
|
||||||
|
if (m->fields_size > message_size - sizeof(struct bus_header) ||
|
||||||
|
ALIGN8(m->fields_size) > message_size - sizeof(struct bus_header) ||
|
||||||
|
m->body_size != message_size - sizeof(struct bus_header) - ALIGN8(m->fields_size))
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3061,15 +3064,21 @@ void bus_body_part_unmap(struct bus_body_part *part) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
|
static int buffer_peek(const void *p, size_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
|
||||||
size_t k, start, end;
|
size_t k, start, end;
|
||||||
|
|
||||||
assert(rindex);
|
assert(rindex);
|
||||||
assert(align > 0);
|
assert(align > 0);
|
||||||
|
|
||||||
start = ALIGN_TO((size_t) *rindex, align);
|
start = ALIGN_TO(*rindex, align);
|
||||||
end = start + nbytes;
|
if (start > sz)
|
||||||
|
return -EBADMSG;
|
||||||
|
|
||||||
|
/* Avoid overflow below */
|
||||||
|
if (nbytes > SIZE_MAX - start)
|
||||||
|
return -EBADMSG;
|
||||||
|
|
||||||
|
end = start + nbytes;
|
||||||
if (end > sz)
|
if (end > sz)
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
@ -3272,10 +3281,17 @@ static int message_peek_body(
|
|||||||
assert(rindex);
|
assert(rindex);
|
||||||
assert(align > 0);
|
assert(align > 0);
|
||||||
|
|
||||||
start = ALIGN_TO((size_t) *rindex, align);
|
start = ALIGN_TO(*rindex, align);
|
||||||
padding = start - *rindex;
|
if (start > m->user_body_size)
|
||||||
end = start + nbytes;
|
return -EBADMSG;
|
||||||
|
|
||||||
|
padding = start - *rindex;
|
||||||
|
|
||||||
|
/* Avoid overflow below */
|
||||||
|
if (nbytes > SIZE_MAX - start)
|
||||||
|
return -EBADMSG;
|
||||||
|
|
||||||
|
end = start + nbytes;
|
||||||
if (end > m->user_body_size)
|
if (end > m->user_body_size)
|
||||||
return -EBADMSG;
|
return -EBADMSG;
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
|
|||||||
@ -2342,8 +2342,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
|
|||||||
if (r == 0)
|
if (r == 0)
|
||||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||||
|
|
||||||
reset_scheduled_shutdown(m);
|
|
||||||
|
|
||||||
if (m->enable_wall_messages) {
|
if (m->enable_wall_messages) {
|
||||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||||
_cleanup_free_ char *username = NULL;
|
_cleanup_free_ char *username = NULL;
|
||||||
@ -2361,6 +2359,8 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
|
|||||||
username, tty, logind_wall_tty_filter, m);
|
username, tty, logind_wall_tty_filter, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset_scheduled_shutdown(m);
|
||||||
|
|
||||||
return sd_bus_reply_method_return(message, "b", true);
|
return sd_bus_reply_method_return(message, "b", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -42,20 +42,28 @@ _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
|
|||||||
return left % USEC_PER_HOUR;
|
return left % USEC_PER_HOUR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool logind_wall_tty_filter(const char *tty, void *userdata) {
|
bool logind_wall_tty_filter(const char *tty, bool is_local, void *userdata) {
|
||||||
Manager *m = userdata;
|
Manager *m = ASSERT_PTR(userdata);
|
||||||
const char *p;
|
|
||||||
|
|
||||||
assert(m);
|
assert(m->scheduled_shutdown_action);
|
||||||
|
|
||||||
if (!m->scheduled_shutdown_tty)
|
const char *p = path_startswith(tty, "/dev/");
|
||||||
return true;
|
|
||||||
|
|
||||||
p = path_startswith(tty, "/dev/");
|
|
||||||
if (!p)
|
if (!p)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return !streq(p, m->scheduled_shutdown_tty);
|
/* Do not send information about events which do not destroy local sessions to local terminals. We
|
||||||
|
* can assume that if the system enters sleep or hibernation, this will be visible in an obvious way
|
||||||
|
* for any local user. And once the systems exits sleep or hibernation, the notication would be just
|
||||||
|
* noise, in particular for auto-suspend. */
|
||||||
|
if (is_local &&
|
||||||
|
IN_SET(m->scheduled_shutdown_action->handle,
|
||||||
|
HANDLE_SUSPEND,
|
||||||
|
HANDLE_HIBERNATE,
|
||||||
|
HANDLE_HYBRID_SLEEP,
|
||||||
|
HANDLE_SUSPEND_THEN_HIBERNATE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !streq_ptr(p, m->scheduled_shutdown_tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int warn_wall(Manager *m, usec_t n) {
|
static int warn_wall(Manager *m, usec_t n) {
|
||||||
|
|||||||
@ -180,6 +180,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_n_autovts);
|
|||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs_size);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs_size);
|
||||||
|
|
||||||
int manager_setup_wall_message_timer(Manager *m);
|
int manager_setup_wall_message_timer(Manager *m);
|
||||||
bool logind_wall_tty_filter(const char *tty, void *userdata);
|
bool logind_wall_tty_filter(const char *tty, bool is_local, void *userdata);
|
||||||
|
|
||||||
int manager_read_efi_boot_loader_entries(Manager *m);
|
int manager_read_efi_boot_loader_entries(Manager *m);
|
||||||
|
|||||||
@ -528,18 +528,26 @@ static int dns_stub_send(
|
|||||||
if (s)
|
if (s)
|
||||||
r = dns_stream_write_packet(s, reply);
|
r = dns_stream_write_packet(s, reply);
|
||||||
else {
|
else {
|
||||||
int fd;
|
int fd, ifindex;
|
||||||
|
|
||||||
fd = find_socket_fd(m, l, p->family, &p->sender, SOCK_DGRAM);
|
fd = find_socket_fd(m, l, p->family, &p->sender, SOCK_DGRAM);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
|
if (address_is_proxy(p->family, &p->destination))
|
||||||
|
/* Force loopback iface if this is the loopback proxy stub
|
||||||
|
* and ifindex was normalized to 0 by manager_recv(). */
|
||||||
|
ifindex = p->ifindex ?: LOOPBACK_IFINDEX;
|
||||||
|
else
|
||||||
|
/* Force loopback iface if this is the main listener stub. */
|
||||||
|
ifindex = l ? p->ifindex : LOOPBACK_IFINDEX;
|
||||||
|
|
||||||
/* Note that it is essential here that we explicitly choose the source IP address for this
|
/* Note that it is essential here that we explicitly choose the source IP address for this
|
||||||
* packet. This is because otherwise the kernel will choose it automatically based on the
|
* packet. This is because otherwise the kernel will choose it automatically based on the
|
||||||
* routing table and will thus pick 127.0.0.1 rather than 127.0.0.53. */
|
* routing table and will thus pick 127.0.0.1 rather than 127.0.0.53/54. */
|
||||||
r = manager_send(m,
|
r = manager_send(m,
|
||||||
fd,
|
fd,
|
||||||
l || address_is_proxy(p->family, &p->destination) ? p->ifindex : LOOPBACK_IFINDEX, /* force loopback iface if this is the main listener stub */
|
ifindex,
|
||||||
p->family, &p->sender, p->sender_port, &p->destination,
|
p->family, &p->sender, p->sender_port, &p->destination,
|
||||||
reply);
|
reply);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ static void *bpf_dl = NULL;
|
|||||||
|
|
||||||
struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
|
struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
|
||||||
struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *);
|
struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *);
|
||||||
long (*sym_libbpf_get_error)(const void *);
|
|
||||||
int (*sym_bpf_link__fd)(const struct bpf_link *);
|
int (*sym_bpf_link__fd)(const struct bpf_link *);
|
||||||
int (*sym_bpf_link__destroy)(struct bpf_link *);
|
int (*sym_bpf_link__destroy)(struct bpf_link *);
|
||||||
int (*sym_bpf_map__fd)(const struct bpf_map *);
|
int (*sym_bpf_map__fd)(const struct bpf_map *);
|
||||||
@ -26,9 +25,27 @@ void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *);
|
|||||||
void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
|
void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
|
||||||
bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
||||||
const char* (*sym_bpf_program__name)(const struct bpf_program *);
|
const char* (*sym_bpf_program__name)(const struct bpf_program *);
|
||||||
|
libbpf_print_fn_t (*sym_libbpf_set_print)(libbpf_print_fn_t);
|
||||||
|
long (*sym_libbpf_get_error)(const void *);
|
||||||
|
|
||||||
|
_printf_(2,0)
|
||||||
|
static int bpf_print_func(enum libbpf_print_level level, const char *fmt, va_list ap) {
|
||||||
|
#if !LOG_TRACE
|
||||||
|
/* libbpf logs a lot of details at its debug level, which we don't need to see. */
|
||||||
|
if (level == LIBBPF_DEBUG)
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
/* All other levels are downgraded to LOG_DEBUG */
|
||||||
|
|
||||||
|
/* errno is used here, on the assumption that if the log message uses %m, errno will be set to
|
||||||
|
* something useful. Otherwise, it shouldn't matter, we may pass 0 or some bogus value. */
|
||||||
|
return log_internalv(LOG_DEBUG, errno, NULL, 0, NULL, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
int dlopen_bpf(void) {
|
int dlopen_bpf(void) {
|
||||||
return dlopen_many_sym_or_warn(
|
int r;
|
||||||
|
|
||||||
|
r = dlopen_many_sym_or_warn(
|
||||||
&bpf_dl, "libbpf.so.0", LOG_DEBUG,
|
&bpf_dl, "libbpf.so.0", LOG_DEBUG,
|
||||||
DLSYM_ARG(bpf_link__destroy),
|
DLSYM_ARG(bpf_link__destroy),
|
||||||
DLSYM_ARG(bpf_link__fd),
|
DLSYM_ARG(bpf_link__fd),
|
||||||
@ -48,7 +65,14 @@ int dlopen_bpf(void) {
|
|||||||
DLSYM_ARG(bpf_program__attach_cgroup),
|
DLSYM_ARG(bpf_program__attach_cgroup),
|
||||||
DLSYM_ARG(bpf_program__attach_lsm),
|
DLSYM_ARG(bpf_program__attach_lsm),
|
||||||
DLSYM_ARG(bpf_program__name),
|
DLSYM_ARG(bpf_program__name),
|
||||||
|
DLSYM_ARG(libbpf_set_print),
|
||||||
DLSYM_ARG(libbpf_get_error));
|
DLSYM_ARG(libbpf_get_error));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* We set the print helper unconditionally. Otherwise libbpf will emit not useful log messages. */
|
||||||
|
(void) sym_libbpf_set_print(bpf_print_func);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
extern struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
|
extern struct bpf_link* (*sym_bpf_program__attach_cgroup)(struct bpf_program *, int);
|
||||||
extern struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *);
|
extern struct bpf_link* (*sym_bpf_program__attach_lsm)(struct bpf_program *);
|
||||||
extern long (*sym_libbpf_get_error)(const void *);
|
|
||||||
extern int (*sym_bpf_link__fd)(const struct bpf_link *);
|
extern int (*sym_bpf_link__fd)(const struct bpf_link *);
|
||||||
extern int (*sym_bpf_link__destroy)(struct bpf_link *);
|
extern int (*sym_bpf_link__destroy)(struct bpf_link *);
|
||||||
extern int (*sym_bpf_map__fd)(const struct bpf_map *);
|
extern int (*sym_bpf_map__fd)(const struct bpf_map *);
|
||||||
@ -27,6 +26,8 @@ extern void (*sym_bpf_object__detach_skeleton)(struct bpf_object_skeleton *);
|
|||||||
extern void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
|
extern void (*sym_bpf_object__destroy_skeleton)(struct bpf_object_skeleton *);
|
||||||
extern bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
extern bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
||||||
extern const char* (*sym_bpf_program__name)(const struct bpf_program *);
|
extern const char* (*sym_bpf_program__name)(const struct bpf_program *);
|
||||||
|
extern libbpf_print_fn_t (*sym_libbpf_set_print)(libbpf_print_fn_t);
|
||||||
|
extern long (*sym_libbpf_get_error)(const void *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -571,7 +571,11 @@ static int verify_xbootldr_udev(
|
|||||||
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
|
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to get device property: %m");
|
return log_error_errno(r, "Failed to get device property: %m");
|
||||||
if (id128_equal_string(v, GPT_XBOOTLDR))
|
|
||||||
|
r = id128_equal_string(v, GPT_XBOOTLDR);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to parse ID_PART_ENTRY_TYPE=%s: %m", v);
|
||||||
|
if (r == 0)
|
||||||
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
|
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
|
||||||
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
|
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
|
||||||
"File system \"%s\" has wrong type for extended boot loader partition.", node);
|
"File system \"%s\" has wrong type for extended boot loader partition.", node);
|
||||||
|
|||||||
@ -1123,7 +1123,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter
|
|||||||
if (ERRNO_IS_SECCOMP_FATAL(r))
|
if (ERRNO_IS_SECCOMP_FATAL(r))
|
||||||
return r;
|
return r;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug_errno(r, "Failed to install systemc call filter for architecture %s, skipping: %m",
|
log_debug_errno(r, "Failed to install system call filter for architecture %s, skipping: %m",
|
||||||
seccomp_arch_to_string(arch));
|
seccomp_arch_to_string(arch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -337,7 +337,7 @@ int utmp_wall(
|
|||||||
const char *message,
|
const char *message,
|
||||||
const char *username,
|
const char *username,
|
||||||
const char *origin_tty,
|
const char *origin_tty,
|
||||||
bool (*match_tty)(const char *tty, void *userdata),
|
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
|
_unused_ _cleanup_(utxent_cleanup) bool utmpx = false;
|
||||||
@ -381,17 +381,20 @@ int utmp_wall(
|
|||||||
if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
|
if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* this access is fine, because STRLEN("/dev/") << 32 (UT_LINESIZE) */
|
/* This access is fine, because strlen("/dev/") < 32 (UT_LINESIZE) */
|
||||||
if (path_startswith(u->ut_line, "/dev/"))
|
if (path_startswith(u->ut_line, "/dev/"))
|
||||||
path = u->ut_line;
|
path = u->ut_line;
|
||||||
else {
|
else {
|
||||||
if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
|
if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
path = buf;
|
path = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match_tty || match_tty(path, userdata)) {
|
/* It seems that the address field is always set for remote logins.
|
||||||
|
* For local logins and other local entries, we get [0,0,0,0]. */
|
||||||
|
bool is_local = memeqzero(u->ut_addr_v6, sizeof(u->ut_addr_v6));
|
||||||
|
|
||||||
|
if (!match_tty || match_tty(path, is_local, userdata)) {
|
||||||
q = write_to_terminal(path, text);
|
q = write_to_terminal(path, text);
|
||||||
if (q < 0)
|
if (q < 0)
|
||||||
r = q;
|
r = q;
|
||||||
|
|||||||
@ -23,7 +23,7 @@ int utmp_wall(
|
|||||||
const char *message,
|
const char *message,
|
||||||
const char *username,
|
const char *username,
|
||||||
const char *origin_tty,
|
const char *origin_tty,
|
||||||
bool (*match_tty)(const char *tty, void *userdata),
|
bool (*match_tty)(const char *tty, bool is_local, void *userdata),
|
||||||
void *userdata);
|
void *userdata);
|
||||||
|
|
||||||
static inline bool utxent_start(void) {
|
static inline bool utxent_start(void) {
|
||||||
|
|||||||
@ -211,7 +211,9 @@ tests += [
|
|||||||
|
|
||||||
[files('test-mkdir.c')],
|
[files('test-mkdir.c')],
|
||||||
|
|
||||||
[files('test-json.c')],
|
[files('test-json.c'),
|
||||||
|
[],
|
||||||
|
[libm]],
|
||||||
|
|
||||||
[files('test-modhex.c')],
|
[files('test-modhex.c')],
|
||||||
|
|
||||||
@ -275,7 +277,9 @@ tests += [
|
|||||||
|
|
||||||
[files('test-parse-helpers.c')],
|
[files('test-parse-helpers.c')],
|
||||||
|
|
||||||
[files('test-parse-util.c')],
|
[files('test-parse-util.c'),
|
||||||
|
[],
|
||||||
|
[libm]],
|
||||||
|
|
||||||
[files('test-sysctl-util.c')],
|
[files('test-sysctl-util.c')],
|
||||||
|
|
||||||
@ -664,6 +668,8 @@ tests += [
|
|||||||
[], [], [], 'ENABLE_NSCD', 'manual'],
|
[], [], [], 'ENABLE_NSCD', 'manual'],
|
||||||
|
|
||||||
[files('test-hmac.c')],
|
[files('test-hmac.c')],
|
||||||
|
|
||||||
|
[files('test-sha256.c')],
|
||||||
]
|
]
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
|
|||||||
@ -655,7 +655,7 @@ TEST(memory_deny_write_execute_shmat) {
|
|||||||
log_notice("Seccomp not available, skipping %s", __func__);
|
log_notice("Seccomp not available, skipping %s", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!have_seccomp_privs()) {
|
if (!have_seccomp_privs() || have_effective_cap(CAP_IPC_OWNER) <= 0) {
|
||||||
log_notice("Not privileged, skipping %s", __func__);
|
log_notice("Not privileged, skipping %s", __func__);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
50
src/test/test-sha256.c
Normal file
50
src/test/test-sha256.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
#include "sha256.h"
|
||||||
|
#include "string-util.h"
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
static void sha256_process_string(const char *key, struct sha256_ctx *ctx) {
|
||||||
|
sha256_process_bytes(key, strlen(key), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_sha256_one(const char *key, const char *expect) {
|
||||||
|
uint8_t result[SHA256_DIGEST_SIZE + 3];
|
||||||
|
_cleanup_free_ char *str = NULL;
|
||||||
|
struct sha256_ctx ctx;
|
||||||
|
|
||||||
|
log_debug("\"%s\" → %s", key, expect);
|
||||||
|
|
||||||
|
assert_se(str = new(char, strlen(key) + 4));
|
||||||
|
|
||||||
|
/* This tests unaligned buffers. */
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 4; i++) {
|
||||||
|
strcpy(str + i, key);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < 4; j++) {
|
||||||
|
_cleanup_free_ char *hex_result = NULL;
|
||||||
|
|
||||||
|
sha256_init_ctx(&ctx);
|
||||||
|
sha256_process_string(str + i, &ctx);
|
||||||
|
sha256_finish_ctx(&ctx, result + j);
|
||||||
|
|
||||||
|
hex_result = hexmem(result + j, SHA256_DIGEST_SIZE);
|
||||||
|
assert_se(streq_ptr(hex_result, expect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(sha256) {
|
||||||
|
/* Results compared with output of 'echo -n "<input>" | sha256sum -' */
|
||||||
|
|
||||||
|
test_sha256_one("abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73");
|
||||||
|
test_sha256_one("ほげほげあっちょんぶりけ",
|
||||||
|
"ce7225683653be3b74861c5a4323b6baf3c3ceb361413ca99e3a5b52c04411bd");
|
||||||
|
test_sha256_one("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
|
||||||
|
"9cfe7faff7054298ca87557e15a10262de8d3eee77827417fbdfea1c41b9ec23");
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_TEST_MAIN(LOG_INFO);
|
||||||
@ -94,7 +94,7 @@ static int send_passwords(const char *socket_name, char **passwords) {
|
|||||||
return (int) n;
|
return (int) n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool wall_tty_match(const char *path, void *userdata) {
|
static bool wall_tty_match(const char *path, bool is_local, void *userdata) {
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|||||||
@ -556,7 +556,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parent already died?");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parent already died?");
|
||||||
|
|
||||||
if (kill(parent, SIGUSR2) < 0)
|
if (kill(parent, SIGUSR2) < 0)
|
||||||
return log_error_errno(errno, "Failed to kill our own parent.");
|
return log_error_errno(errno, "Failed to kill our own parent: %m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -127,7 +127,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
|
|
||||||
r = query_volatile_mode(&m);
|
r = query_volatile_mode(&m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to determine volatile mode from kernel command line.");
|
return log_error_errno(r, "Failed to determine volatile mode from kernel command line: %m");
|
||||||
if (r == 0 && argc >= 2) {
|
if (r == 0 && argc >= 2) {
|
||||||
/* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
|
/* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
|
||||||
m = volatile_mode_from_string(argv[1]);
|
m = volatile_mode_from_string(argv[1]);
|
||||||
|
|||||||
@ -10,6 +10,11 @@ TEST_FORCE_NEWIMAGE=1
|
|||||||
# shellcheck source=test/test-functions
|
# shellcheck source=test/test-functions
|
||||||
. "${TEST_BASE_DIR:?}/test-functions"
|
. "${TEST_BASE_DIR:?}/test-functions"
|
||||||
|
|
||||||
|
PART_UUID="deadbeef-dead-dead-beef-000000000000"
|
||||||
|
DM_NAME="test24_varcrypt"
|
||||||
|
KERNEL_APPEND+=" rd.luks=1 luks.name=$PART_UUID=$DM_NAME luks.key=$PART_UUID=/keyfile:LABEL=varcrypt_keydev"
|
||||||
|
QEMU_OPTIONS+=" -drive format=raw,cache=unsafe,file=${STATEDIR:?}/keydev.img"
|
||||||
|
|
||||||
check_result_qemu() {
|
check_result_qemu() {
|
||||||
local ret=1
|
local ret=1
|
||||||
|
|
||||||
@ -17,13 +22,13 @@ check_result_qemu() {
|
|||||||
[[ -e "${initdir:?}/testok" ]] && ret=0
|
[[ -e "${initdir:?}/testok" ]] && ret=0
|
||||||
[[ -f "$initdir/failed" ]] && cp -a "$initdir/failed" "${TESTDIR:?}"
|
[[ -f "$initdir/failed" ]] && cp -a "$initdir/failed" "${TESTDIR:?}"
|
||||||
|
|
||||||
cryptsetup luksOpen "${LOOPDEV:?}p2" varcrypt <"$TESTDIR/keyfile"
|
cryptsetup luksOpen "${LOOPDEV:?}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile"
|
||||||
mount /dev/mapper/varcrypt "$initdir/var"
|
mount "/dev/mapper/$DM_NAME" "$initdir/var"
|
||||||
save_journal "$initdir/var/log/journal"
|
save_journal "$initdir/var/log/journal"
|
||||||
check_coverage_reports "${initdir:?}" || ret=5
|
check_coverage_reports "${initdir:?}" || ret=5
|
||||||
_umount_dir "$initdir/var"
|
_umount_dir "$initdir/var"
|
||||||
_umount_dir "$initdir"
|
_umount_dir "$initdir"
|
||||||
cryptsetup luksClose /dev/mapper/varcrypt
|
cryptsetup luksClose "/dev/mapper/$DM_NAME"
|
||||||
|
|
||||||
[[ -f "$TESTDIR/failed" ]] && cat "$TESTDIR/failed"
|
[[ -f "$TESTDIR/failed" ]] && cat "$TESTDIR/failed"
|
||||||
echo "${JOURNAL_LIST:-No journals were saved}"
|
echo "${JOURNAL_LIST:-No journals were saved}"
|
||||||
@ -36,45 +41,65 @@ test_create_image() {
|
|||||||
create_empty_image_rootdir
|
create_empty_image_rootdir
|
||||||
|
|
||||||
echo -n test >"${TESTDIR:?}/keyfile"
|
echo -n test >"${TESTDIR:?}/keyfile"
|
||||||
cryptsetup -q luksFormat --pbkdf pbkdf2 --pbkdf-force-iterations 1000 "${LOOPDEV:?}p2" "$TESTDIR/keyfile"
|
cryptsetup -q luksFormat --uuid="$PART_UUID" --pbkdf pbkdf2 --pbkdf-force-iterations 1000 "${LOOPDEV:?}p2" "$TESTDIR/keyfile"
|
||||||
cryptsetup luksOpen "${LOOPDEV}p2" varcrypt <"$TESTDIR/keyfile"
|
cryptsetup luksOpen "${LOOPDEV}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile"
|
||||||
mkfs.ext4 -L var /dev/mapper/varcrypt
|
mkfs.ext4 -L var "/dev/mapper/$DM_NAME"
|
||||||
mkdir -p "${initdir:?}/var"
|
mkdir -p "${initdir:?}/var"
|
||||||
mount /dev/mapper/varcrypt "$initdir/var"
|
mount "/dev/mapper/$DM_NAME" "$initdir/var"
|
||||||
|
|
||||||
# Create what will eventually be our root filesystem onto an overlay
|
LOG_LEVEL=5
|
||||||
(
|
|
||||||
LOG_LEVEL=5
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source <(udevadm info --export --query=env --name=/dev/mapper/varcrypt)
|
|
||||||
# shellcheck source=/dev/null
|
|
||||||
source <(udevadm info --export --query=env --name="${LOOPDEV}p2")
|
|
||||||
|
|
||||||
setup_basic_environment
|
setup_basic_environment
|
||||||
mask_supporting_services
|
mask_supporting_services
|
||||||
|
|
||||||
install_dmevent
|
install_dmevent
|
||||||
generate_module_dependencies
|
generate_module_dependencies
|
||||||
cat >"$initdir/etc/crypttab" <<EOF
|
|
||||||
$DM_NAME UUID=$ID_FS_UUID /etc/varkey
|
|
||||||
EOF
|
|
||||||
echo -n test >"$initdir/etc/varkey"
|
|
||||||
ddebug <"$initdir/etc/crypttab"
|
|
||||||
|
|
||||||
cat >>"$initdir/etc/fstab" <<EOF
|
# Create a keydev
|
||||||
/dev/mapper/varcrypt /var ext4 defaults 0 1
|
dd if=/dev/zero of="${STATEDIR:?}/keydev.img" bs=1M count=16
|
||||||
|
mkfs.ext4 -L varcrypt_keydev "$STATEDIR/keydev.img"
|
||||||
|
mkdir -p "$STATEDIR/keydev"
|
||||||
|
mount "$STATEDIR/keydev.img" "$STATEDIR/keydev"
|
||||||
|
echo -n test >"$STATEDIR/keydev/keyfile"
|
||||||
|
umount "$STATEDIR/keydev"
|
||||||
|
|
||||||
|
cat >>"$initdir/etc/fstab" <<EOF
|
||||||
|
/dev/mapper/$DM_NAME /var ext4 defaults 0 1
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Forward journal messages to the console, so we have something
|
# Forward journal messages to the console, so we have something
|
||||||
# to investigate even if we fail to mount the encrypted /var
|
# to investigate even if we fail to mount the encrypted /var
|
||||||
echo ForwardToConsole=yes >> "$initdir/etc/systemd/journald.conf"
|
echo ForwardToConsole=yes >> "$initdir/etc/systemd/journald.conf"
|
||||||
)
|
|
||||||
|
# If $INITRD wasn't provided explicitly, generate a custom one with dm-crypt
|
||||||
|
# support
|
||||||
|
if [[ -z "$INITRD" ]]; then
|
||||||
|
INITRD="${TESTDIR:?}/initrd.img"
|
||||||
|
dinfo "Generating a custom initrd with dm-crypt support in '${INITRD:?}'"
|
||||||
|
|
||||||
|
if command -v dracut >/dev/null; then
|
||||||
|
dracut --force --verbose --add crypt "$INITRD"
|
||||||
|
elif command -v mkinitcpio >/dev/null; then
|
||||||
|
mkinitcpio --addhooks sd-encrypt --generate "$INITRD"
|
||||||
|
elif command -v mkinitramfs >/dev/null; then
|
||||||
|
# The cryptroot hook is provided by the cryptsetup-initramfs package
|
||||||
|
if ! dpkg-query -s cryptsetup-initramfs; then
|
||||||
|
derror "Missing 'cryptsetup-initramfs' package for dm-crypt support in initrd"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkinitramfs -o "$INITRD"
|
||||||
|
else
|
||||||
|
dfatal "Unrecognized initrd generator, can't continue"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_root_var() {
|
cleanup_root_var() {
|
||||||
ddebug "umount ${initdir:?}/var"
|
ddebug "umount ${initdir:?}/var"
|
||||||
mountpoint "$initdir/var" && umount "$initdir/var"
|
mountpoint "$initdir/var" && umount "$initdir/var"
|
||||||
[[ -b /dev/mapper/varcrypt ]] && cryptsetup luksClose /dev/mapper/varcrypt
|
[[ -b "/dev/mapper/${DM_NAME:?}" ]] && cryptsetup luksClose "/dev/mapper/$DM_NAME"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_cleanup() {
|
test_cleanup() {
|
||||||
|
|||||||
BIN
test/fuzz/fuzz-bus-message/issue-23486-case-1
Normal file
BIN
test/fuzz/fuzz-bus-message/issue-23486-case-1
Normal file
Binary file not shown.
BIN
test/fuzz/fuzz-bus-message/issue-23486-case-2
Normal file
BIN
test/fuzz/fuzz-bus-message/issue-23486-case-2
Normal file
Binary file not shown.
BIN
test/fuzz/fuzz-bus-message/issue-23486-case-3
Normal file
BIN
test/fuzz/fuzz-bus-message/issue-23486-case-3
Normal file
Binary file not shown.
@ -337,6 +337,11 @@ qemu_min_version() {
|
|||||||
# Return 0 if qemu did run (then you must check the result state/logs for actual
|
# Return 0 if qemu did run (then you must check the result state/logs for actual
|
||||||
# success), or 1 if qemu is not available.
|
# success), or 1 if qemu is not available.
|
||||||
run_qemu() {
|
run_qemu() {
|
||||||
|
# If the test provided its own initrd, use it (e.g. TEST-24)
|
||||||
|
if [[ -z "$INITRD" && -f "${TESTDIR:?}/initrd.img" ]]; then
|
||||||
|
INITRD="$TESTDIR/initrd.img"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -f /etc/machine-id ]; then
|
if [ -f /etc/machine-id ]; then
|
||||||
read -r MACHINE_ID </etc/machine-id
|
read -r MACHINE_ID </etc/machine-id
|
||||||
[ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
|
[ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
|
||||||
|
|||||||
@ -73,7 +73,7 @@ def run(args):
|
|||||||
|
|
||||||
logger.info("waiting for reboot")
|
logger.info("waiting for reboot")
|
||||||
|
|
||||||
console.expect('H login: ', 10)
|
console.expect('H login: ', 30)
|
||||||
console.sendline('root')
|
console.sendline('root')
|
||||||
console.expect('bash.*# ', 10)
|
console.expect('bash.*# ', 10)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user