mirror of
https://git.proxmox.com/git/systemd
synced 2025-10-25 02:52:14 +00:00
New upstream version 251.2
This commit is contained in:
parent
5249429fa0
commit
cfd0f7785c
@ -686,7 +686,7 @@
|
||||
<varlistentry>
|
||||
<term><option>--luks-cipher=</option><replaceable>CIPHER</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-hash-algorithm=</option><replaceable>ALGORITHM</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
|
||||
<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>
|
||||
|
||||
@ -121,7 +121,7 @@
|
||||
will be stored as an EFI variable in that case, overriding this option.
|
||||
</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
|
||||
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>
|
||||
@ -211,7 +211,7 @@
|
||||
<varlistentry>
|
||||
<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>
|
||||
</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.
|
||||
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
|
||||
copied. Returns a converted <varname>errno</varname>-like, negative error code or <constant>0</constant>.
|
||||
Before this call, <parameter>dst</parameter> must be unset, i.e. either freshly initialized with
|
||||
copied. 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>
|
||||
|
||||
<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>,
|
||||
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
|
||||
@ -286,6 +291,18 @@
|
||||
to <constant>NULL</constant>. The structure may be reused afterwards.</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>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
@ -297,7 +314,8 @@
|
||||
<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
|
||||
<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
|
||||
<constant>false</constant> when <parameter>e</parameter> is
|
||||
@ -305,7 +323,9 @@
|
||||
<parameter>e->name</parameter> otherwise.</para>
|
||||
|
||||
<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
|
||||
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
|
||||
non-<constant>NULL</constant> and the <structfield>name</structfield> field is equal to one of the given
|
||||
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>
|
||||
<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>
|
||||
|
||||
<varlistentry>
|
||||
<term><constant>-EINVAL</constant></term>
|
||||
|
||||
<listitem><para>Error was already set in <structname>sd_bus_error</structname> structure when one
|
||||
the error-setting functions was called.</para></listitem>
|
||||
<listitem><para>Error was already set in the <structname>sd_bus_error</structname> structure when
|
||||
one the error-setting functions was called.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -350,9 +356,29 @@
|
||||
<listitem><para>Memory allocation failed.</para></listitem>
|
||||
</varlistentry>
|
||||
</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>
|
||||
</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" />
|
||||
|
||||
<refsect1>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>shutdown</refname>
|
||||
<refpurpose>Halt, power-off or reboot the machine</refpurpose>
|
||||
<refpurpose>Halt, power off or reboot the machine</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
@ -33,8 +33,7 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>shutdown</command> may be used to halt, power-off
|
||||
or reboot the machine.</para>
|
||||
<para><command>shutdown</command> may be used to halt, power off, or reboot the machine.</para>
|
||||
|
||||
<para>The first argument may be a time string (which is usually
|
||||
<literal>now</literal>). Optionally, this may be followed by a
|
||||
@ -81,47 +80,41 @@
|
||||
<term><option>-P</option></term>
|
||||
<term><option>--poweroff</option></term>
|
||||
|
||||
<listitem><para>Power-off the machine (the
|
||||
default).</para></listitem>
|
||||
<listitem><para>Power the machine off (the default).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-r</option></term>
|
||||
<term><option>--reboot</option></term>
|
||||
|
||||
<listitem><para>Reboot the
|
||||
machine.</para></listitem>
|
||||
<listitem><para>Reboot the machine.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
|
||||
<listitem><para>Equivalent to <option>--poweroff</option>,
|
||||
unless <option>--halt</option> is specified.</para></listitem>
|
||||
<listitem><para>The same as <option>--poweroff</option>, but does not override the action to take if
|
||||
it is "halt". E.g. <command>shutdown --reboot -h</command> means "poweroff", but <command>shutdown
|
||||
--halt -h</command> means "halt".</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-k</option></term>
|
||||
|
||||
<listitem><para>Do not halt, power-off, reboot, just write
|
||||
wall message.</para></listitem>
|
||||
<listitem><para>Do not halt, power off, or reboot, but just write the wall message.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-wall</option></term>
|
||||
|
||||
<listitem><para>Do not send wall
|
||||
message before
|
||||
halt, power-off, reboot.</para></listitem>
|
||||
<listitem><para>Do not send wall message before halt, power off, or reboot.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-c</option></term>
|
||||
|
||||
<listitem><para>Cancel a pending shutdown. This may be used
|
||||
to cancel the effect of an invocation of
|
||||
<command>shutdown</command> with a time argument that is not
|
||||
<literal>+0</literal> or
|
||||
<listitem><para>Cancel a pending shutdown. This may be used to cancel the effect of an invocation of
|
||||
<command>shutdown</command> with a time argument that is not <literal>+0</literal> or
|
||||
<literal>now</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
<cmdsynopsis>
|
||||
<command>systemd-creds</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="plain">COMMAND</arg>
|
||||
<arg choice="opt" rep="repeat">ARGS</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
@ -26,10 +26,9 @@
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para>A unit configuration file whose name ends in
|
||||
<literal>.automount</literal> encodes information about a file
|
||||
system automount point controlled and supervised by
|
||||
systemd.</para>
|
||||
<para>A unit configuration file whose name ends in <literal>.automount</literal> encodes information
|
||||
about a file system automount point controlled and supervised by systemd. Automount units may be used to
|
||||
implement on-demand mounting as well as parallelized mounting of file systems.</para>
|
||||
|
||||
<para>This man page lists the configuration options specific to
|
||||
this unit type. See
|
||||
@ -55,9 +54,6 @@
|
||||
accesses <filename>/home/lennart</filename> the mount unit
|
||||
<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
|
||||
should not set <varname>After=</varname> or <varname>Requires=</varname>
|
||||
for mount dependencies here. For example, you should not set
|
||||
@ -65,8 +61,11 @@
|
||||
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
|
||||
system service manager (and root's user service manager), but not in unprivileged user's service
|
||||
manager.</para>
|
||||
system service manager (and root's user service manager), but not in unprivileged users' service
|
||||
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>
|
||||
@ -78,12 +77,12 @@
|
||||
<para>The following dependencies are implicitly added:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>If an automount unit is beneath another mount unit in the
|
||||
file system hierarchy, both a requirement and an ordering
|
||||
dependency between both units are created automatically.</para></listitem>
|
||||
<listitem><para>If an automount unit is beneath another mount unit in the file system hierarchy, a
|
||||
requirement and ordering dependencies are created to the on the unit higher in the hierarchy.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>An implicit <varname>Before=</varname> dependency is created
|
||||
between an automount unit and the mount unit it activates.</para></listitem>
|
||||
<listitem><para>An implicit <varname>Before=</varname> dependency is created between an automount
|
||||
unit and the mount unit it activates.</para></listitem>
|
||||
</itemizedlist>
|
||||
</refsect2>
|
||||
|
||||
@ -161,6 +160,7 @@
|
||||
creating these directories. Takes an access mode in octal
|
||||
notation. Defaults to 0755.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>TimeoutIdleSec=</varname></term>
|
||||
<listitem><para>Configures an idle timeout. Once the mount has been
|
||||
|
||||
@ -357,20 +357,29 @@ int cg_kill(
|
||||
Set *s,
|
||||
cg_kill_log_func_t log_kill,
|
||||
void *userdata) {
|
||||
int r;
|
||||
|
||||
int r, ret;
|
||||
|
||||
r = cg_kill_items(controller, path, sig, flags, s, log_kill, userdata, "cgroup.procs");
|
||||
if (r < 0 || sig != SIGKILL)
|
||||
return r;
|
||||
|
||||
ret = r;
|
||||
|
||||
/* 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
|
||||
(4340d175b898) and 4.14.138 (feb6b123b7dd). */
|
||||
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 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) {
|
||||
|
||||
@ -543,7 +543,7 @@ int bpf_firewall_compile(Unit *u) {
|
||||
return supported;
|
||||
if (supported == BPF_FIREWALL_UNSUPPORTED)
|
||||
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 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
|
||||
@ -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
|
||||
* all, either. */
|
||||
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
|
||||
* 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
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);
|
||||
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));
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(u, r, "Can't add program to BPF program set: %m");
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -645,7 +645,8 @@ int bpf_firewall_load_custom(Unit *u) {
|
||||
return supported;
|
||||
|
||||
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);
|
||||
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) {
|
||||
r = bpf_program_cgroup_attach(prog, attach_type, path, BPF_F_ALLOW_MULTI);
|
||||
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;
|
||||
}
|
||||
@ -697,16 +698,19 @@ int bpf_firewall_install(Unit *u) {
|
||||
if (supported < 0)
|
||||
return supported;
|
||||
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)
|
||||
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 &&
|
||||
(!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);
|
||||
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;
|
||||
|
||||
@ -728,7 +732,8 @@ int bpf_firewall_install(Unit *u) {
|
||||
if (u->ip_bpf_egress) {
|
||||
r = bpf_program_cgroup_attach(u->ip_bpf_egress, BPF_CGROUP_INET_EGRESS, path, flags);
|
||||
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. */
|
||||
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) {
|
||||
r = bpf_program_cgroup_attach(u->ip_bpf_ingress, BPF_CGROUP_INET_INGRESS, path, flags);
|
||||
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);
|
||||
}
|
||||
@ -824,11 +830,11 @@ int bpf_firewall_supported(void) {
|
||||
|
||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
||||
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) {
|
||||
bpf_firewall_unsupported_reason =
|
||||
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;
|
||||
}
|
||||
|
||||
@ -836,21 +842,21 @@ int bpf_firewall_supported(void) {
|
||||
r = bpf_program_new(BPF_PROG_TYPE_CGROUP_SKB, NULL, &program);
|
||||
if (r < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
r = bpf_program_add_instructions(program, trivial, ELEMENTSOF(trivial));
|
||||
if (r < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
r = bpf_program_load_kernel(program, NULL, 0);
|
||||
if (r < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -874,7 +880,7 @@ int bpf_firewall_supported(void) {
|
||||
if (bpf(BPF_PROG_DETACH, &attr, sizeof(attr)) < 0) {
|
||||
if (errno != EBADF) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -882,7 +888,7 @@ int bpf_firewall_supported(void) {
|
||||
} else {
|
||||
bpf_firewall_unsupported_reason =
|
||||
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.");
|
||||
return supported = BPF_FIREWALL_UNSUPPORTED;
|
||||
}
|
||||
@ -902,20 +908,20 @@ int bpf_firewall_supported(void) {
|
||||
|
||||
if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
} else {
|
||||
bpf_firewall_unsupported_reason =
|
||||
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.");
|
||||
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) {
|
||||
r = bpf_program_cgroup_attach(prog, key->attach_type, path, attach_flags);
|
||||
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;
|
||||
@ -89,31 +89,31 @@ static int bpf_foreign_prepare(
|
||||
r = path_is_fs_type(bpffs_path, BPF_FS_MAGIC);
|
||||
if (r < 0)
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
if (r < 0)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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(prog);
|
||||
@ -134,17 +134,17 @@ int bpf_foreign_install(Unit *u) {
|
||||
|
||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, NULL, &cgroup_path);
|
||||
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) {
|
||||
r = bpf_foreign_prepare(u, p->attach_type, p->bpffs_path);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
/* libbpf, clang and llc compile time dependencies are satisfied */
|
||||
#include "bpf-dlopen.h"
|
||||
#include "bpf-link.h"
|
||||
#include "bpf-util.h"
|
||||
#include "bpf/restrict_fs/restrict-fs-skel.h"
|
||||
|
||||
#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();
|
||||
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? */
|
||||
r = sym_bpf_map__resize(obj->maps.cgroup_hash, CGROUP_HASH_SIZE_MAX);
|
||||
assert(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));
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
assert(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);
|
||||
assert(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);
|
||||
|
||||
@ -103,7 +104,7 @@ static int mac_bpf_use(void) {
|
||||
r = read_one_line_file("/sys/kernel/security/lsm", &lsm_list);
|
||||
if (r < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -116,7 +117,7 @@ static int mac_bpf_use(void) {
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
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;
|
||||
}
|
||||
|
||||
@ -135,33 +136,18 @@ bool lsm_bpf_supported(bool initialize) {
|
||||
if (!initialize)
|
||||
return false;
|
||||
|
||||
r = dlopen_bpf();
|
||||
if (r < 0) {
|
||||
log_info_errno(r, "Failed to open libbpf, LSM BPF is not supported: %m");
|
||||
if (!cgroup_bpf_supported())
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
if (r == 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -171,7 +157,7 @@ bool lsm_bpf_supported(bool initialize) {
|
||||
|
||||
if (!bpf_can_link_lsm_program(obj->progs.restrict_filesystems)) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -192,10 +178,10 @@ int lsm_bpf_setup(Manager *m) {
|
||||
link = sym_bpf_program__attach_lsm(obj->progs.restrict_filesystems);
|
||||
r = sym_libbpf_get_error(link);
|
||||
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));
|
||||
|
||||
log_info("LSM BPF program attached");
|
||||
log_info("bpf-lsm: LSM BPF program attached");
|
||||
|
||||
obj->links.restrict_filesystems = TAKE_PTR(link);
|
||||
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)
|
||||
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(
|
||||
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 */
|
||||
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);
|
||||
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)
|
||||
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;
|
||||
|
||||
/* 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)
|
||||
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) {
|
||||
r = fs_type_from_string(fs, &magic);
|
||||
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;
|
||||
}
|
||||
|
||||
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++) {
|
||||
if (magic[i] == 0)
|
||||
break;
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
@ -278,10 +264,10 @@ int lsm_bpf_cleanup(const Unit *u) {
|
||||
|
||||
int fd = sym_bpf_map__fd(u->manager->restrict_fs->maps.cgroup_hash);
|
||||
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)
|
||||
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;
|
||||
}
|
||||
@ -305,11 +291,11 @@ bool lsm_bpf_supported(bool initialize) {
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
@ -344,7 +330,7 @@ int lsm_bpf_parse_filesystem(
|
||||
set = filesystem_set_find(name);
|
||||
if (!set) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -11,8 +11,9 @@
|
||||
/* libbpf, clang, llvm and bpftool compile time dependencies are satisfied */
|
||||
#include "bpf-dlopen.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-skel.h"
|
||||
|
||||
static struct socket_bind_bpf *socket_bind_bpf_free(struct socket_bind_bpf *obj) {
|
||||
/* 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)
|
||||
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)
|
||||
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();
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
assert(allow_map_fd >= 0);
|
||||
@ -96,7 +97,7 @@ static int prepare_socket_bind_bpf(
|
||||
r = update_rules_map(allow_map_fd, allow);
|
||||
if (r < 0)
|
||||
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));
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
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));
|
||||
|
||||
*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;
|
||||
int r;
|
||||
|
||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
||||
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)
|
||||
if (!cgroup_bpf_supported())
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
r = prepare_socket_bind_bpf(/*unit=*/NULL, /*allow_rules=*/NULL, /*deny_rules=*/NULL, &obj);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
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;
|
||||
}
|
||||
@ -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);
|
||||
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)
|
||||
return 0;
|
||||
|
||||
r = prepare_socket_bind_bpf(u, cc->socket_bind_allow, cc->socket_bind_deny, &obj);
|
||||
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);
|
||||
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);
|
||||
r = sym_libbpf_get_error(ipv4);
|
||||
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));
|
||||
|
||||
ipv6 = sym_bpf_program__attach_cgroup(obj->progs.sd_bind6, cgroup_fd);
|
||||
r = sym_libbpf_get_error(ipv6);
|
||||
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));
|
||||
|
||||
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) {
|
||||
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) {
|
||||
|
||||
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);
|
||||
|
||||
/* First, let's put the deserialized state and found mask into effect, if we have it. */
|
||||
|
||||
if (d->deserialized_state < 0 ||
|
||||
(d->deserialized_state == d->state &&
|
||||
d->deserialized_found == d->found))
|
||||
if (d->deserialized_state < 0)
|
||||
return 0;
|
||||
|
||||
d->found = d->deserialized_found;
|
||||
device_set_state(d, d->deserialized_state);
|
||||
Manager *m = u->manager;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
Manager *m;
|
||||
|
||||
assert(d);
|
||||
|
||||
m = UNIT(d)->manager;
|
||||
|
||||
if (MANAGER_IS_RUNNING(m) && (m->honor_device_enumeration || MANAGER_IS_USER(m))) {
|
||||
if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
|
||||
DeviceFound n, previous;
|
||||
|
||||
/* When we are already running, then apply the new mask right-away, and trigger state changes
|
||||
|
||||
@ -135,6 +135,13 @@ libcore_sources = '''
|
||||
unit.h
|
||||
'''.split()
|
||||
|
||||
if conf.get('BPF_FRAMEWORK') == 1
|
||||
libcore_sources += files(
|
||||
'bpf-util.c',
|
||||
'bpf-util.h',
|
||||
)
|
||||
endif
|
||||
|
||||
subdir('bpf')
|
||||
|
||||
subdir('bpf/socket_bind')
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
|
||||
#include "bpf-dlopen.h"
|
||||
#include "bpf-link.h"
|
||||
|
||||
#include "bpf-util.h"
|
||||
#include "bpf/restrict_ifaces/restrict-ifaces-skel.h"
|
||||
|
||||
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();
|
||||
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));
|
||||
if (r != 0)
|
||||
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));
|
||||
|
||||
obj->rodata->is_allow_list = is_allow_list;
|
||||
|
||||
r = restrict_ifaces_bpf__load(obj);
|
||||
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);
|
||||
|
||||
@ -56,13 +56,15 @@ static int prepare_restrict_ifaces_bpf(
|
||||
|
||||
ifindex = rtnl_resolve_interface(&rtnl, iface);
|
||||
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;
|
||||
}
|
||||
|
||||
if (sym_bpf_map_update_elem(map_fd, &ifindex, &dummy, BPF_ANY))
|
||||
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));
|
||||
}
|
||||
|
||||
@ -78,29 +80,21 @@ int restrict_network_interfaces_supported(void) {
|
||||
if (supported >= 0)
|
||||
return supported;
|
||||
|
||||
r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
|
||||
if (r < 0)
|
||||
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 (!cgroup_bpf_supported())
|
||||
return (supported = false);
|
||||
|
||||
if (!sym_bpf_probe_prog_type(BPF_PROG_TYPE_CGROUP_SKB, /*ifindex=*/0)) {
|
||||
log_debug("BPF program type cgroup_skb is not supported");
|
||||
return supported = 0;
|
||||
log_debug("restrict-interfaces: BPF program type cgroup_skb is not supported");
|
||||
return (supported = false);
|
||||
}
|
||||
|
||||
r = prepare_restrict_ifaces_bpf(NULL, true, NULL, &obj);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to load BPF object: %m");
|
||||
return supported = 0;
|
||||
log_debug_errno(r, "restrict-interfaces: Failed to load BPF object: %m");
|
||||
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) {
|
||||
@ -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);
|
||||
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)
|
||||
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);
|
||||
r = sym_libbpf_get_error(ingress_link);
|
||||
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);
|
||||
r = sym_libbpf_get_error(egress_link);
|
||||
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_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);
|
||||
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;
|
||||
}
|
||||
@ -192,7 +187,7 @@ int restrict_network_interfaces_supported(void) {
|
||||
|
||||
int restrict_network_interfaces_install(Unit *u) {
|
||||
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) {
|
||||
|
||||
@ -47,6 +47,20 @@
|
||||
# define SWAP64(n) (n)
|
||||
#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
|
||||
64-byte boundary. (FIPS 180-2:5.1.1) */
|
||||
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
|
||||
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. */
|
||||
prolog according to the standard and write the result to RESBUF. */
|
||||
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
|
||||
/* Take yet unprocessed bytes into account. */
|
||||
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. */
|
||||
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;
|
||||
}
|
||||
@ -156,17 +170,6 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx
|
||||
|
||||
/* Process available complete blocks. */
|
||||
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))
|
||||
while (len > 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;
|
||||
len -= 64;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
else {
|
||||
sha256_process_block(buffer, len & ~63, ctx);
|
||||
buffer = (const char *) buffer + (len & ~63);
|
||||
len &= 63;
|
||||
|
||||
@ -80,12 +80,13 @@ fi
|
||||
|
||||
if [ "${0##*/}" = "installkernel" ]; then
|
||||
COMMAND=add
|
||||
# make install doesn't pass any initrds
|
||||
no_initrds=1
|
||||
# kernel's install.sh invokes us as
|
||||
# /sbin/installkernel <version> <vmlinuz> <map> <installation-dir>
|
||||
# We ignore the last two arguments.
|
||||
set -- "$1"
|
||||
else
|
||||
COMMAND="$1"
|
||||
[ $# -ge 1 ] && shift
|
||||
no_initrds=0
|
||||
fi
|
||||
|
||||
if [ "$COMMAND" = "inspect" ]; then
|
||||
@ -320,16 +321,8 @@ case "$COMMAND" in
|
||||
fi
|
||||
|
||||
for f in $PLUGINS; do
|
||||
if [ "$no_initrds" = 1 ]; then
|
||||
# kernel's install.sh invokes us as
|
||||
# /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
|
||||
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS" "$@"
|
||||
"$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$@"
|
||||
|
||||
err=$?
|
||||
[ $err -eq $skip_remaining ] && break
|
||||
@ -362,8 +355,8 @@ case "$COMMAND" in
|
||||
|
||||
# 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; }
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Error: unknown command '$COMMAND'" >&2
|
||||
exit 1
|
||||
|
||||
@ -222,7 +222,8 @@ tests += [
|
||||
libglib,
|
||||
libgobject,
|
||||
libgio,
|
||||
libdbus]],
|
||||
libdbus,
|
||||
libm]],
|
||||
|
||||
[files('sd-bus/test-bus-signature.c'),
|
||||
[],
|
||||
|
||||
@ -428,7 +428,7 @@ int bus_message_from_header(
|
||||
|
||||
_cleanup_free_ sd_bus_message *m = NULL;
|
||||
struct bus_header *h;
|
||||
size_t a, label_sz;
|
||||
size_t a, label_sz = 0; /* avoid false maybe-uninitialized warning */
|
||||
|
||||
assert(bus);
|
||||
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->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;
|
||||
}
|
||||
|
||||
@ -3061,15 +3064,21 @@ void bus_body_part_unmap(struct bus_body_part *part) {
|
||||
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;
|
||||
|
||||
assert(rindex);
|
||||
assert(align > 0);
|
||||
|
||||
start = ALIGN_TO((size_t) *rindex, align);
|
||||
end = start + nbytes;
|
||||
start = ALIGN_TO(*rindex, align);
|
||||
if (start > sz)
|
||||
return -EBADMSG;
|
||||
|
||||
/* Avoid overflow below */
|
||||
if (nbytes > SIZE_MAX - start)
|
||||
return -EBADMSG;
|
||||
|
||||
end = start + nbytes;
|
||||
if (end > sz)
|
||||
return -EBADMSG;
|
||||
|
||||
@ -3272,10 +3281,17 @@ static int message_peek_body(
|
||||
assert(rindex);
|
||||
assert(align > 0);
|
||||
|
||||
start = ALIGN_TO((size_t) *rindex, align);
|
||||
padding = start - *rindex;
|
||||
end = start + nbytes;
|
||||
start = ALIGN_TO(*rindex, align);
|
||||
if (start > m->user_body_size)
|
||||
return -EBADMSG;
|
||||
|
||||
padding = start - *rindex;
|
||||
|
||||
/* Avoid overflow below */
|
||||
if (nbytes > SIZE_MAX - start)
|
||||
return -EBADMSG;
|
||||
|
||||
end = start + nbytes;
|
||||
if (end > m->user_body_size)
|
||||
return -EBADMSG;
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "def.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
@ -2342,8 +2342,6 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
|
||||
if (r == 0)
|
||||
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) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = 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);
|
||||
}
|
||||
|
||||
reset_scheduled_shutdown(m);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool logind_wall_tty_filter(const char *tty, void *userdata) {
|
||||
Manager *m = userdata;
|
||||
const char *p;
|
||||
bool logind_wall_tty_filter(const char *tty, bool is_local, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
assert(m);
|
||||
assert(m->scheduled_shutdown_action);
|
||||
|
||||
if (!m->scheduled_shutdown_tty)
|
||||
return true;
|
||||
|
||||
p = path_startswith(tty, "/dev/");
|
||||
const char *p = path_startswith(tty, "/dev/");
|
||||
if (!p)
|
||||
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) {
|
||||
|
||||
@ -180,6 +180,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_n_autovts);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs_size);
|
||||
|
||||
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);
|
||||
|
||||
@ -528,18 +528,26 @@ static int dns_stub_send(
|
||||
if (s)
|
||||
r = dns_stream_write_packet(s, reply);
|
||||
else {
|
||||
int fd;
|
||||
int fd, ifindex;
|
||||
|
||||
fd = find_socket_fd(m, l, p->family, &p->sender, SOCK_DGRAM);
|
||||
if (fd < 0)
|
||||
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
|
||||
* 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,
|
||||
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,
|
||||
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_lsm)(struct bpf_program *);
|
||||
long (*sym_libbpf_get_error)(const void *);
|
||||
int (*sym_bpf_link__fd)(const struct bpf_link *);
|
||||
int (*sym_bpf_link__destroy)(struct bpf_link *);
|
||||
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 *);
|
||||
bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
||||
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) {
|
||||
return dlopen_many_sym_or_warn(
|
||||
int r;
|
||||
|
||||
r = dlopen_many_sym_or_warn(
|
||||
&bpf_dl, "libbpf.so.0", LOG_DEBUG,
|
||||
DLSYM_ARG(bpf_link__destroy),
|
||||
DLSYM_ARG(bpf_link__fd),
|
||||
@ -48,7 +65,14 @@ int dlopen_bpf(void) {
|
||||
DLSYM_ARG(bpf_program__attach_cgroup),
|
||||
DLSYM_ARG(bpf_program__attach_lsm),
|
||||
DLSYM_ARG(bpf_program__name),
|
||||
DLSYM_ARG(libbpf_set_print),
|
||||
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
|
||||
|
||||
@ -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_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__destroy)(struct bpf_link *);
|
||||
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 bool (*sym_bpf_probe_prog_type)(enum bpf_prog_type, __u32);
|
||||
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
|
||||
|
||||
|
||||
@ -571,7 +571,11 @@ static int verify_xbootldr_udev(
|
||||
r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
|
||||
if (r < 0)
|
||||
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,
|
||||
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
|
||||
"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))
|
||||
return r;
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
@ -337,7 +337,7 @@ int utmp_wall(
|
||||
const char *message,
|
||||
const char *username,
|
||||
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) {
|
||||
|
||||
_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)
|
||||
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/"))
|
||||
path = u->ut_line;
|
||||
else {
|
||||
if (asprintf(&buf, "/dev/%.*s", (int) sizeof(u->ut_line), u->ut_line) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
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);
|
||||
if (q < 0)
|
||||
r = q;
|
||||
|
||||
@ -23,7 +23,7 @@ int utmp_wall(
|
||||
const char *message,
|
||||
const char *username,
|
||||
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);
|
||||
|
||||
static inline bool utxent_start(void) {
|
||||
|
||||
@ -211,7 +211,9 @@ tests += [
|
||||
|
||||
[files('test-mkdir.c')],
|
||||
|
||||
[files('test-json.c')],
|
||||
[files('test-json.c'),
|
||||
[],
|
||||
[libm]],
|
||||
|
||||
[files('test-modhex.c')],
|
||||
|
||||
@ -275,7 +277,9 @@ tests += [
|
||||
|
||||
[files('test-parse-helpers.c')],
|
||||
|
||||
[files('test-parse-util.c')],
|
||||
[files('test-parse-util.c'),
|
||||
[],
|
||||
[libm]],
|
||||
|
||||
[files('test-sysctl-util.c')],
|
||||
|
||||
@ -664,6 +668,8 @@ tests += [
|
||||
[], [], [], 'ENABLE_NSCD', 'manual'],
|
||||
|
||||
[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__);
|
||||
return;
|
||||
}
|
||||
if (!have_seccomp_privs()) {
|
||||
if (!have_seccomp_privs() || have_effective_cap(CAP_IPC_OWNER) <= 0) {
|
||||
log_notice("Not privileged, skipping %s", __func__);
|
||||
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;
|
||||
}
|
||||
|
||||
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_close_ int fd = -1;
|
||||
struct stat st;
|
||||
|
||||
@ -556,7 +556,7 @@ static int run(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Parent already died?");
|
||||
|
||||
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);
|
||||
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) {
|
||||
/* 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]);
|
||||
|
||||
@ -10,6 +10,11 @@ TEST_FORCE_NEWIMAGE=1
|
||||
# shellcheck source=test/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() {
|
||||
local ret=1
|
||||
|
||||
@ -17,13 +22,13 @@ check_result_qemu() {
|
||||
[[ -e "${initdir:?}/testok" ]] && ret=0
|
||||
[[ -f "$initdir/failed" ]] && cp -a "$initdir/failed" "${TESTDIR:?}"
|
||||
|
||||
cryptsetup luksOpen "${LOOPDEV:?}p2" varcrypt <"$TESTDIR/keyfile"
|
||||
mount /dev/mapper/varcrypt "$initdir/var"
|
||||
cryptsetup luksOpen "${LOOPDEV:?}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile"
|
||||
mount "/dev/mapper/$DM_NAME" "$initdir/var"
|
||||
save_journal "$initdir/var/log/journal"
|
||||
check_coverage_reports "${initdir:?}" || ret=5
|
||||
_umount_dir "$initdir/var"
|
||||
_umount_dir "$initdir"
|
||||
cryptsetup luksClose /dev/mapper/varcrypt
|
||||
cryptsetup luksClose "/dev/mapper/$DM_NAME"
|
||||
|
||||
[[ -f "$TESTDIR/failed" ]] && cat "$TESTDIR/failed"
|
||||
echo "${JOURNAL_LIST:-No journals were saved}"
|
||||
@ -36,45 +41,65 @@ test_create_image() {
|
||||
create_empty_image_rootdir
|
||||
|
||||
echo -n test >"${TESTDIR:?}/keyfile"
|
||||
cryptsetup -q luksFormat --pbkdf pbkdf2 --pbkdf-force-iterations 1000 "${LOOPDEV:?}p2" "$TESTDIR/keyfile"
|
||||
cryptsetup luksOpen "${LOOPDEV}p2" varcrypt <"$TESTDIR/keyfile"
|
||||
mkfs.ext4 -L var /dev/mapper/varcrypt
|
||||
cryptsetup -q luksFormat --uuid="$PART_UUID" --pbkdf pbkdf2 --pbkdf-force-iterations 1000 "${LOOPDEV:?}p2" "$TESTDIR/keyfile"
|
||||
cryptsetup luksOpen "${LOOPDEV}p2" "${DM_NAME:?}" <"$TESTDIR/keyfile"
|
||||
mkfs.ext4 -L var "/dev/mapper/$DM_NAME"
|
||||
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
|
||||
# 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")
|
||||
LOG_LEVEL=5
|
||||
|
||||
setup_basic_environment
|
||||
mask_supporting_services
|
||||
setup_basic_environment
|
||||
mask_supporting_services
|
||||
|
||||
install_dmevent
|
||||
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"
|
||||
install_dmevent
|
||||
generate_module_dependencies
|
||||
|
||||
cat >>"$initdir/etc/fstab" <<EOF
|
||||
/dev/mapper/varcrypt /var ext4 defaults 0 1
|
||||
# Create a keydev
|
||||
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
|
||||
|
||||
# Forward journal messages to the console, so we have something
|
||||
# to investigate even if we fail to mount the encrypted /var
|
||||
echo ForwardToConsole=yes >> "$initdir/etc/systemd/journald.conf"
|
||||
)
|
||||
# Forward journal messages to the console, so we have something
|
||||
# to investigate even if we fail to mount the encrypted /var
|
||||
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() {
|
||||
ddebug "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() {
|
||||
|
||||
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
|
||||
# success), or 1 if qemu is not available.
|
||||
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
|
||||
read -r MACHINE_ID </etc/machine-id
|
||||
[ -z "$INITRD" ] && [ -e "$EFI_MOUNT/$MACHINE_ID/$KERNEL_VER/initrd" ] \
|
||||
|
||||
@ -73,7 +73,7 @@ def run(args):
|
||||
|
||||
logger.info("waiting for reboot")
|
||||
|
||||
console.expect('H login: ', 10)
|
||||
console.expect('H login: ', 30)
|
||||
console.sendline('root')
|
||||
console.expect('bash.*# ', 10)
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user