1
0
mirror of https://github.com/systemd/systemd synced 2025-11-22 02:04:45 +01:00

Compare commits

...

20 Commits

Author SHA1 Message Date
Sebastian Gross
582a1e1877 network-generator: ip: do not fail on ntp value
linux https://www.kernel.org/doc/html/latest/admin-guide/nfs/nfsroot.html
states `ntp0-ip` as parameter to `ip=` command line.

Until now systemd-network-generator would fail if ntp was provided with
-EINVAL due to trailing arguments.

Stay in line with kernel doc and handle ntp value properly.
2025-09-26 21:11:11 +09:00
Daan De Meyer
4feade85d7
dissect: Add more debug logging (#39125) 2025-09-26 11:53:35 +02:00
Daan De Meyer
f9b46986e1 dissect: Add more debug logging 2025-09-26 11:53:05 +02:00
Daan De Meyer
677785c8f8 ssh-proxy: Add support for per user machined
Let's check both the per user machined and the system machined instead
of only the system machined. We give preference to the per user machined
and fall back to the system machined.
2025-09-26 11:13:32 +02:00
Lennart Poettering
bd4c39a384
mute console kernel log/pid1 status output while firstboot is running (#39101)
This is also preparation for the installer later, split out of #38764.
It makes the experience a lot nicer if our nice little tools aren't
constantly interrupted by log spew from the kernel.

Fixes: #34448
2025-09-26 11:12:24 +02:00
Lennart Poettering
83b6ef9b62 libselinux: turn into dlopen() dep 2025-09-26 11:12:04 +02:00
Lennart Poettering
26cde6f0ce update TODO 2025-09-26 10:03:12 +02:00
Itxaka
1e9c9773b9 Parse a new profile key in Type 1 boot entries
This allows Type 1 entries to take advantage of multiprofile efi files
by allowing the configuration of the profile associated with that entry.

It will now parse the profile key in a Type 1 config to select that
profile when booting that efi file instead of relaying in the cmdline

Signed-off-by: Itxaka <itxaka@kairos.io>
2025-09-26 10:00:43 +02:00
Lennart Poettering
971637c47d firstboot: get rid of pointless strjoina() 2025-09-26 09:43:45 +02:00
Lennart Poettering
82a48eb1db test: add simple test case for mute-console service 2025-09-26 09:42:13 +02:00
Lennart Poettering
2eb0820d86 varlinkctl: send READY=1 for --more calls once we received first reply 2025-09-26 09:42:13 +02:00
Lennart Poettering
0d2cc656c8 firstboot: mute console while running on the console at boot
Fixes: #34448
2025-09-26 09:42:13 +02:00
Lennart Poettering
40e742be3c prompt-util: add client helper for muting the console 2025-09-26 09:42:13 +02:00
Lennart Poettering
ac63a04bd6 mute-console: add simple varlink service that can disable log/status spew to kernel console
For "wizard" style interactive tools it's very annoying if they are
interrupted by kernel log output or PID1's status output. let's add some
infra to disable this temporarily. I decided to implement this as an IPC
service so that we can make this robust: if the client request the
muting dies we can automatically unmute again.

This is hence a tiny varlink service, but it can also be started
directly from the cmdline.
2025-09-26 09:42:13 +02:00
Lennart Poettering
45c04464dc shutdown: move printk changing code int generic code 2025-09-26 09:39:00 +02:00
Daan De Meyer
a93593df2f dissect: Add full stop to debug log messages in dissect_image() 2025-09-26 09:26:06 +02:00
Yu Watanabe
97940e77a9 mkosi: bump fedora from 42 to 43
It seems
- the address sanitizer on fedora 42 reports false-positive, or
- probing partitions in libblkid 2.40.4 has a bug.

Not sure which causes the issue, but anyway the address sanitizer
kills udev-worker when sym_blkid_partition_get_name() is called
in udev-builtin-blkid.c.
```
systemd-udevd[488]: ==488==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7ffdd716e020 at pc 0x563e3ca66fcb bp 0x7ffdd716d970 sp 0x7ffdd716d968
systemd-udevd[488]: READ of size 8 at 0x7ffdd716e020 thread T0 ((udev-worker))
(snip)
systemd-udevd[488]: HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
systemd-udevd[488]:       (longjmp and C++ exceptions *are* supported)
systemd-udevd[488]: SUMMARY: AddressSanitizer: stack-buffer-underflow (/usr/bin/udevadm+0x187fca) (BuildId: 1fb56dbdf0447aba1185d6e34560b782b76098be)
(snip)
systemd-udevd[488]: Command: (udev-worker)
systemd-udevd[488]: ==488==ABORTING
```

Let's bump fedora from 42 to 43.

Fixes mkosi fedora 42 job failures after c349edfe49dc2c4b8a79e5d08ecf7c8e93c4c909.
2025-09-26 09:14:13 +02:00
Anton Tiurin
59d946ee6b networkd: fia xRequiredOperationalStateForOnline serializtion
In integration tests (for example TEST-85-NETWORK-NetworkctlTests)

LINK_OPERSTATE_RANGE_INVALID and required_for_online == -1 are serialized as
```
"RequiredForOnline": "true",
"RequiredOperationalStateForOnline": [null, null]
```
Such link should be reported as required_for_online=False and not
serialize nulls.
2025-09-26 14:55:50 +09:00
Anton Tiurin
9893859beb networkctl: change bitrate format from 'bps' to 'Bps' 2025-09-26 14:41:20 +09:00
Daan De Meyer
946cc446c0 gpt: Introduce function to convert verity hash or sig to data partition
Let's rename the existing partition_verity_to_data() to
partition_verity_hash_to_data() and make a new partition_verity_to_data() that
handles both verity hash and verity signature partitions.

Rename other functions to match the new naming.
2025-09-25 20:06:11 +02:00
57 changed files with 1319 additions and 289 deletions

View File

@ -110,7 +110,7 @@ jobs:
no_kvm: 0
shim: 0
- distro: fedora
release: "42"
release: "43"
runner: ubuntu-24.04
sanitizers: address,undefined
llvm: 1

7
TODO
View File

@ -1772,11 +1772,6 @@ Features:
* pid1: also remove PID files of a service when the service starts, not just
when it exits
* make us use dynamically fewer deps for containers in general purpose distros:
o turn into dlopen() deps:
- libblkid (only in RootImage= handling in PID 1, but not elsewhere)
- libpam (only when called from PID 1)
* seccomp: maybe use seccomp_merge() to merge our filters per-arch if we can.
Apparently kernel performance is much better with fewer larger seccomp
filters than with more smaller seccomp filters.
@ -1798,7 +1793,7 @@ Features:
* unify on openssl:
- figure out what to do about libmicrohttpd, which has a hard dependency on
gnutls
- port fsprg over to a dlopen lib, then switch it to openssl
- port fsprg over to openssl
* add growvol and makevol options for /etc/crypttab, similar to
x-systemd.growfs and x-systemd-makefs.

View File

@ -1050,6 +1050,10 @@ manpages = [
['systemd-modules-load.service', '8', ['systemd-modules-load'], 'HAVE_KMOD'],
['systemd-mount', '1', ['systemd-umount'], ''],
['systemd-mountfsd.service', '8', ['systemd-mountfsd'], 'ENABLE_MOUNTFSD'],
['systemd-mute-console',
'1',
['systemd-mute-console.socket', 'systemd-mute-console@.service'],
''],
['systemd-network-generator.service', '8', ['systemd-network-generator'], ''],
['systemd-networkd-wait-online.service',
'8',

View File

@ -354,6 +354,16 @@
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--mute-console=</option></term>
<listitem><para>Takes a boolean argument. If true kernel log output and service manager status output
to the system console is temporarily disabled while <command>systemd-firstboot</command> is running,
so that its own output is not interrupted. Defaults to false.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>

View File

@ -0,0 +1,79 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-mute-console"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-mute-console</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-mute-console</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-mute-console</refname>
<refname>systemd-mute-console@.service</refname>
<refname>systemd-mute-console.socket</refname>
<refpurpose>Temporarily mute kernel log output and service manager status output to the system console</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>systemd-mute-console</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
</cmdsynopsis>
<para><filename>systemd-mute-console@.service</filename></para>
<para><filename>systemd-mute-console.socket</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>The <command>systemd-mute-console</command> tool and service may be used to
temporarily mute the log output of the kernel as well as the status output of the service manager to
the system console. It may be used by tools running on the console to ensure their terminal output is not
interrupted by unrelated messages.</para>
<para>The tool can be invoked directly in which case it will mute the two outputs and then issue an
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
<literal>READY=1</literal> notification once that is completed. On <constant>SIGINT</constant> or
<constant>SIGTERM</constant> output is unmuted again. Alternatively it can be invoked via Varlink
IPC.</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>The following options are understood:</para>
<variablelist>
<varlistentry>
<term><option>--kernel=<replaceable>bool</replaceable></option></term>
<term><option>--pid1=<replaceable>bool</replaceable></option></term>
<listitem><para>Individually controls which output to mute. If true is specified the respective
output is muted, if false the output is left as is. Defaults to true.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>

View File

@ -1154,6 +1154,7 @@ libselinux = dependency('libselinux',
version : '>= 2.1.9',
required : get_option('selinux'))
conf.set10('HAVE_SELINUX', libselinux.found())
libselinux_cflags = libselinux.partial_dependency(includes: true, compile_args: true)
libapparmor = dependency('libapparmor',
version : '>= 2.13',
@ -2383,6 +2384,7 @@ subdir('src/measure')
subdir('src/modules-load')
subdir('src/mount')
subdir('src/mountfsd')
subdir('src/mute-console')
subdir('src/network')
subdir('src/notify')
subdir('src/nspawn')

View File

@ -1299,6 +1299,12 @@ static void boot_entry_add_type1(
} else if (streq8(key, "sort-key")) {
free(entry->sort_key);
entry->sort_key = xstr8_to_16(value);
} else if (streq8(key, "profile")) {
uint64_t u;
if (parse_number8(value, &u, NULL) && u <= UINT_MAX)
entry->profile = (unsigned)u;
else
log_warning("Error parsing 'profile' entry option, ignoring: %s", value);
} else if (streq8(key, "version")) {
free(entry->version);

View File

@ -6111,7 +6111,7 @@ int exec_invoke(
char *exec_context = mac_selinux_context_net ?: context->selinux_context;
if (exec_context) {
r = setexeccon(exec_context);
r = sym_setexeccon_raw(exec_context);
if (r < 0) {
if (!context->selinux_context_ignore) {
*exit_status = EXIT_SELINUX_CONTEXT;

View File

@ -6124,7 +6124,7 @@ int unit_load_fragment(Unit *u) {
_cleanup_freecon_ char *selcon = NULL;
/* Cache the SELinux context of the unit file here. We'll make use of when checking access permissions to loaded units */
r = fgetfilecon_raw(fileno(f), &selcon);
r = sym_fgetfilecon_raw(fileno(f), &selcon);
if (r < 0)
log_unit_warning_errno(u, r, "Failed to read SELinux context of '%s', ignoring: %m", fragment);

View File

@ -137,7 +137,7 @@ libcore_static = static_library(
libmount_cflags,
librt,
libseccomp_cflags,
libselinux,
libselinux_cflags,
threads,
userspace],
build_by_default : false)
@ -200,7 +200,7 @@ executables += [
libapparmor_cflags,
libkmod_cflags,
libseccomp_cflags,
libselinux,
libselinux_cflags,
],
},
libexec_template + {
@ -213,7 +213,7 @@ executables += [
libapparmor_cflags,
libpam_cflags,
libseccomp_cflags,
libselinux,
libselinux_cflags,
],
},
fuzz_template + {

View File

@ -4,8 +4,6 @@
#if HAVE_SELINUX
#include <selinux/avc.h>
#include <selinux/selinux.h>
#include <unistd.h>
#include "sd-bus.h"
@ -153,7 +151,7 @@ static int access_init(sd_bus_error *error) {
if (initialized)
return 1;
if (avc_open(NULL, 0) != 0) {
if (sym_avc_open(NULL, 0) != 0) {
/* Passing errno to save original value for later */
r = log_selinux_enforcing_errno(errno, "Failed to open the SELinux AVC: %m");
if (r == 0)
@ -168,8 +166,8 @@ static int access_init(sd_bus_error *error) {
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %m");
}
selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) { .func_audit = audit_callback });
selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = log_callback });
sym_selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) { .func_audit = audit_callback });
sym_selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) { .func_log = log_callback });
initialized = true;
return 1;
@ -196,7 +194,7 @@ static int get_our_contexts(const Unit *unit, const char **ret_acon, const char
* does exactly the same - call getcon_raw(). However, it involves
* selinux_init() which opens label DB. It was not part of the
* original code. I don't want to change it for now. */
if (getcon_raw(&fcon) < 0)
if (sym_getcon_raw(&fcon) < 0)
return log_debug_errno(errno, "SELinux getcon_raw() failed: %m");
if (!fcon)
@ -226,7 +224,7 @@ static int check_access(
assert(audit_info);
assert(audit_info->function);
r = selinux_check_access(scon, tcon, tclass, permission, audit_info);
r = sym_selinux_check_access(scon, tcon, tclass, permission, audit_info);
if (r < 0) {
errno = -(r = errno_or_else(EPERM));
@ -357,7 +355,7 @@ int mac_selinux_access_check_varlink_internal(
/* We should call mac_selinux_get_peer_label() here similarly to get_our_contexts().
* See the explanation there why not. */
if (getpeercon_raw(fd, &scon) < 0)
if (sym_getpeercon_raw(fd, &scon) < 0)
return log_selinux_enforcing_errno(
errno,
"Failed to get peer SELinux context%s: %m",

View File

@ -18,13 +18,17 @@ int mac_selinux_setup(bool *loaded_policy) {
#if HAVE_SELINUX
int r;
r = dlopen_libselinux();
if (r < 0)
return log_debug_errno(r, "No SELinux library available, skipping setup: %m");
mac_selinux_disable_logging();
/* Don't load policy in the initrd if we don't appear to have it. For the real root, we check below
* if we've already loaded policy, and return gracefully. */
if (in_initrd() && access(selinux_path(), F_OK) < 0) {
if (in_initrd() && access(sym_selinux_path(), F_OK) < 0) {
if (errno != ENOENT)
log_warning_errno(errno, "Unable to check if %s exists, assuming it does not: %m", selinux_path());
log_warning_errno(errno, "Unable to check if %s exists, assuming it does not: %m", sym_selinux_path());
return 0;
}
@ -37,7 +41,7 @@ int mac_selinux_setup(bool *loaded_policy) {
* empty. SELinux guarantees this won't happen, but that file isn't specific to SELinux, and may be
* provided by some other arbitrary LSM with different semantics. */
_cleanup_freecon_ char *con = NULL;
if (getcon_raw(&con) < 0)
if (sym_getcon_raw(&con) < 0)
log_debug_errno(errno, "getcon_raw() failed, assuming SELinux is not initialized: %m");
else if (con) {
initialized = !streq(con, "kernel");
@ -50,7 +54,7 @@ int mac_selinux_setup(bool *loaded_policy) {
/* Now load the policy */
usec_t before_load = now(CLOCK_MONOTONIC);
int enforce = 0;
if (selinux_init_load_policy(&enforce) == 0) { /* NB: Apparently doesn't set useful errno! */
if (sym_selinux_init_load_policy(&enforce) == 0) { /* NB: Apparently doesn't set useful errno! */
mac_selinux_retest();
/* Transition to the new context */
@ -60,7 +64,7 @@ int mac_selinux_setup(bool *loaded_policy) {
log_open();
log_warning_errno(r, "Failed to compute init label, ignoring: %m");
} else {
r = RET_NERRNO(setcon_raw(label));
r = RET_NERRNO(sym_setcon_raw(label));
log_open();
if (r < 0)
log_warning_errno(r, "Failed to transition into init label '%s', ignoring: %m", label);

View File

@ -6,6 +6,7 @@
#include "sd-bus.h"
#include "sd-id128.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "ask-password-api.h"
@ -86,6 +87,7 @@ static bool arg_welcome = true;
static bool arg_reset = false;
static ImagePolicy *arg_image_policy = NULL;
static bool arg_chrome = true;
static bool arg_mute_console = false;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@ -99,13 +101,17 @@ STATIC_DESTRUCTOR_REGISTER(arg_root_shell, freep);
STATIC_DESTRUCTOR_REGISTER(arg_kernel_cmdline, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
static void print_welcome(int rfd) {
static void print_welcome(int rfd, sd_varlink **mute_console_link) {
_cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL;
static bool done = false;
const char *pn, *ac;
int r;
assert(rfd >= 0);
assert(mute_console_link);
if (!*mute_console_link && arg_mute_console)
(void) mute_console(mute_console_link);
if (!arg_welcome)
return;
@ -227,7 +233,7 @@ static int locale_is_ok(const char *name, void *userdata) {
return r != 0 ? locale_is_installed(name) > 0 : locale_is_valid(name);
}
static int prompt_locale(int rfd) {
static int prompt_locale(int rfd, sd_varlink **mute_console_link) {
_cleanup_strv_free_ char **locales = NULL;
bool acquired_from_creds = false;
int r;
@ -279,7 +285,7 @@ static int prompt_locale(int rfd) {
/* Not setting arg_locale_message here, since it defaults to LANG anyway */
}
} else {
print_welcome(rfd);
print_welcome(rfd, mute_console_link);
r = prompt_loop("Please enter the new system locale name or number",
GLYPH_WORLD,
@ -321,7 +327,7 @@ static int prompt_locale(int rfd) {
return 0;
}
static int process_locale(int rfd) {
static int process_locale(int rfd, sd_varlink **mute_console_link) {
_cleanup_close_ int pfd = -EBADF;
_cleanup_free_ char *f = NULL;
char* locales[3];
@ -357,7 +363,7 @@ static int process_locale(int rfd) {
}
}
r = prompt_locale(rfd);
r = prompt_locale(rfd, mute_console_link);
if (r < 0)
return r;
@ -394,7 +400,7 @@ static int keymap_is_ok(const char* name, void *userdata) {
return r != 0 ? keymap_exists(name) > 0 : keymap_is_valid(name);
}
static int prompt_keymap(int rfd) {
static int prompt_keymap(int rfd, sd_varlink **mute_console_link) {
_cleanup_strv_free_ char **kmaps = NULL;
int r;
@ -422,7 +428,7 @@ static int prompt_keymap(int rfd) {
if (r < 0)
return log_error_errno(r, "Failed to read keymaps: %m");
print_welcome(rfd);
print_welcome(rfd, mute_console_link);
return prompt_loop(
"Please enter the new keymap name or number",
@ -439,7 +445,7 @@ static int prompt_keymap(int rfd) {
&arg_keymap);
}
static int process_keymap(int rfd) {
static int process_keymap(int rfd, sd_varlink **mute_console_link) {
_cleanup_close_ int pfd = -EBADF;
_cleanup_free_ char *f = NULL;
_cleanup_strv_free_ char **keymap = NULL;
@ -474,7 +480,7 @@ static int process_keymap(int rfd) {
}
}
r = prompt_keymap(rfd);
r = prompt_keymap(rfd, mute_console_link);
if (r == -ENOENT)
return 0; /* don't fail if no keymaps are installed */
if (r < 0)
@ -508,7 +514,7 @@ static int timezone_is_ok(const char *name, void *userdata) {
return timezone_is_valid(name, LOG_DEBUG);
}
static int prompt_timezone(int rfd) {
static int prompt_timezone(int rfd, sd_varlink **mute_console_link) {
_cleanup_strv_free_ char **zones = NULL;
int r;
@ -534,7 +540,7 @@ static int prompt_timezone(int rfd) {
if (r < 0)
return log_error_errno(r, "Cannot query timezone list: %m");
print_welcome(rfd);
print_welcome(rfd, mute_console_link);
return prompt_loop(
"Please enter the new timezone name or number",
@ -551,7 +557,7 @@ static int prompt_timezone(int rfd) {
&arg_timezone);
}
static int process_timezone(int rfd) {
static int process_timezone(int rfd, sd_varlink **mute_console_link) {
_cleanup_close_ int pfd = -EBADF;
_cleanup_free_ char *f = NULL, *relpath = NULL;
const char *e;
@ -592,7 +598,7 @@ static int process_timezone(int rfd) {
}
}
r = prompt_timezone(rfd);
r = prompt_timezone(rfd, mute_console_link);
if (r < 0)
return r;
@ -616,7 +622,7 @@ static int hostname_is_ok(const char *name, void *userdata) {
return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
}
static int prompt_hostname(int rfd) {
static int prompt_hostname(int rfd, sd_varlink **mute_console_link) {
int r;
assert(rfd >= 0);
@ -629,7 +635,7 @@ static int prompt_hostname(int rfd) {
return 0;
}
print_welcome(rfd);
print_welcome(rfd, mute_console_link);
r = prompt_loop("Please enter the new hostname",
GLYPH_LABEL,
@ -652,7 +658,7 @@ static int prompt_hostname(int rfd) {
return 0;
}
static int process_hostname(int rfd) {
static int process_hostname(int rfd, sd_varlink **mute_console_link) {
_cleanup_close_ int pfd = -EBADF;
_cleanup_free_ char *f = NULL;
int r;
@ -671,7 +677,7 @@ static int process_hostname(int rfd) {
if (r <= 0)
return r;
r = prompt_hostname(rfd);
r = prompt_hostname(rfd, mute_console_link);
if (r < 0)
return r;
@ -720,7 +726,7 @@ static int process_machine_id(int rfd) {
return 0;
}
static int prompt_root_password(int rfd) {
static int prompt_root_password(int rfd, sd_varlink **mute_console_link) {
const char *msg1, *msg2;
int r;
@ -737,10 +743,10 @@ static int prompt_root_password(int rfd) {
return 0;
}
print_welcome(rfd);
print_welcome(rfd, mute_console_link);
msg1 = strjoina("Please enter the new root password (empty to skip):");
msg2 = strjoina("Please enter the new root password again:");
msg1 = "Please enter the new root password (empty to skip):";
msg2 = "Please enter the new root password again:";
suggest_passwords();
@ -817,7 +823,7 @@ static int shell_is_ok(const char *path, void *userdata) {
return find_shell(rfd, path) >= 0;
}
static int prompt_root_shell(int rfd) {
static int prompt_root_shell(int rfd, sd_varlink **mute_console_link) {
int r;
assert(rfd >= 0);
@ -838,7 +844,7 @@ static int prompt_root_shell(int rfd) {
return 0;
}
print_welcome(rfd);
print_welcome(rfd, mute_console_link);
return prompt_loop(
"Please enter the new root shell",
@ -1005,7 +1011,7 @@ static int write_root_shadow(int etc_fd, const char *hashed_password) {
return 0;
}
static int process_root_account(int rfd) {
static int process_root_account(int rfd, sd_varlink **mute_console_link) {
_cleanup_close_ int pfd = -EBADF;
_cleanup_(release_lock_file) LockFile lock = LOCK_FILE_INIT;
_cleanup_(erase_and_freep) char *_hashed_password = NULL;
@ -1059,7 +1065,7 @@ static int process_root_account(int rfd) {
return log_oom();
}
r = prompt_root_shell(rfd);
r = prompt_root_shell(rfd, mute_console_link);
if (r < 0)
return r;
@ -1078,7 +1084,7 @@ static int process_root_account(int rfd) {
arg_root_password_is_hashed = true;
}
r = prompt_root_password(rfd);
r = prompt_root_password(rfd, mute_console_link);
if (r < 0)
return r;
@ -1246,6 +1252,8 @@ static int help(void) {
" --welcome=no Disable the welcome text\n"
" --chrome=no Don't show color bar at top and bottom of\n"
" terminal\n"
" --mute-console=yes Tell kernel/PID 1 to not write to the console\n"
" while running\n"
" --reset Remove existing files\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
@ -1293,6 +1301,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_WELCOME,
ARG_CHROME,
ARG_RESET,
ARG_MUTE_CONSOLE,
};
static const struct option options[] = {
@ -1331,6 +1340,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "welcome", required_argument, NULL, ARG_WELCOME },
{ "chrome", required_argument, NULL, ARG_CHROME },
{ "reset", no_argument, NULL, ARG_RESET },
{ "mute-console", required_argument, NULL, ARG_MUTE_CONSOLE },
{}
};
@ -1550,6 +1560,13 @@ static int parse_argv(int argc, char *argv[]) {
arg_reset = true;
break;
case ARG_MUTE_CONSOLE:
r = parse_boolean_argument("--mute-console=", optarg, &arg_mute_console);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
@ -1712,27 +1729,28 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
r = process_locale(rfd);
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *mute_console_link = NULL;
r = process_locale(rfd, &mute_console_link);
if (r < 0)
return r;
if (r > 0 && !offline)
(void) reload_system_manager(&bus);
r = process_keymap(rfd);
r = process_keymap(rfd, &mute_console_link);
if (r < 0)
return r;
if (r > 0 && !offline)
(void) reload_vconsole(&bus);
r = process_timezone(rfd);
r = process_timezone(rfd, &mute_console_link);
if (r < 0)
return r;
r = process_hostname(rfd);
r = process_hostname(rfd, &mute_console_link);
if (r < 0)
return r;
r = process_root_account(rfd);
r = process_root_account(rfd, &mute_console_link);
if (r < 0)
return r;

View File

@ -1,9 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
#include <sys/stat.h>
#include <unistd.h>
@ -27,6 +23,7 @@
#include "prioq.h"
#include "process-util.h"
#include "procfs-util.h"
#include "selinux-util.h"
#include "set.h"
#include "string-util.h"
#include "syslog-util.h"
@ -257,6 +254,9 @@ static int client_context_read_label(
assert(pid_is_valid(c->pid));
assert(label_size == 0 || label);
if (!mac_selinux_use())
return 0;
if (label_size > 0) {
char *l;
@ -275,7 +275,7 @@ static int client_context_read_label(
/* If we got no SELinux label passed in, let's try to acquire one */
if (getpidcon(c->pid, &con) >= 0 && con) {
if (sym_getpidcon_raw(c->pid, &con) >= 0 && con) {
free_and_replace(c->label, con);
c->label_size = strlen(c->label);
}

View File

@ -58,7 +58,7 @@ journal_test_template = test_template + {
journal_fuzz_template = fuzz_template + {
'objects' : ['systemd-journald'],
'dependencies' : libselinux,
'dependencies' : libselinux_cflags,
}
executables += [
@ -69,7 +69,7 @@ executables += [
'extract' : systemd_journald_extract_sources,
'dependencies' : [
liblz4_cflags,
libselinux,
libselinux_cflags,
libxz_cflags,
libzstd_cflags,
threads,
@ -87,7 +87,7 @@ executables += [
'public' : true,
'sources' : files('cat.c'),
'objects' : ['systemd-journald'],
'dependencies' : [libselinux, threads],
'dependencies' : [threads],
},
executable_template + {
'name' : 'journalctl',
@ -106,7 +106,7 @@ executables += [
'sources' : files('test-journald-config.c'),
'dependencies' : [
liblz4_cflags,
libselinux,
libselinux_cflags,
libxz_cflags,
],
},
@ -114,7 +114,7 @@ executables += [
'sources' : files('test-journald-rate-limit.c'),
'dependencies' : [
liblz4_cflags,
libselinux,
libselinux_cflags,
libxz_cflags,
],
},
@ -122,7 +122,7 @@ executables += [
'sources' : files('test-journald-syslog.c'),
'dependencies' : [
liblz4_cflags,
libselinux,
libselinux_cflags,
libxz_cflags,
threads,
],
@ -130,7 +130,7 @@ executables += [
journal_test_template + {
'sources' : files('test-journald-tables.c'),
'dependencies' : [
libselinux,
libselinux_cflags,
],
},
journal_fuzz_template + {

View File

@ -0,0 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
executables += [
executable_template + {
'name' : 'systemd-mute-console',
'public' : true,
'sources' : files('mute-console.c'),
},
]

View File

@ -0,0 +1,419 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <stdbool.h>
#include "sd-bus.h"
#include "sd-event.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "ansi-color.h"
#include "build.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "bus-util.h"
#include "daemon-util.h"
#include "errno-util.h"
#include "log.h"
#include "main-func.h"
#include "parse-argument.h"
#include "pretty-print.h"
#include "printk-util.h"
#include "varlink-io.systemd.MuteConsole.h"
#include "varlink-util.h"
#include "virt.h"
static bool arg_mute_pid1 = true;
static bool arg_mute_kernel = true;
static bool arg_varlink = false;
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("systemd-mute-console", "1", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...]\n"
"\n%sMute status output to the console.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --kernel=BOOL Mute kernel log output\n"
" --pid1=BOOL Mute PID 1 status output\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_KERNEL,
ARG_PID1,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "kernel", required_argument, NULL, ARG_KERNEL },
{ "pid1", required_argument, NULL, ARG_PID1 },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hq", options, NULL)) >= 0) {
switch (c) {
case 'h':
return help();
case ARG_VERSION:
return version();
case ARG_PID1:
r = parse_boolean_argument("--pid1=", optarg, &arg_mute_pid1);
if (r < 0)
return r;
break;
case ARG_KERNEL:
r = parse_boolean_argument("--kernel=", optarg, &arg_mute_kernel);
if (r < 0)
return r;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
}
r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT);
if (r < 0)
return log_error_errno(r, "Failed to check if invoked in Varlink mode: %m");
if (r > 0)
arg_varlink = true;
return 1;
}
static int set_show_status(const char *value) {
int r;
assert(value);
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
r = bus_connect_system_systemd(&bus);
if (r < 0)
return log_error_errno(r, "Failed to connect to systemd: %m");
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = bus_call_method(bus, bus_systemd_mgr, "SetShowStatus", &error, /* ret_reply= */ NULL, "s", value);
if (r < 0)
return log_error_errno(r, "Failed to issue SetShowStatus() method call: %s", bus_error_message(&error, r));
return 0;
}
typedef struct Context {
bool mute_pid1;
bool mute_kernel;
bool muted_pid1;
int saved_kernel;
sd_varlink *link;
} Context;
static int mute_pid1(Context *c) {
int r;
assert(c);
if (!c->mute_pid1) {
log_debug("Muting of PID 1 status console output disabled.");
c->muted_pid1 = false;
return 0;
}
r = set_show_status("no");
if (r < 0)
return r;
log_debug("Successfully muted PID 1 status console output.");
c->muted_pid1 = true;
return 0;
}
static int unmute_pid1(Context *c) {
int r;
assert(c);
if (!c->muted_pid1) {
log_debug("Not restoring PID 1 status console output level.");
return 0;
}
r = set_show_status("");
if (r < 0)
return r;
log_debug("Successfully unmuted PID 1 status console output.");
c->muted_pid1 = false;
return 0;
}
static int mute_kernel(Context *c) {
int r;
assert(c);
if (!arg_mute_kernel) {
log_debug("Muting of kernel printk() console output disabled.");
c->saved_kernel = -1;
return 0;
}
if (detect_container() > 0) {
log_debug("Skipping muting of print() console output, because running in a container.");
c->saved_kernel = -1;
return 0;
}
int level = sysctl_printk_read();
if (level < 0)
return log_error_errno(level, "Failed to read kernel printk() console output level: %m");
if (level == 0) {
log_info("Not muting kernel printk() console output, since it is already disabled.");
c->saved_kernel = -1; /* don't bother with restoring */
} else {
r = sysctl_printk_write(0);
if (r < 0)
return log_error_errno(r, "Failed to change kernel printk() console output level: %m");
log_debug("Successfully muted kernel printk() console output.");
c->saved_kernel = level;
}
return 0;
}
static int unmute_kernel(Context *c) {
int r;
assert(c);
if (c->saved_kernel < 0) {
log_debug("Not restoring kernel printk() console output level.");
return 0;
}
int level = sysctl_printk_read();
if (level < 0)
return log_error_errno(level, "Failed to read kernel printk() console output level: %m");
if (level != 0) {
log_info("Not unmuting kernel printk() console output, since it has been changed externally in the meantime.");
return 0;
}
r = sysctl_printk_write(c->saved_kernel);
if (r < 0)
return log_error_errno(r, "Failed to unmute kernel printk() console output level: %m");
log_debug("Successfully unmuted kernel printk() console output.");
c->saved_kernel = -1;
return 0;
}
static void context_done(Context *c) {
assert(c);
(void) unmute_pid1(c);
(void) unmute_kernel(c);
if (c->link) {
(void) sd_varlink_set_userdata(c->link, NULL);
c->link = sd_varlink_flush_close_unref(c->link);
}
}
static Context* context_free(Context *c) {
if (!c)
return NULL;
context_done(c);
return mfree(c);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(Context*, context_free);
static void vl_on_disconnect(sd_varlink_server *server, sd_varlink *link, void *userdata) {
assert(link);
Context *c = sd_varlink_get_userdata(link);
if (!c)
return;
context_free(c);
}
static int vl_method_mute(
sd_varlink *link,
sd_json_variant *parameters,
sd_varlink_method_flags_t flags,
void *userdata) {
int r;
assert(link);
_cleanup_(context_freep) Context *nc = new(Context, 1);
if (!nc)
return -ENOMEM;
*nc = (Context) {
.mute_pid1 = true,
.mute_kernel = true,
.saved_kernel = -1,
};
static const sd_json_dispatch_field dispatch_table[] = {
{ "kernel", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(Context, mute_kernel), 0 },
{ "pid1", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(Context, mute_pid1), 0 },
{}
};
r = sd_varlink_dispatch(link, parameters, dispatch_table, nc);
if (r != 0)
return r;
if (!FLAGS_SET(flags, SD_VARLINK_METHOD_MORE))
return sd_varlink_error(link, SD_VARLINK_ERROR_EXPECTED_MORE, NULL);
r = sd_varlink_server_bind_disconnect(sd_varlink_get_server(link), vl_on_disconnect);
if (r < 0)
return r;
(void) sd_varlink_set_userdata(link, nc);
nc->link = sd_varlink_ref(link);
Context *c = TAKE_PTR(nc); /* the Context object is now managed by the disconnect handler, not us anymore */
r = 0;
RET_GATHER(r, mute_pid1(c));
RET_GATHER(r, mute_kernel(c));
if (r < 0)
return r;
/* Let client know we are muted now. We use sd_varlink_notify() here (rather than sd_varlink_reply())
* because we want to keep the method call open, as we want that the lifetime of the
* connection/method call to determine how long we keep the console muted. */
r = sd_varlink_notify(link, /* parameters= */ NULL);
if (r < 0)
return r;
return 0;
}
static int vl_server(void) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
int r;
/* Invocation as Varlink service */
r = varlink_server_new(
&varlink_server,
SD_VARLINK_SERVER_ROOT_ONLY|
SD_VARLINK_SERVER_HANDLE_SIGINT|
SD_VARLINK_SERVER_HANDLE_SIGTERM,
/* userdata= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to allocate Varlink server: %m");
r = sd_varlink_server_add_interface(varlink_server, &vl_interface_io_systemd_MuteConsole);
if (r < 0)
return log_error_errno(r, "Failed to add Varlink interface: %m");
r = sd_varlink_server_bind_method_many(
varlink_server,
"io.systemd.MuteConsole.Mute", vl_method_mute);
if (r < 0)
return log_error_errno(r, "Failed to bind Varlink methods: %m");
r = sd_varlink_server_loop_auto(varlink_server);
if (r < 0)
return log_error_errno(r, "Failed to run Varlink event loop: %m");
return 0;
}
static int run(int argc, char* argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
if (arg_varlink)
return vl_server();
if (!arg_mute_pid1 && !arg_mute_kernel)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not asked to mute anything, refusing.");
_cleanup_(context_done) Context c = {
.mute_pid1 = arg_mute_pid1,
.mute_kernel = arg_mute_kernel,
.saved_kernel = -1,
};
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
r = sd_event_new(&event);
if (r < 0)
return log_error_errno(r, "Failed to get default event source: %m");
(void) sd_event_set_watchdog(event, true);
(void) sd_event_set_signal_exit(event, true);
int ret = 0;
RET_GATHER(ret, mute_pid1(&c));
RET_GATHER(ret, mute_kernel(&c));
/* Now tell service manager we area ready to go */
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message =
notify_start("READY=1\n"
"STATUS=Console status output muted temporarily.",
"STOPPING=1\n"
"STATUS=Console status output unmuted.");
/* Now wait for SIGINT/SIGTERM */
r = sd_event_loop(event);
if (r < 0)
RET_GATHER(ret, log_error_errno(r, "Failed to run event loop: %m"));
RET_GATHER(ret, unmute_pid1(&c));
RET_GATHER(ret, unmute_kernel(&c));
return ret;
}
DEFINE_MAIN_FUNCTION(run);

View File

@ -21,7 +21,7 @@
ip={dhcp|on|any|dhcp6|auto6|either6|link6|link-local}
ip=<interface>:{dhcp|on|any|dhcp6|auto6|link6|link-local}[:[<mtu>][:<macaddr>]]
ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft|link-local}[:[<mtu>][:<macaddr>]]
ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft|link-local}[:[<dns1>][:<dns2>]]
ip=<client-IP>:[<peer>]:<gateway-IP>:<netmask>:<client_hostname>:<interface>:{none|off|dhcp|on|any|dhcp6|auto6|link6|ibft|link-local}[:[<dns1>][:[<dns2>][:[<ntp>]]]]
rd.route=<net>/<netmask>:<gateway>[:<interface>]
nameserver=<IP> [nameserver=<IP> ...]
rd.peerdns=0
@ -197,6 +197,7 @@ static Network* network_free(Network *network) {
strv_free(network->vlan);
free(network->bridge);
free(network->bond);
free(network->ntp);
while ((address = network->addresses))
address_free(address);
@ -650,6 +651,27 @@ static int network_set_bond(Context *context, const char *ifname, const char *va
return free_and_strdup(&network->bond, value);
}
static int network_set_ntp(Context *context, const char *ifname, const char *value) {
Network *network;
int r;
assert(context);
assert(ifname);
if (isempty(value))
return 0;
r = in_addr_from_string_auto(value, NULL, NULL);
if (r < 0)
return log_debug_errno(r, "Invalid NTP address '%s' for '%s'", value, ifname);
r = network_acquire(context, ifname, &network);
if (r < 0)
return log_debug_errno(r, "Failed to acquire network for '%s': %m", ifname);
return free_and_strdup(&network->ntp, value);
}
static int parse_cmdline_ip_mtu_mac(Context *context, const char *ifname, const char *value) {
_cleanup_free_ char *mtu = NULL;
int r;
@ -865,6 +887,18 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va
if (r < 0)
return r;
/* Next, try [:<ntp>] */
_cleanup_free_ char *ntp = NULL;
r = extract_ip_address_str(AF_UNSPEC, &p, &ntp);
if (r < 0)
return log_debug_errno(r, "Failed to parse NTP address in ip=%s: %m", value);
if (r == 0)
return 0;
r = network_set_ntp(context, ifname, ntp);
if (r < 0)
return r;
/* refuse unexpected trailing strings */
if (!isempty(p))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected trailing string in 'ip=%s'.", value);
@ -1373,6 +1407,9 @@ void network_dump(Network *network, FILE *f) {
if (network->bond)
fprintf(f, "Bond=%s\n", network->bond);
if (network->ntp)
fprintf(f, "NTP=%s\n", network->ntp);
fputs("\n[DHCP]\n", f);
if (!isempty(network->hostname))

View File

@ -65,6 +65,7 @@ struct Network {
char **vlan;
char *bridge;
char *bond;
char *ntp;
/* [DHCP] */
char *hostname;

View File

@ -213,6 +213,51 @@ int main(int argc, char *argv[]) {
"Gateway=192.168.0.1\n"
);
test_network_one("eth0", "ip", "192.168.0.10::192.168.0.1:255.255.255.0::eth0:on:10.10.10.10:10.10.10.11:10.10.10.161",
"[Match]\n"
"Name=eth0\n"
"\n[Link]\n"
"\n[Network]\n"
"DHCP=yes\n"
"DNS=10.10.10.10\n"
"DNS=10.10.10.11\n"
"NTP=10.10.10.161\n"
"\n[DHCP]\n"
"\n[Address]\n"
"Address=192.168.0.10/24\n"
"\n[Route]\n"
"Gateway=192.168.0.1\n"
);
test_network_one("eth0", "ip", "192.168.0.10::192.168.0.1:255.255.255.0::eth0:on:10.10.10.10::10.10.10.161",
"[Match]\n"
"Name=eth0\n"
"\n[Link]\n"
"\n[Network]\n"
"DHCP=yes\n"
"DNS=10.10.10.10\n"
"NTP=10.10.10.161\n"
"\n[DHCP]\n"
"\n[Address]\n"
"Address=192.168.0.10/24\n"
"\n[Route]\n"
"Gateway=192.168.0.1\n"
);
test_network_one("eth0", "ip", "192.168.0.10::192.168.0.1:255.255.255.0::eth0:on:::10.10.10.161",
"[Match]\n"
"Name=eth0\n"
"\n[Link]\n"
"\n[Network]\n"
"DHCP=yes\n"
"NTP=10.10.10.161\n"
"\n[DHCP]\n"
"\n[Address]\n"
"Address=192.168.0.10/24\n"
"\n[Route]\n"
"Gateway=192.168.0.1\n"
);
test_network_one("eth0", "ip", "[2001:1234:56:8f63::10]::[2001:1234:56:8f63::1]:64:hogehoge:eth0:on",
"[Match]\n"
"Name=eth0\n"

View File

@ -768,7 +768,7 @@ static int link_status_one(
if (r < 0)
return table_log_add_error(r);
r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
r = table_add_cell_stringf(table, NULL, "%sBps/%sBps",
FORMAT_BYTES_FULL(info->tx_bitrate, 0),
FORMAT_BYTES_FULL(info->rx_bitrate, 0));
if (r < 0)

View File

@ -444,14 +444,15 @@ static int network_append_json(Network *network, sd_json_variant **v) {
v,
SD_JSON_BUILD_PAIR_STRING("NetworkFile", network->filename),
SD_JSON_BUILD_PAIR_STRV("NetworkFileDropins", network->dropins),
SD_JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network->required_for_online),
SD_JSON_BUILD_PAIR("RequiredOperationalStateForOnline",
SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.min)),
SD_JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.max)))),
SD_JSON_BUILD_PAIR_STRING("RequiredFamilyForOnline",
link_required_address_family_to_string(network->required_family_for_online)),
SD_JSON_BUILD_PAIR_STRING("ActivationPolicy",
activation_policy_to_string(network->activation_policy)));
SD_JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network->required_for_online > 0),
SD_JSON_BUILD_PAIR_CONDITION(
operational_state_range_is_valid(&network->required_operstate_for_online),
"RequiredOperationalStateForOnline",
SD_JSON_BUILD_ARRAY(
SD_JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.min)),
SD_JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.max)))),
SD_JSON_BUILD_PAIR_STRING("RequiredFamilyForOnline", link_required_address_family_to_string(network->required_family_for_online)),
SD_JSON_BUILD_PAIR_STRING("ActivationPolicy", activation_policy_to_string(network->activation_policy)));
}
static int netdev_append_json(NetDev *netdev, sd_json_variant **v) {

View File

@ -48,7 +48,7 @@ executables += [
'extract' : nspawn_extract_sources,
'dependencies' : [
libseccomp_cflags,
libselinux,
libselinux_cflags,
],
},
nspawn_test_template + {

View File

@ -13,10 +13,6 @@
#include <sys/wait.h>
#include <unistd.h>
#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
#include "sd-bus.h"
#include "sd-daemon.h"
#include "sd-event.h"
@ -104,6 +100,7 @@
#include "rm-rf.h"
#include "runtime-scope.h"
#include "seccomp-util.h"
#include "selinux-util.h"
#include "shift-uid.h"
#include "signal-util.h"
#include "siphash24.h"
@ -3532,8 +3529,8 @@ static int inner_child(
}
#if HAVE_SELINUX
if (arg_selinux_context)
if (setexeccon(arg_selinux_context) < 0)
if (arg_selinux_context && mac_selinux_use())
if (sym_setexeccon_raw(arg_selinux_context) < 0)
return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
#endif

View File

@ -29,7 +29,7 @@ executables += [
'sources' : systemd_portabled_sources,
'link_with' : portabled_link_with,
'dependencies' : [
libselinux,
libselinux_cflags,
threads,
],
},

View File

@ -310,10 +310,11 @@ static int extract_now(
#if HAVE_SELINUX
/* The units will be copied on the host's filesystem, so if they had a SELinux label
* we have to preserve it. Copy it out so that it can be applied later. */
r = fgetfilecon_raw(fd, &con);
if (r < 0 && !ERRNO_IS_XATTR_ABSENT(errno))
log_debug_errno(errno, "Failed to get SELinux file context from '%s', ignoring: %m", de->d_name);
if (mac_selinux_use()) {
r = sym_fgetfilecon_raw(fd, &con);
if (r < 0 && !ERRNO_IS_XATTR_ABSENT(errno))
log_debug_errno(errno, "Failed to get SELinux file context from '%s', ignoring: %m", de->d_name);
}
#endif
if (socket_fd >= 0) {

View File

@ -2809,7 +2809,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
}
/* Verity partitions are read only, let's imply the RO flag hence, unless explicitly configured otherwise. */
if ((partition_designator_is_verity(p->type.designator) || p->verity == VERITY_DATA) && p->read_only < 0)
if ((partition_designator_is_verity_hash(p->type.designator) || p->verity == VERITY_DATA) && p->read_only < 0)
p->read_only = true;
/* Default to "growfs" on, unless read-only */
@ -7500,7 +7500,7 @@ static int resolve_copy_blocks_auto_candidate_harder(
* verity/verity-sig partition for it, based on udev metadata. */
const char *property;
if (partition_designator_is_verity(partition_type.designator))
if (partition_designator_is_verity_hash(partition_type.designator))
property = "ID_DISSECT_PART_VERITY_DEVICE";
else if (partition_designator_is_verity_sig(partition_type.designator))
property = "ID_DISSECT_PART_VERITY_SIG_DEVICE";

View File

@ -1060,9 +1060,31 @@ static int dissect_image(
if (!image_filter_test(filter, type.designator, label))
continue;
log_debug("Dissecting %s partition with label %s and UUID %s",
log_debug("Dissecting %s partition with label %s and UUID %s.",
strna(partition_designator_to_string(type.designator)), strna(label), SD_ID128_TO_UUID_STRING(id));
/* Note that we don't check the SD_GPT_FLAG_NO_AUTO flag for the ESP, as it is
* not defined there. We instead check the SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as
* recommended by the UEFI spec (See "12.3.3 Number and Location of System
* Partitions"). */
if (FLAGS_SET(pflags, SD_GPT_FLAG_NO_AUTO) && type.designator != PARTITION_ESP) {
log_debug("Partition has 'no auto' flag set, ignoring.");
continue;
}
if (!verity && partition_designator_is_verity(type.designator)) {
log_debug("Partition is a verity hash or verity signature partition but no verity was requested, ignoring.");
continue;
}
PartitionDesignator vd = partition_verity_to_data(type.designator);
if (verity && verity->designator >= 0 && vd >= 0 && vd != verity->designator) {
log_debug("Partition is a %s partition but verity was only requested for the %s partition, ignoring.",
partition_designator_to_string(type.designator),
partition_designator_to_string(verity->designator));
continue;
}
if (IN_SET(type.designator,
PARTITION_HOME,
PARTITION_SRV,
@ -1072,21 +1094,15 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
} else if (type.designator == PARTITION_ESP) {
/* Note that we don't check the SD_GPT_FLAG_NO_AUTO flag for the ESP, as it is
* not defined there. We instead check the SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL, as
* recommended by the UEFI spec (See "12.3.3 Number and Location of System
* Partitions"). */
if (pflags & SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL)
if (FLAGS_SET(pflags, SD_GPT_FLAG_NO_BLOCK_IO_PROTOCOL)) {
log_debug("ESP Partition has 'no block io' flag set, ignoring.");
continue;
}
fstype = "vfat";
@ -1095,12 +1111,13 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
/* If a root ID is specified, ignore everything but the root id */
if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id))
if (!sd_id128_is_null(root_uuid) && !sd_id128_equal(root_uuid, id)) {
log_debug("Partition UUID '%s' does not match expected UUID '%s' derived from root verity hash, ignoring.",
SD_ID128_TO_UUID_STRING(id),
SD_ID128_TO_UUID_STRING(root_uuid));
continue;
}
rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
@ -1110,20 +1127,15 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
m->has_verity = true;
/* If no verity configuration is specified, then don't do verity */
if (!verity)
continue;
if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
continue;
/* If root hash is specified, then ignore everything but the root id */
if (!sd_id128_is_null(root_verity_uuid) && !sd_id128_equal(root_verity_uuid, id))
if (!sd_id128_is_null(root_verity_uuid) && !sd_id128_equal(root_verity_uuid, id)) {
log_debug("Partition UUID '%s' does not match expected UUID '%s' derived from root verity hash, ignoring.",
SD_ID128_TO_UUID_STRING(id),
SD_ID128_TO_UUID_STRING(root_verity_uuid));
continue;
}
fstype = "DM_verity_hash";
rw = false;
@ -1133,16 +1145,7 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
m->has_verity_sig = true;
if (!verity)
continue;
if (verity->designator >= 0 && verity->designator != PARTITION_ROOT)
continue;
fstype = "verity_hash_signature";
rw = false;
@ -1151,12 +1154,13 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
/* If a usr ID is specified, ignore everything but the usr id */
if (!sd_id128_is_null(usr_uuid) && !sd_id128_equal(usr_uuid, id))
if (!sd_id128_is_null(usr_uuid) && !sd_id128_equal(usr_uuid, id)) {
log_debug("Partition UUID '%s' does not match expected UUID '%s' derived from usr verity hash, ignoring.",
SD_ID128_TO_UUID_STRING(id),
SD_ID128_TO_UUID_STRING(usr_uuid));
continue;
}
rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
@ -1166,19 +1170,15 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
m->has_verity = true;
if (!verity)
continue;
if (verity->designator >= 0 && verity->designator != PARTITION_USR)
continue;
/* If usr hash is specified, then ignore everything but the usr id */
if (!sd_id128_is_null(usr_verity_uuid) && !sd_id128_equal(usr_verity_uuid, id))
if (!sd_id128_is_null(usr_verity_uuid) && !sd_id128_equal(usr_verity_uuid, id)) {
log_debug("Partition UUID '%s' does not match expected UUID '%s' derived from usr verity hash, ignoring.",
SD_ID128_TO_UUID_STRING(id),
SD_ID128_TO_UUID_STRING(usr_uuid));
continue;
}
fstype = "DM_verity_hash";
rw = false;
@ -1188,16 +1188,7 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
m->has_verity_sig = true;
if (!verity)
continue;
if (verity->designator >= 0 && verity->designator != PARTITION_USR)
continue;
fstype = "verity_hash_signature";
rw = false;
@ -1205,9 +1196,6 @@ static int dissect_image(
check_partition_flags(node, pflags, SD_GPT_FLAG_NO_AUTO);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
/* Note: we don't set fstype = "swap" here, because we still need to probe if
* it might be encrypted (i.e. fstype "crypt_LUKS") or unencrypted
* (i.e. fstype "swap"), and the only way to figure that out is via fstype
@ -1222,9 +1210,6 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
if (generic_node)
multiple_generic = true;
else {
@ -1240,9 +1225,6 @@ static int dissect_image(
check_partition_flags(node, pflags,
SD_GPT_FLAG_NO_AUTO | SD_GPT_FLAG_READ_ONLY | SD_GPT_FLAG_GROWFS);
if (pflags & SD_GPT_FLAG_NO_AUTO)
continue;
if (!FLAGS_SET(flags, DISSECT_IMAGE_RELAX_VAR_CHECK)) {
sd_id128_t var_uuid;
@ -1446,12 +1428,12 @@ static int dissect_image(
m->partitions[PARTITION_ROOT_VERITY_SIG].found))
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Found root verity hash partition without matching root data partition");
"Found root verity hash partition without matching root data partition.");
/* Hmm, we found a signature partition but no Verity data? Something is off. */
if (m->partitions[PARTITION_ROOT_VERITY_SIG].found && !m->partitions[PARTITION_ROOT_VERITY].found)
return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Found root verity signature partition without matching root verity hash partition");
"Found root verity signature partition without matching root verity hash partition.");
/* as above */
if (!m->partitions[PARTITION_USR].found &&
@ -1459,12 +1441,12 @@ static int dissect_image(
m->partitions[PARTITION_USR_VERITY_SIG].found))
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Found usr verity hash partition without matching usr data partition");
"Found usr verity hash partition without matching usr data partition.");
/* as above */
if (m->partitions[PARTITION_USR_VERITY_SIG].found && !m->partitions[PARTITION_USR_VERITY].found)
return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Found usr verity signature partition without matching usr verity hash partition");
"Found usr verity signature partition without matching usr verity hash partition.");
/* If root and /usr are combined then insist that the architecture matches */
if (m->partitions[PARTITION_ROOT].found &&
@ -1473,7 +1455,7 @@ static int dissect_image(
m->partitions[PARTITION_USR].architecture >= 0 &&
m->partitions[PARTITION_ROOT].architecture != m->partitions[PARTITION_USR].architecture))
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTE),
"Found root and usr partitions with different architectures (%s vs %s)",
"Found root and usr partitions with different architectures (%s vs %s).",
architecture_to_string(m->partitions[PARTITION_ROOT].architecture),
architecture_to_string(m->partitions[PARTITION_USR].architecture));
@ -1543,17 +1525,17 @@ static int dissect_image(
/* Check if we have a root fs if we are told to do check. /usr alone is fine too, but only if appropriate flag for that is set too */
if (FLAGS_SET(flags, DISSECT_IMAGE_REQUIRE_ROOT) &&
!(m->partitions[PARTITION_ROOT].found || (m->partitions[PARTITION_USR].found && FLAGS_SET(flags, DISSECT_IMAGE_USR_NO_ROOT))))
return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Root or usr partition requested but found neither");
return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Root or usr partition requested but found neither.");
if (m->partitions[PARTITION_ROOT_VERITY].found) {
/* We only support one verity partition per image, i.e. can't do for both /usr and root fs */
if (m->partitions[PARTITION_USR_VERITY].found)
return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "Found both root and usr verity enabled partitions which is not supported");
return log_debug_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "Found both root and usr verity enabled partitions which is not supported.");
/* We don't support verity enabled root with a split out /usr. Neither with nor without
* verity there. (Note that we do support verity-less root with verity-full /usr, though.) */
if (m->partitions[PARTITION_USR].found)
return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL), "Found verity enabled root partition with split usr partition which is not supported");
return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL), "Found verity enabled root partition with split usr partition which is not supported.");
}
if (verity) {
@ -1561,7 +1543,7 @@ static int dissect_image(
if (verity->designator >= 0 && !m->partitions[verity->designator].found)
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Explicit %s verity designator was specified but did not find %s partition",
"Explicit %s verity designator was specified but did not find %s partition.",
partition_designator_to_string(verity->designator),
partition_designator_to_string(verity->designator));
@ -1573,12 +1555,12 @@ static int dissect_image(
if (!m->partitions[PARTITION_ROOT].found)
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Verity enabled root partition was requested but did not find a root data partition");
"Verity enabled root partition was requested but did not find a root data partition.");
if (!m->partitions[PARTITION_ROOT_VERITY].found)
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Verity enabled root partition was requested but did not find a root verity hash partition");
"Verity enabled root partition was requested but did not find a root verity hash partition.");
/* If we found a verity setup, then the root partition is necessarily read-only. */
m->partitions[PARTITION_ROOT].rw = false;
@ -1588,12 +1570,12 @@ static int dissect_image(
if (!m->partitions[PARTITION_USR].found)
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Verity enabled usr partition was requested but did not find a usr data partition");
"Verity enabled usr partition was requested but did not find a usr data partition.");
if (!m->partitions[PARTITION_USR_VERITY].found)
return log_debug_errno(
SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Verity enabled usr partition was requested but did not find a usr verity hash partition");
"Verity enabled usr partition was requested but did not find a usr verity hash partition.");
m->partitions[PARTITION_USR].rw = false;
@ -1619,7 +1601,7 @@ static int dissect_image(
if (m->partitions[di].found) {
found_flags = PARTITION_POLICY_ENCRYPTED|PARTITION_POLICY_UNPROTECTED|PARTITION_POLICY_UNUSED;
PartitionDesignator vi = partition_verity_of(di);
PartitionDesignator vi = partition_verity_hash_of(di);
if (vi >= 0 && m->partitions[vi].found) {
found_flags |= PARTITION_POLICY_VERITY;
@ -1633,7 +1615,7 @@ static int dissect_image(
if (DEBUG_LOGGING) {
_cleanup_free_ char *s = NULL;
(void) partition_policy_flags_to_string(found_flags, /* simplify= */ false, &s);
log_debug("Found for designator %s: %s", partition_designator_to_string(di), strna(s));
log_debug("Found for designator %s: %s.", partition_designator_to_string(di), strna(s));
}
r = image_policy_check_protection(policy, di, found_flags);
@ -3119,7 +3101,7 @@ int dissected_image_decrypt(
if (r < 0)
return r;
k = partition_verity_of(i);
k = partition_verity_hash_of(i);
if (k >= 0) {
flags |= getenv_bool("SYSTEMD_VERITY_SHARING") != 0 ? DISSECT_IMAGE_VERITY_SHARE : 0;
@ -3608,7 +3590,7 @@ int dissected_image_load_verity_sig_partition(
if (!m->partitions[dd].found)
return 0;
PartitionDesignator dv = partition_verity_of(dd);
PartitionDesignator dv = partition_verity_hash_of(dd);
assert(dv >= 0);
if (!m->partitions[dv].found)
return 0;
@ -3734,7 +3716,7 @@ int dissected_image_guess_verity_roothash(
if (!d->found)
return 0;
PartitionDesignator dv = partition_verity_of(dd);
PartitionDesignator dv = partition_verity_hash_of(dd);
assert(dv >= 0);
DissectedPartition *p = m->partitions + dv;
@ -4178,7 +4160,7 @@ bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesi
if (image->single_file_system)
return partition_designator == PARTITION_ROOT && image->has_verity;
return partition_verity_of(partition_designator) >= 0;
return partition_verity_hash_of(partition_designator) >= 0;
}
bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator partition_designator) {
@ -4195,7 +4177,7 @@ bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignat
if (image->single_file_system)
return partition_designator == PARTITION_ROOT;
k = partition_verity_of(partition_designator);
k = partition_verity_hash_of(partition_designator);
return k >= 0 && image->partitions[k].found;
}

View File

@ -31,7 +31,7 @@ bool partition_designator_is_versioned(PartitionDesignator d) {
PARTITION_USR_VERITY_SIG);
}
PartitionDesignator partition_verity_of(PartitionDesignator p) {
PartitionDesignator partition_verity_hash_of(PartitionDesignator p) {
switch (p) {
case PARTITION_ROOT:
@ -59,7 +59,7 @@ PartitionDesignator partition_verity_sig_of(PartitionDesignator p) {
}
}
PartitionDesignator partition_verity_to_data(PartitionDesignator d) {
PartitionDesignator partition_verity_hash_to_data(PartitionDesignator d) {
switch (d) {
case PARTITION_ROOT_VERITY:
@ -87,6 +87,14 @@ PartitionDesignator partition_verity_sig_to_data(PartitionDesignator d) {
}
}
PartitionDesignator partition_verity_to_data(PartitionDesignator d) {
PartitionDesignator e = partition_verity_hash_to_data(d);
if (e >= 0)
return e;
return partition_verity_sig_to_data(d);
}
static const char *const partition_designator_table[_PARTITION_DESIGNATOR_MAX] = {
[PARTITION_ROOT] = "root",
[PARTITION_USR] = "usr",

View File

@ -31,19 +31,24 @@ typedef enum PartitionDesignator {
bool partition_designator_is_versioned(PartitionDesignator d) _const_;
PartitionDesignator partition_verity_of(PartitionDesignator p) _const_;
PartitionDesignator partition_verity_hash_of(PartitionDesignator p) _const_;
PartitionDesignator partition_verity_sig_of(PartitionDesignator p) _const_;
PartitionDesignator partition_verity_to_data(PartitionDesignator d) _const_;
PartitionDesignator partition_verity_hash_to_data(PartitionDesignator d) _const_;
PartitionDesignator partition_verity_sig_to_data(PartitionDesignator d) _const_;
PartitionDesignator partition_verity_to_data(PartitionDesignator d) _const_;
static inline bool partition_designator_is_verity(PartitionDesignator d) {
return partition_verity_to_data(d) >= 0;
static inline bool partition_designator_is_verity_hash(PartitionDesignator d) {
return partition_verity_hash_to_data(d) >= 0;
}
static inline bool partition_designator_is_verity_sig(PartitionDesignator d) {
return partition_verity_sig_to_data(d) >= 0;
}
static inline bool partition_designator_is_verity(PartitionDesignator d) {
return partition_verity_to_data(d) >= 0;
}
const char* partition_designator_to_string(PartitionDesignator d) _const_;
PartitionDesignator partition_designator_from_string(const char *name) _pure_;

View File

@ -76,12 +76,12 @@ static PartitionPolicyFlags partition_policy_normalized_flags(const PartitionPol
/* If this is a verity or verity signature designator, then mask off all protection bits, this after
* all needs no protection, because it *is* the protection */
if (partition_verity_to_data(policy->designator) >= 0 ||
if (partition_verity_hash_to_data(policy->designator) >= 0 ||
partition_verity_sig_to_data(policy->designator) >= 0)
flags &= ~(PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED|PARTITION_POLICY_ENCRYPTED);
/* if this designator has no verity concept, then mask off verity protection flags */
if (partition_verity_of(policy->designator) < 0)
if (partition_verity_hash_of(policy->designator) < 0)
flags &= ~(PARTITION_POLICY_VERITY|PARTITION_POLICY_SIGNED);
/* If the partition must be absent, then the gpt flags don't matter */
@ -110,7 +110,7 @@ PartitionPolicyFlags image_policy_get(const ImagePolicy *policy, PartitionDesign
/* Hmm, so this didn't work, then let's see if we can derive some policy from the underlying data
* partition in case of verity/signature partitions */
data_designator = partition_verity_to_data(designator);
data_designator = partition_verity_hash_to_data(designator);
if (data_designator >= 0) {
PartitionPolicyFlags data_flags;

View File

@ -154,6 +154,7 @@ shared_sources = files(
'polkit-agent.c',
'portable-util.c',
'pretty-print.c',
'printk-util.c',
'prompt-util.c',
'ptyfwd.c',
'qrcode-util.c',
@ -201,6 +202,7 @@ shared_sources = files(
'varlink-io.systemd.ManagedOOM.c',
'varlink-io.systemd.Manager.c',
'varlink-io.systemd.MountFileSystem.c',
'varlink-io.systemd.MuteConsole.c',
'varlink-io.systemd.NamespaceResource.c',
'varlink-io.systemd.Network.c',
'varlink-io.systemd.PCRExtend.c',
@ -328,7 +330,7 @@ libshared_deps = [threads,
libpam_cflags,
librt,
libseccomp_cflags,
libselinux,
libselinux_cflags,
libxenctrl_cflags,
libxz_cflags,
libzstd_cflags]

42
src/shared/printk-util.c Normal file
View File

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "extract-word.h"
#include "log.h"
#include "parse-util.h"
#include "printk-util.h"
#include "sysctl-util.h"
int sysctl_printk_read(void) {
int r;
_cleanup_free_ char *sysctl_printk_vals = NULL;
r = sysctl_read("kernel/printk", &sysctl_printk_vals);
if (r < 0)
return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
_cleanup_free_ char *sysctl_printk_curr = NULL;
const char *p = sysctl_printk_vals;
r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
if (r < 0)
return log_debug_errno(r, "Failed to split out kernel printk priority: %m");
if (r == 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Short read while reading kernel.printk sysctl");
int current_lvl;
r = safe_atoi(sysctl_printk_curr, &current_lvl);
if (r < 0)
return log_debug_errno(r, "Failed to parse kernel.printk sysctl: %s", sysctl_printk_vals);
return current_lvl;
}
int sysctl_printk_write(int l) {
int r;
r = sysctl_writef("kernel/printk", "%i", l);
if (r < 0)
return log_debug_errno(r, "Failed to set kernel.printk to %i: %m", l);
return 0;
}

5
src/shared/printk-util.h Normal file
View File

@ -0,0 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int sysctl_printk_read(void);
int sysctl_printk_write(int l);

View File

@ -2,6 +2,8 @@
#include <unistd.h>
#include <sd-varlink.h>
#include "alloc-util.h"
#include "glyph-util.h"
#include "log.h"
@ -330,3 +332,60 @@ void chrome_hide(void) {
fflush(stdout);
}
static int vl_on_reply(sd_varlink *link, sd_json_variant *parameters, const char *error_id, sd_varlink_reply_flags_t flags, void *userdata) {
assert(link);
/* We want to keep the link around (since its lifetime defines the lifetime of the console muting),
* hence let's detach it from the event loop now, and then exit the event loop. */
_cleanup_(sd_event_unrefp) sd_event *e = sd_event_ref(ASSERT_PTR(sd_varlink_get_event(link)));
sd_varlink_detach_event(link);
(void) sd_event_exit(e, (error_id || !FLAGS_SET(flags, SD_VARLINK_REPLY_CONTINUES)) ? -EBADR : 0);
return 0;
}
int mute_console(sd_varlink **ret_link) {
int r;
assert(ret_link);
/* Talks to the MuteConsole service, and asks for output to the console to be muted, as long as the
* connection is retained */
_cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *link = NULL;
r = sd_varlink_connect_address(&link, "/run/systemd/io.systemd.MuteConsole");
if (r < 0)
return log_debug_errno(r, "Failed to connect to console muting service: %m");
_cleanup_(sd_event_unrefp) sd_event* event = NULL;
r = sd_event_new(&event);
if (r < 0)
return r;
r = sd_varlink_attach_event(link, event, /* priority= */ 0);
if (r < 0)
return r;
r = sd_varlink_bind_reply(link, vl_on_reply);
if (r < 0)
return r;
r = sd_varlink_set_relative_timeout(link, UINT64_MAX);
if (r < 0)
return log_debug_errno(r, "Failed to disable method call time-out: %m");
r = sd_varlink_observe(link, "io.systemd.MuteConsole.Mute", /* parameters= */ NULL);
if (r < 0)
return log_debug_errno(r, "Failed to issue Mute() call to io.systemd.MuteConsole: %m");
/* Now run the event loop, it will exit on the first reply, which is when we know the console output
* is now muted. */
r = sd_event_loop(event);
if (r < 0)
return r;
*ret_link = TAKE_PTR(link);
return 0;
}

View File

@ -29,3 +29,5 @@ int prompt_loop(const char *text,
int chrome_show(const char *top, const char *bottom);
void chrome_hide(void);
int mute_console(sd_varlink **ret_link);

View File

@ -27,7 +27,7 @@
#include "time-util.h"
#if HAVE_SELINUX
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(context_t, context_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(context_t, sym_context_free, context_freep, NULL);
typedef enum Initialized {
UNINITIALIZED,
@ -49,12 +49,98 @@ static int mac_selinux_label_post(int dir_fd, const char *path, bool created) {
mac_selinux_create_file_clear();
return 0;
}
static void *libselinux_dl = NULL;
DLSYM_PROTOTYPE(avc_open) = NULL;
DLSYM_PROTOTYPE(context_free) = NULL;
DLSYM_PROTOTYPE(context_new) = NULL;
DLSYM_PROTOTYPE(context_range_get) = NULL;
DLSYM_PROTOTYPE(context_range_set) = NULL;
DLSYM_PROTOTYPE(context_str) = NULL;
DLSYM_PROTOTYPE(fgetfilecon_raw) = NULL;
DLSYM_PROTOTYPE(fini_selinuxmnt) = NULL;
DLSYM_PROTOTYPE(freecon) = NULL;
DLSYM_PROTOTYPE(getcon_raw) = NULL;
DLSYM_PROTOTYPE(getfilecon_raw) = NULL;
DLSYM_PROTOTYPE(getpeercon_raw) = NULL;
DLSYM_PROTOTYPE(getpidcon_raw) = NULL;
DLSYM_PROTOTYPE(is_selinux_enabled) = NULL;
DLSYM_PROTOTYPE(security_compute_create_raw) = NULL;
DLSYM_PROTOTYPE(security_getenforce) = NULL;
DLSYM_PROTOTYPE(selabel_close) = NULL;
DLSYM_PROTOTYPE(selabel_lookup_raw) = NULL;
DLSYM_PROTOTYPE(selabel_open) = NULL;
DLSYM_PROTOTYPE(selinux_check_access) = NULL;
DLSYM_PROTOTYPE(selinux_getenforcemode) = NULL;
DLSYM_PROTOTYPE(selinux_init_load_policy) = NULL;
DLSYM_PROTOTYPE(selinux_path) = NULL;
DLSYM_PROTOTYPE(selinux_set_callback) = NULL;
DLSYM_PROTOTYPE(selinux_status_close) = NULL;
DLSYM_PROTOTYPE(selinux_status_getenforce) = NULL;
DLSYM_PROTOTYPE(selinux_status_open) = NULL;
DLSYM_PROTOTYPE(selinux_status_policyload) = NULL;
DLSYM_PROTOTYPE(setcon_raw) = NULL;
DLSYM_PROTOTYPE(setexeccon_raw) = NULL;
DLSYM_PROTOTYPE(setfilecon_raw) = NULL;
DLSYM_PROTOTYPE(setfscreatecon_raw) = NULL;
DLSYM_PROTOTYPE(setsockcreatecon_raw) = NULL;
DLSYM_PROTOTYPE(string_to_security_class) = NULL;
int dlopen_libselinux(void) {
ELF_NOTE_DLOPEN("selinux",
"Support for SELinux",
ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
"libselinux.so.1");
return dlopen_many_sym_or_warn(
&libselinux_dl,
"libselinux.so.1",
LOG_DEBUG,
DLSYM_ARG(avc_open),
DLSYM_ARG(context_free),
DLSYM_ARG(context_new),
DLSYM_ARG(context_range_get),
DLSYM_ARG(context_range_set),
DLSYM_ARG(context_str),
DLSYM_ARG(fgetfilecon_raw),
DLSYM_ARG(fini_selinuxmnt),
DLSYM_ARG(freecon),
DLSYM_ARG(getcon_raw),
DLSYM_ARG(getfilecon_raw),
DLSYM_ARG(getpeercon_raw),
DLSYM_ARG(getpidcon_raw),
DLSYM_ARG(is_selinux_enabled),
DLSYM_ARG(security_compute_create_raw),
DLSYM_ARG(security_getenforce),
DLSYM_ARG(selabel_close),
DLSYM_ARG(selabel_lookup_raw),
DLSYM_ARG(selabel_open),
DLSYM_ARG(selinux_check_access),
DLSYM_ARG(selinux_getenforcemode),
DLSYM_ARG(selinux_init_load_policy),
DLSYM_ARG(selinux_path),
DLSYM_ARG(selinux_set_callback),
DLSYM_ARG(selinux_status_close),
DLSYM_ARG(selinux_status_getenforce),
DLSYM_ARG(selinux_status_open),
DLSYM_ARG(selinux_status_policyload),
DLSYM_ARG(setcon_raw),
DLSYM_ARG(setexeccon_raw),
DLSYM_ARG(setfilecon_raw),
DLSYM_ARG(setfscreatecon_raw),
DLSYM_ARG(setsockcreatecon_raw),
DLSYM_ARG(string_to_security_class));
}
#endif
bool mac_selinux_use(void) {
#if HAVE_SELINUX
if (_unlikely_(cached_use < 0)) {
cached_use = is_selinux_enabled() > 0;
if (dlopen_libselinux() < 0)
return (cached_use = false);
cached_use = sym_is_selinux_enabled() > 0;
log_trace("SELinux enabled state cached to: %s", enabled_disabled(cached_use));
}
@ -71,10 +157,13 @@ bool mac_selinux_enforcing(void) {
/* If the SELinux status page has been successfully opened, retrieve the enforcing
* status over it to avoid system calls in security_getenforce(). */
if (dlopen_libselinux() < 0)
return false;
if (have_status_page)
r = selinux_status_getenforce();
r = sym_selinux_status_getenforce();
else
r = security_getenforce();
r = sym_security_getenforce();
#endif
return r != 0;
@ -92,13 +181,18 @@ static int open_label_db(void) {
/* Avoid maybe-uninitialized false positives */
usec_t before_timestamp = USEC_INFINITY, after_timestamp = USEC_INFINITY;
struct mallinfo2 before_mallinfo = {};
int r;
r = dlopen_libselinux();
if (r < 0)
return r;
if (DEBUG_LOGGING) {
before_mallinfo = mallinfo2();
before_timestamp = now(CLOCK_MONOTONIC);
}
hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
hnd = sym_selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!hnd)
return log_selinux_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
@ -113,7 +207,7 @@ static int open_label_db(void) {
/* release memory after measurement */
if (label_hnd)
selabel_close(label_hnd);
sym_selabel_close(label_hnd);
label_hnd = TAKE_PTR(hnd);
return 0;
@ -142,7 +236,7 @@ static int selinux_init(bool force) {
mac_selinux_disable_logging();
r = selinux_status_open(/* netlink fallback= */ 1);
r = sym_selinux_status_open(/* netlink fallback= */ 1);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(errno))
return log_selinux_enforcing_errno(errno, "Failed to open SELinux status page: %m");
@ -154,7 +248,7 @@ static int selinux_init(bool force) {
r = open_label_db();
if (r < 0) {
selinux_status_close();
sym_selinux_status_close();
return r;
}
@ -164,7 +258,7 @@ static int selinux_init(bool force) {
/* Save the current policyload sequence number, so mac_selinux_maybe_reload() does not trigger on
* first call without any actual change. */
last_policyload = selinux_status_policyload();
last_policyload = sym_selinux_status_policyload();
initialized = INITIALIZED;
return 1;
@ -203,6 +297,9 @@ void mac_selinux_maybe_reload(void) {
if (!initialized)
return;
if (dlopen_libselinux() < 0)
return;
/* Do not use selinux_status_updated(3), cause since libselinux 3.2 selinux_check_access(3),
* called in core and user instances, does also use it under the hood.
* That can cause changes to be consumed by selinux_check_access(3) and not being visible here.
@ -210,7 +307,7 @@ void mac_selinux_maybe_reload(void) {
* invoked since libselinux 3.2 by selinux_status_updated(3).
* Relevant libselinux commit: https://github.com/SELinuxProject/selinux/commit/05bdc03130d741e53e1fb45a958d0a2c184be503
* Debian Bullseye is going to ship libselinux 3.1, so stay compatible for backports. */
policyload = selinux_status_policyload();
policyload = sym_selinux_status_policyload();
if (policyload < 0) {
log_debug_errno(errno, "Failed to get SELinux policyload from status page: %m");
return;
@ -227,11 +324,13 @@ void mac_selinux_finish(void) {
#if HAVE_SELINUX
if (label_hnd) {
selabel_close(label_hnd);
sym_selabel_close(label_hnd);
label_hnd = NULL;
}
selinux_status_close();
if (sym_selinux_status_close)
sym_selinux_status_close();
have_status_page = false;
initialized = false;
@ -248,7 +347,10 @@ static int selinux_log_glue(int type, const char *fmt, ...) {
void mac_selinux_disable_logging(void) {
#if HAVE_SELINUX
/* Turn off all of SELinux' own logging, we want to do that ourselves */
selinux_set_callback(SELINUX_CB_LOG, (const union selinux_callback) { .func_log = selinux_log_glue });
if (dlopen_libselinux() < 0)
return;
sym_selinux_set_callback(SELINUX_CB_LOG, (const union selinux_callback) { .func_log = selinux_log_glue });
#endif
}
@ -274,7 +376,7 @@ static int selinux_fix_fd(
if (!label_hnd)
return 0;
if (selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) {
if (sym_selabel_lookup_raw(label_hnd, &fcon, label_path, st.st_mode) < 0) {
/* If there's no label to set, then exit without warning */
if (errno == ENOENT)
return 0;
@ -282,11 +384,8 @@ static int selinux_fix_fd(
return log_selinux_enforcing_errno(errno, "Unable to lookup intended SELinux security context of %s: %m", label_path);
}
if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) {
_cleanup_freecon_ char *oldcon = NULL;
r = -errno;
r = RET_NERRNO(sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon));
if (r < 0) {
/* If the FS doesn't support labels, then exit without warning */
if (ERRNO_IS_NOT_SUPPORTED(r))
return 0;
@ -296,7 +395,8 @@ static int selinux_fix_fd(
return 0;
/* If the old label is identical to the new one, suppress any kind of error */
if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(fcon, oldcon))
_cleanup_freecon_ char *oldcon = NULL;
if (sym_getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq_ptr(fcon, oldcon))
return 0;
return log_selinux_enforcing_errno(r, "Unable to fix SELinux security context of %s: %m", label_path);
@ -371,7 +471,7 @@ int mac_selinux_apply(const char *path, const char *label) {
assert(label);
if (setfilecon(path, label) < 0)
if (sym_setfilecon_raw(path, label) < 0)
return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, path);
#endif
return 0;
@ -390,7 +490,7 @@ int mac_selinux_apply_fd(int fd, const char *path, const char *label) {
assert(label);
if (setfilecon(FORMAT_PROC_FD_PATH(fd), label) < 0)
if (sym_setfilecon_raw(FORMAT_PROC_FD_PATH(fd), label) < 0)
return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s on path %s: %m", label, strna(path));
#endif
return 0;
@ -411,21 +511,21 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **ret_label) {
if (r == 0)
return -EOPNOTSUPP;
if (getcon_raw(&mycon) < 0)
if (sym_getcon_raw(&mycon) < 0)
return -errno;
if (!mycon)
return -EOPNOTSUPP;
if (getfilecon_raw(exe, &fcon) < 0)
if (sym_getfilecon_raw(exe, &fcon) < 0)
return -errno;
if (!fcon)
return -EOPNOTSUPP;
sclass = string_to_security_class("process");
sclass = sym_string_to_security_class("process");
if (sclass == 0)
return -ENOSYS;
return RET_NERRNO(security_compute_create_raw(mycon, fcon, sclass, ret_label));
return RET_NERRNO(sym_security_compute_create_raw(mycon, fcon, sclass, ret_label));
#else
return -EOPNOTSUPP;
#endif
@ -444,7 +544,7 @@ int mac_selinux_get_our_label(char **ret_label) {
return -EOPNOTSUPP;
_cleanup_freecon_ char *con = NULL;
if (getcon_raw(&con) < 0)
if (sym_getcon_raw(&con) < 0)
return -errno;
if (!con)
return -EOPNOTSUPP;
@ -470,7 +570,7 @@ int mac_selinux_get_peer_label(int socket_fd, char **ret_label) {
return -EOPNOTSUPP;
_cleanup_freecon_ char *con = NULL;
if (getpeercon_raw(socket_fd, &con) < 0)
if (sym_getpeercon_raw(socket_fd, &con) < 0)
return -errno;
if (!con)
return -EOPNOTSUPP;
@ -500,47 +600,47 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
if (r == 0)
return -EOPNOTSUPP;
if (getcon_raw(&mycon) < 0)
if (sym_getcon_raw(&mycon) < 0)
return -errno;
if (!mycon)
return -EOPNOTSUPP;
if (getpeercon_raw(socket_fd, &peercon) < 0)
if (sym_getpeercon_raw(socket_fd, &peercon) < 0)
return -errno;
if (!peercon)
return -EOPNOTSUPP;
if (!exec_label) { /* If there is no context set for next exec let's use context of target executable */
if (getfilecon_raw(exe, &fcon) < 0)
if (sym_getfilecon_raw(exe, &fcon) < 0)
return -errno;
if (!fcon)
return -EOPNOTSUPP;
}
bcon = context_new(mycon);
bcon = sym_context_new(mycon);
if (!bcon)
return -ENOMEM;
pcon = context_new(peercon);
pcon = sym_context_new(peercon);
if (!pcon)
return -ENOMEM;
range = context_range_get(pcon);
range = sym_context_range_get(pcon);
if (!range)
return -errno;
if (context_range_set(bcon, range) != 0)
if (sym_context_range_set(bcon, range) != 0)
return -errno;
bcon_str = context_str(bcon);
bcon_str = sym_context_str(bcon);
if (!bcon_str)
return -ENOMEM;
sclass = string_to_security_class("process");
sclass = sym_string_to_security_class("process");
if (sclass == 0)
return -ENOSYS;
return RET_NERRNO(security_compute_create_raw(bcon_str, fcon, sclass, ret_label));
return RET_NERRNO(sym_security_compute_create_raw(bcon_str, fcon, sclass, ret_label));
#else
return -EOPNOTSUPP;
#endif
@ -563,7 +663,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
if (!label_hnd)
return 0;
r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
r = sym_selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
if (r < 0) {
/* No context specified by the policy? Proceed without setting it. */
if (errno == ENOENT)
@ -572,7 +672,7 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
return log_selinux_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
}
if (setfscreatecon_raw(filecon) < 0)
if (sym_setfscreatecon_raw(filecon) < 0)
return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
return 0;
@ -625,7 +725,7 @@ int mac_selinux_create_file_prepare_label(const char *path, const char *label) {
if (r <= 0)
return r;
if (setfscreatecon_raw(label) < 0)
if (sym_setfscreatecon_raw(label) < 0)
return log_selinux_enforcing_errno(errno, "Failed to set specified SELinux security context '%s' for '%s': %m", label, strna(path));
#endif
return 0;
@ -639,7 +739,7 @@ void mac_selinux_create_file_clear(void) {
if (selinux_init(/* force= */ false) <= 0)
return;
setfscreatecon_raw(NULL);
(void) sym_setfscreatecon_raw(NULL);
#endif
}
@ -654,7 +754,7 @@ int mac_selinux_create_socket_prepare(const char *label) {
if (r <= 0)
return r;
if (setsockcreatecon(label) < 0)
if (sym_setsockcreatecon_raw(label) < 0)
return log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s for sockets: %m", label);
#endif
@ -669,7 +769,7 @@ void mac_selinux_create_socket_clear(void) {
if (selinux_init(/* force= */ false) <= 0)
return;
setsockcreatecon_raw(NULL);
(void) sym_setsockcreatecon_raw(NULL);
#endif
}
@ -719,7 +819,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
goto skipped;
if (path_is_absolute(path))
r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
r = sym_selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
else {
_cleanup_free_ char *newpath = NULL;
@ -727,7 +827,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
if (r < 0)
return r;
r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
r = sym_selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK);
}
if (r < 0) {
@ -739,7 +839,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
if (r < 0)
return r;
} else {
if (setfscreatecon_raw(fcon) < 0) {
if (sym_setfscreatecon_raw(fcon) < 0) {
r = log_selinux_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", fcon, path);
if (r < 0)
return r;
@ -750,7 +850,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
r = RET_NERRNO(bind(fd, addr, addrlen));
if (context_changed)
(void) setfscreatecon_raw(NULL);
(void) sym_setfscreatecon_raw(NULL);
return r;

View File

@ -6,10 +6,58 @@
#include "forward.h"
#if HAVE_SELINUX
#include <selinux/avc.h>
#include <selinux/label.h>
#include <selinux/context.h>
#include <selinux/selinux.h> /* IWYU pragma: export */
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(char*, freecon, NULL);
#include "dlfcn-util.h"
int dlopen_libselinux(void);
extern DLSYM_PROTOTYPE(avc_open);
extern DLSYM_PROTOTYPE(context_free);
extern DLSYM_PROTOTYPE(context_new);
extern DLSYM_PROTOTYPE(context_range_get);
extern DLSYM_PROTOTYPE(context_range_set);
extern DLSYM_PROTOTYPE(context_str);
extern DLSYM_PROTOTYPE(fgetfilecon_raw);
extern DLSYM_PROTOTYPE(fini_selinuxmnt);
extern DLSYM_PROTOTYPE(freecon);
extern DLSYM_PROTOTYPE(getcon_raw);
extern DLSYM_PROTOTYPE(getfilecon_raw);
extern DLSYM_PROTOTYPE(getpeercon_raw);
extern DLSYM_PROTOTYPE(getpidcon_raw);
extern DLSYM_PROTOTYPE(is_selinux_enabled);
extern DLSYM_PROTOTYPE(security_compute_create_raw);
extern DLSYM_PROTOTYPE(security_getenforce);
extern DLSYM_PROTOTYPE(selabel_close);
extern DLSYM_PROTOTYPE(selabel_lookup_raw);
extern DLSYM_PROTOTYPE(selabel_open);
extern DLSYM_PROTOTYPE(selinux_check_access);
extern DLSYM_PROTOTYPE(selinux_getenforcemode);
extern DLSYM_PROTOTYPE(selinux_init_load_policy);
extern DLSYM_PROTOTYPE(selinux_path);
extern DLSYM_PROTOTYPE(selinux_set_callback);
extern DLSYM_PROTOTYPE(selinux_status_close);
extern DLSYM_PROTOTYPE(selinux_status_getenforce);
extern DLSYM_PROTOTYPE(selinux_status_open);
extern DLSYM_PROTOTYPE(selinux_status_policyload);
extern DLSYM_PROTOTYPE(setcon_raw);
extern DLSYM_PROTOTYPE(setexeccon_raw);
extern DLSYM_PROTOTYPE(setfilecon_raw);
extern DLSYM_PROTOTYPE(setfscreatecon_raw);
extern DLSYM_PROTOTYPE(setsockcreatecon_raw);
extern DLSYM_PROTOTYPE(string_to_security_class);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(char*, sym_freecon, freeconp, NULL);
#else
static inline int dlopen_libselinux(void) {
return -EOPNOTSUPP;
}
static inline void freeconp(char **p) {
assert(*p == NULL);
}

View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-varlink-idl.h"
#include "varlink-io.systemd.MuteConsole.h"
static SD_VARLINK_DEFINE_METHOD(
Mute,
SD_VARLINK_FIELD_COMMENT("Whether to mute the kernel's output to the console (defaults to true)."),
SD_VARLINK_DEFINE_INPUT(kernel, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether to mute PID1's output to the console (defaults to true)."),
SD_VARLINK_DEFINE_INPUT(pid1, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_MuteConsole,
"io.systemd.MuteConsole",
SD_VARLINK_INTERFACE_COMMENT("API for temporarily muting noisy output to the main kernel console"),
SD_VARLINK_SYMBOL_COMMENT("Mute kernel and PID 1 output to the main kernel console"),
&vl_method_Mute);

View File

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-varlink-idl.h"
extern const sd_varlink_interface vl_interface_io_systemd_MuteConsole;

View File

@ -36,6 +36,7 @@
#include "log.h"
#include "parse-util.h"
#include "pidref.h"
#include "printk-util.h"
#include "process-util.h"
#include "reboot-util.h"
#include "rlimit-util.h"
@ -272,42 +273,14 @@ int sync_with_progress(int fd) {
return r;
}
static int read_current_sysctl_printk_log_level(void) {
_cleanup_free_ char *sysctl_printk_vals = NULL, *sysctl_printk_curr = NULL;
int current_lvl;
const char *p;
int r;
r = sysctl_read("kernel/printk", &sysctl_printk_vals);
if (r < 0)
return log_debug_errno(r, "Cannot read sysctl kernel.printk: %m");
p = sysctl_printk_vals;
r = extract_first_word(&p, &sysctl_printk_curr, NULL, 0);
if (r < 0)
return log_debug_errno(r, "Failed to split out kernel printk priority: %m");
if (r == 0)
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Short read while reading kernel.printk sysctl");
r = safe_atoi(sysctl_printk_curr, &current_lvl);
if (r < 0)
return log_debug_errno(r, "Failed to parse kernel.printk sysctl: %s", sysctl_printk_vals);
return current_lvl;
}
static void bump_sysctl_printk_log_level(int min_level) {
int current_lvl, r;
/* Set the logging level to be able to see messages with log level smaller or equal to min_level */
current_lvl = read_current_sysctl_printk_log_level();
int current_lvl = sysctl_printk_read();
if (current_lvl < 0 || current_lvl >= min_level + 1)
return;
r = sysctl_writef("kernel/printk", "%i", min_level + 1);
if (r < 0)
log_debug_errno(r, "Failed to bump kernel.printk to %i: %m", min_level + 1);
(void) sysctl_printk_write(min_level + 1);
}
static void init_watchdog(void) {

View File

@ -10,10 +10,10 @@
#include "iovec-util.h"
#include "log.h"
#include "main-func.h"
#include "path-lookup.h"
#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "varlink-util.h"
static int process_vsock_cid(unsigned cid, const char *port) {
int r;
@ -135,23 +135,57 @@ static int process_vsock_mux(const char *path, const char *port) {
return 0;
}
static int process_machine(const char *machine, const char *port) {
static int fetch_machine(const char *machine, RuntimeScope scope, sd_json_variant **ret) {
int r;
assert(machine);
assert(ret);
_cleanup_free_ char *addr = NULL;
r = runtime_directory_generic(scope, "machine/io.systemd.Machine", &addr);
if (r < 0)
return r;
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
r = sd_varlink_connect_address(&vl, addr);
if (r < 0)
return log_error_errno(r, "Failed to connect to machined on %s: %m", addr);
_cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
const char *error_id;
r = sd_varlink_callbo(
vl,
"io.systemd.Machine.List",
&result,
&error_id,
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(machine)));
if (r < 0)
return log_error_errno(r, "Failed to issue io.systemd.Machine.List() varlink call: %m");
if (error_id) {
if (streq(error_id, "io.systemd.Machine.NoSuchMachine"))
return -ESRCH;
r = sd_varlink_error_to_errno(error_id, result); /* If this is a system errno style error, output it with %m */
if (r != -EBADR)
return log_error_errno(r, "Failed to issue io.systemd.Machine.List() varlink call: %m");
return log_error_errno(r, "Failed to issue io.systemd.Machine.List() varlink call: %s", error_id);
}
*ret = TAKE_PTR(result);
return 0;
}
static int process_machine(const char *machine, const char *port) {
int r;
assert(machine);
assert(port);
r = sd_varlink_connect_address(&vl, "/run/systemd/machine/io.systemd.Machine");
if (r < 0)
return log_error_errno(r, "Failed to connect to machined on /run/systemd/machine/io.systemd.Machine: %m");
_cleanup_(sd_json_variant_unrefp) sd_json_variant *result = NULL;
r = varlink_callbo_and_log(
vl,
"io.systemd.Machine.List",
&result,
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(machine)));
r = fetch_machine(machine, RUNTIME_SCOPE_USER, &result);
if (r == -ESRCH)
r = fetch_machine(machine, RUNTIME_SCOPE_SYSTEM, &result);
if (r < 0)
return r;
@ -167,7 +201,7 @@ static int process_machine(const char *machine, const char *port) {
return log_error_errno(r, "Failed to parse Varlink reply: %m");
if (cid == VMADDR_CID_ANY)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine has no AF_VSOCK CID assigned.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine %s has no AF_VSOCK CID assigned.", machine);
return process_vsock_cid(cid, port);
}

View File

@ -58,7 +58,6 @@ executables += [
'dependencies' : [
libcap,
liblz4_cflags,
libselinux,
libxz_cflags,
libzstd_cflags,
threads,

View File

@ -218,7 +218,7 @@ common_test_dependencies = [
libmount_cflags,
librt,
libseccomp_cflags,
libselinux,
libselinux_cflags,
threads,
]
@ -432,7 +432,7 @@ executables += [
},
test_template + {
'sources' : files('test-selinux.c'),
'dependencies' : libselinux,
'dependencies' : libselinux_cflags,
},
test_template + {
'sources' : files('test-set-disable-mempool.c'),

View File

@ -22,6 +22,7 @@
#include "pkcs11-util.h"
#include "qrcode-util.h"
#include "seccomp-util.h"
#include "selinux-util.h"
#include "tests.h"
#include "tpm2-util.h"
@ -60,6 +61,7 @@ static int run(int argc, char **argv) {
ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID);
ASSERT_DLOPEN(dlopen_libseccomp, HAVE_SECCOMP);
ASSERT_DLOPEN(dlopen_libmount, true);
ASSERT_DLOPEN(dlopen_libselinux, HAVE_SELINUX);
return 0;
}

View File

@ -48,17 +48,20 @@ TEST(verity_mappings) {
for (PartitionDesignator p = 0; p < _PARTITION_DESIGNATOR_MAX; p++) {
PartitionDesignator q;
q = partition_verity_of(p);
assert_se(q < 0 || partition_verity_to_data(q) == p);
q = partition_verity_hash_of(p);
assert_se(q < 0 || partition_verity_hash_to_data(q) == p);
q = partition_verity_sig_of(p);
assert_se(q < 0 || partition_verity_sig_to_data(q) == p);
q = partition_verity_to_data(p);
assert_se(q < 0 || partition_verity_of(q) == p);
q = partition_verity_hash_to_data(p);
assert_se(q < 0 || partition_verity_hash_of(q) == p);
q = partition_verity_sig_to_data(p);
assert_se(q < 0 || partition_verity_sig_of(q) == p);
q = partition_verity_to_data(p);
assert_se(q < 0 || partition_verity_hash_of(q) == p || partition_verity_sig_of(q) == p);
}
}

View File

@ -24,6 +24,7 @@
#include "varlink-io.systemd.Manager.h"
#include "varlink-io.systemd.ManagedOOM.h"
#include "varlink-io.systemd.MountFileSystem.h"
#include "varlink-io.systemd.MuteConsole.h"
#include "varlink-io.systemd.NamespaceResource.h"
#include "varlink-io.systemd.Network.h"
#include "varlink-io.systemd.PCRExtend.h"
@ -166,6 +167,8 @@ TEST(parse_format) {
print_separator();
test_parse_format_one(&vl_interface_io_systemd_UserDatabase);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_MuteConsole);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_NamespaceResource);
print_separator();
test_parse_format_one(&vl_interface_io_systemd_Journal);

View File

@ -232,7 +232,7 @@ executables += [
udev_test_template + {
'sources' : files('test-udev-rule-runner.c'),
'dependencies' : udev_dependencies + [
libselinux,
libselinux_cflags,
],
'type' : 'manual',
},

View File

@ -103,7 +103,8 @@ static int run(int argc, char *argv[]) {
/* Let's make sure the test runs with selinux assumed disabled. */
#if HAVE_SELINUX
fini_selinuxmnt();
if (dlopen_libselinux() >= 0)
sym_fini_selinuxmnt();
#endif
mac_selinux_retest();

View File

@ -265,7 +265,7 @@ static int verb_probe(UdevEvent *event, sd_device *dev) {
}
/* Indicate whether this partition has verity protection */
PartitionDesignator dv = partition_verity_of(d);
PartitionDesignator dv = partition_verity_hash_of(d);
if (dv >= 0 && image->partitions[dv].found) {
/* Add one property that indicates as a boolean whether Verity is available at all for this */
_cleanup_free_ char *f = NULL;

View File

@ -587,8 +587,13 @@ static int reply_callback(
else
r = *ret = log_error_errno(SYNTHETIC_ERRNO(EBADE), "Method call failed: %s", error);
}
} else
} else {
/* Let the caller know we have received at least one reply now. This is useful for
* subscription style interfaces where the first reply indicates the subscription being
* successfully enabled. */
(void) sd_notify(/* unset_environment= */ false, "READY=1");
r = 0;
}
if (!arg_quiet)
sd_json_variant_dump(parameters, arg_json_format_flags, stdout, NULL);

View File

@ -0,0 +1,40 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail
if ! command -v systemd-mute-console >/dev/null; then
echo "systemd-mute-console is not installed, skipping the test"
exit 0
fi
PID="$(systemd-notify --fork -- systemd-mute-console)"
sleep .5
kill "$PID"
unset PID
(! systemd-mute-console --kernel=no --pid1=no)
PID="$(systemd-notify --fork -- systemd-mute-console --kernel=yes --pid1=yes)"
sleep .5
kill "$PID"
unset PID
varlinkctl introspect "$(which systemd-mute-console)"
PID="$(systemd-notify --fork -- varlinkctl call -E "$(which systemd-mute-console)" io.systemd.MuteConsole.Mute '{}')"
sleep .5
kill "$PID"
unset PID
PID="$(systemd-notify --fork -- varlinkctl call -E "$(which systemd-mute-console)" io.systemd.MuteConsole.Mute '{"pid1":true, "kernel":true}')"
sleep .5
kill "$PID"
unset PID
varlinkctl introspect /run/systemd/io.systemd.MuteConsole
PID="$(systemd-notify --fork -- varlinkctl call -E /run/systemd/io.systemd.MuteConsole io.systemd.MuteConsole.Mute '{}')"
sleep .5
kill "$PID"
unset PID

View File

@ -143,6 +143,12 @@ units = [
},
{ 'file' : 'modprobe@.service' },
{ 'file' : 'multi-user.target' },
{
'file' : 'systemd-mute-console.socket',
'symlinks' : ['sockets.target.wants/']
},
{ 'file' : 'systemd-mute-console@.service' },
{ 'file' : 'system-systemd\\x2dmute\\x2dconsole.slice' },
{ 'file' : 'network-online.target' },
{ 'file' : 'network-pre.target' },
{ 'file' : 'network.target' },

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Console Output Muting Service Slice
Documentation=man:systemd-mute-console(8)
DefaultDependencies=no
Conflicts=shutdown.target
Before=shutdown.target
[Slice]
# Serialize requests to mute the console.
ConcurrencySoftMax=1

View File

@ -22,6 +22,7 @@ After=systemd-remount-fs.service
After=systemd-sysusers.service systemd-tmpfiles-setup.service
# Let vconsole-setup do its setup before starting user interaction:
After=systemd-vconsole-setup.service
After=systemd-mute-console.socket
Wants=first-boot-complete.target
Before=first-boot-complete.target sysinit.target
@ -31,7 +32,7 @@ Before=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=systemd-firstboot --prompt-locale --prompt-keymap --prompt-timezone --prompt-root-password
ExecStart=systemd-firstboot --prompt-locale --prompt-keymap --prompt-timezone --prompt-root-password --mute-console=yes
StandardOutput=tty
StandardInput=tty
StandardError=tty

View File

@ -0,0 +1,22 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Console Output Muting Service Socket
Documentation=man:systemd-mute-console(8)
DefaultDependencies=no
Before=sockets.target
Conflicts=shutdown.target
Before=shutdown.target
[Socket]
ListenStream=/run/systemd/io.systemd.MuteConsole
FileDescriptorName=varlink
SocketMode=0600
Accept=yes

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Console Output Muting Service
Documentation=man:systemd-mute-console(8)
DefaultDependencies=no
Conflicts=shutdown.target
Before=shutdown.target
[Service]
ExecStart=systemd-mute-console