1
0
mirror of https://github.com/systemd/systemd synced 2026-03-15 09:34:47 +01:00

Compare commits

...

14 Commits

Author SHA1 Message Date
Jörg Behrmann
cab4b9defd kernel-install: handle removal unsuccessful UKIs and loader entries separately
When a tries file exists, 90-uki-copy.install removes a previous UKI of the
same kernel version and all it's unbooted variants. This removal is guarded
behind a check for the existence of the already booted UKI, i.e. if uki.efi
already exists, uki.efi and uki+*.efi will be removed.

This leaves the edge case that if uki.efi does not exist, but only an unbooted,
e.g. uki+3.efi, it will not be removed. This is not a problem, if the number of
tries is constant between both builds, since a new uki+3.efi would overwrite
the existing one, but if the number of tries is changed to, e.g. uki+5.efi, we
are left with both uki+3.efi and uki+5.efi.

The same is done for loader entries.
2026-01-27 15:53:48 +01:00
Zbigniew Jędrzejewski-Szmek
69d130aac5
preparations for installer PR (#40446)
As suggested by @keszybz the generic preparatory work split out of
#38764
2026-01-27 15:04:47 +01:00
Daniel Foster
49811c6715 man/custom-html: support dark mode
Use the browser's default style and opt in for dark mode.

Has the bonus of removing some
[deprecated attributes](https://developer.mozilla.org/docs/Web/HTML/Reference/Elements/body#deprecated_attributes).
2026-01-27 13:43:33 +01:00
Peter Oliver
bee663e22a NEWS: Remember to mention new option SYSTEMD_COLORS=auto-24bit 2026-01-27 12:27:19 +01:00
Zbigniew Jędrzejewski-Szmek
56b9c3ad40
sd-bus: allow receiving messages with MSG_CTRUNC set (#40089)
In the event that we can't receive all of the fds from the message
(which can happen for a number of reasons including LSM denials or
hitting the fd limit of the process) the kernel will set the MSG_CTRUNC
flag.  Through our use of recvmsg_safe() we've been treating this as a
fatal error, which will result in dropping the connection.

Let's dial that back a bit: we can receive the message, but when the
user attempts to access the missing fds via sd_bus_message_read_basic()
we can return the (existing) error code of -EBADMSG to indicate that the
fd is missing.

We can do this by using recvmsg() directly, and relaxing some of the
checks on message creation: when (and only when) we have received
MSG_CTRUNC we allow a smaller than expected (per the header) number of
fds to be present.  The error check in sd_bus_message_read_basic() was
already there so we don't need to do anything about that.

This puts the receiver of the message into a difficult situation: you
can call sd_bus_message_read_basic() as often as you want but as long as
it keeps returning -EBADMSG it won't progress through the message and
you won't be able to close whatever container you're in.  That means
that the user will probably need to abandon processing the message
anyway.  So why not just drop the message up front?  This approach is
more likely to yield a useful error message, which will be invaluable
for people trying to track down problems caused by LSM denials.

Fixes #34688
2026-01-27 12:07:33 +01:00
Michael Vogt
8c5c04ed27 vmspawn: keep stderr fd connected when running ssh-keygen
When vmspawn executes ssh-keygen it currently hides all std{out,err}.
This is not ideal when errors happen, so this commit tweaks the
code to include stderr in the output.

My use case is that I recently ran into the issue that inside a
`mkosi box` my systemd-homed user was not available so ssh-keygen
errored with `No user exists for uid 1000` [0] but that error was
not visible, only the generic:
`'/usr/bin/ssh-keygen' failed with exit status 255.`
was displayed.

This also adds FORK_REOPEN_LOG to the pidref_safe_fork flags,
thanks to Mike Yuan for the suggestion.

[0] Arguably this is also an issue in ssh-keygen because it does
not need to do the user lookup when `-f /path/` is passed.
2026-01-27 10:35:14 +01:00
Allison Karlitskaya
744d589632 sd-bus: add test cases for truncated fds
We add some test cases for the previous commits: first (with Claude's
help) we exercise the message creation API internally by passing it
various combinations of incorrect fds with the might_be_truncated flag
set to true or false.

Then we try more of a "real world" test by lowering our fd limit and
sending ourselves a message via the bus and making sure that we
successfully receive a message that has had at least some of its fds
truncated.
2026-01-26 16:07:26 +01:00
Allison Karlitskaya
6c8de404c9 sd-bus: allow receiving messages with MSG_CTRUNC set
In the event that we can't receive all of the fds from the message
(which can happen for a number of reasons including LSM denials or
hitting the fd limit of the process) the kernel will set the MSG_CTRUNC
flag.  Through our use of recvmsg_safe() we've been treating this as a
fatal error, which will result in dropping the connection.

Let's dial that back a bit: we can receive the message, but when the
user attempts to access the missing fds via sd_bus_message_read_basic()
we can return the (existing) error code of -EBADMSG to indicate that the
fd is missing.

We can do this by using recvmsg() directly, and relaxing some of the
checks on message creation: when (and only when) we have received
MSG_CTRUNC we allow a smaller than expected (per the header) number of
fds to be present.  The error check in sd_bus_message_read_basic() was
already there so we don't need to do anything about that.

This puts the receiver of the message into a difficult situation: you
can call sd_bus_message_read_basic() as often as you want but as long as
it keeps returning -EBADMSG it won't progress through the message and
you won't be able to close whatever container you're in.  That means
that the user will probably need to abandon processing the message
anyway.  So why not just drop the message up front?  This approach is
more likely to yield a useful error message, which will be invaluable
for people trying to track down problems caused by LSM denials.

Fixes #34688
2026-01-26 16:07:23 +01:00
Lennart Poettering
65a6da9c96 conf-files: add flag so that we don't always prefix returned paths with the root dir path used
This is useful in tools such as system-repart where we show the
definition file paths a lot in our output, but if prefixed with the root
path we'd show a temporary mount dir when operating on a image file.
Hence, let's drop the prefix here, and show only the path within the
image.
2026-01-25 20:51:50 +01:00
Lennart Poettering
8a4f856977 conf-files: rename .name field to .filename to make clearer what precisely it is the name of 2026-01-25 20:51:50 +01:00
Lennart Poettering
9b116a0871 boot-entry: plug through XAT_FDROOT 2026-01-25 20:51:50 +01:00
Lennart Poettering
64ef947022 os-util: support XAT_FDROOT everywhere 2026-01-25 20:51:50 +01:00
Lennart Poettering
6ecfa12af0 conf-files: add support for root_fd based operation
Let's make sure we can safely load configuration files based on a root
fd, including XAT_FDROOT.

(While we are at it, always pass path to root fs before fd to root fs,
following our recently updated CODING_STYLE)
2026-01-25 20:51:50 +01:00
Lennart Poettering
17ade5b2af sd-id128-util: allow XAT_FDROOT pass through in id128_get_machine_at() 2026-01-25 20:51:50 +01:00
35 changed files with 636 additions and 173 deletions

7
NEWS
View File

@ -33,9 +33,10 @@ CHANGES WITH 260 in spe:
Changes in other components:
* New options SYSTEMD_COLORS=auto-16 and SYSTEMD_COLORS=auto-256, which
are like SYSTEMD_COLORS=16 and SYSTEMD_COLORS=256 respectively when
output is to a non-dumb TTY, and like SYSTEMD_COLORS=no otherwise.
* New options SYSTEMD_COLORS=auto-16, SYSTEMD_COLORS=auto-256, and
SYSTEMD_COLORS=auto-24bit, which are like SYSTEMD_COLORS=16,
SYSTEMD_COLORS=256, and SYSTEMD_COLORS=24bit respectively when output
is to a non-dumb TTY, and like SYSTEMD_COLORS=no otherwise.
CHANGES WITH 259:

View File

@ -268,6 +268,10 @@
<!-- add Index link at top of page -->
<xsl:template name="user.header.content">
<style>
:root {
color-scheme: light dark;
}
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
@ -312,6 +316,13 @@
<xsl:text>"</xsl:text>
</xsl:template>
<!-- copied from docbook to remove the static color declarations -->
<xsl:template name="body.attributes">
<xsl:if test="starts-with($writing.mode, 'rl')">
<xsl:attribute name="dir">rtl</xsl:attribute>
</xsl:if>
</xsl:template>
<!-- Switch things to UTF-8, ISO-8859-1 is soo yesteryear -->
<xsl:output method="html" encoding="UTF-8" indent="no"/>

View File

@ -24,7 +24,7 @@ ConfFile* conf_file_free(ConfFile *c) {
if (!c)
return NULL;
free(c->name);
free(c->filename);
free(c->result);
free(c->original_path);
free(c->resolved_path);
@ -44,13 +44,20 @@ static int conf_files_log_level(ConfFilesFlags flags) {
return FLAGS_SET(flags, CONF_FILES_WARN) ? LOG_WARNING : LOG_DEBUG;
}
static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *dirs, int *ret_rfd, char **ret_root, char ***ret_dirs) {
static int prepare_dirs(
const char *root,
ConfFilesFlags flags,
char * const *dirs,
char **ret_root,
int *ret_rfd,
char ***ret_dirs) {
_cleanup_free_ char *root_abs = NULL;
_cleanup_strv_free_ char **dirs_abs = NULL;
int r;
assert(ret_rfd);
assert(ret_root);
assert(ret_rfd);
assert(ret_dirs || strv_isempty(dirs));
int log_level = conf_files_log_level(flags);
@ -65,6 +72,7 @@ static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *di
return log_oom_full(log_level);
}
_cleanup_close_ int rfd = XAT_FDROOT;
if (root) {
/* When a non-trivial root is specified, we will prefix the result later. Hence, it is not
* necessary to modify each config directories here. but needs to normalize the root directory. */
@ -73,6 +81,11 @@ static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *di
return log_full_errno(log_level, r, "Failed to make '%s' absolute: %m", root);
path_simplify(root_abs);
rfd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
if (rfd < 0)
return log_full_errno(log_level, errno, "Failed to open '%s': %m", root_abs);
} else if (ret_dirs) {
/* When an empty root or "/" is specified, we will open "/" below, hence we need to make
* each config directory absolute if relative. */
@ -81,12 +94,8 @@ static int prepare_dirs(const char *root, ConfFilesFlags flags, char * const *di
return log_full_errno(log_level, r, "Failed to make directories absolute: %m");
}
_cleanup_close_ int rfd = open(empty_to_root(root_abs), O_CLOEXEC|O_DIRECTORY|O_PATH);
if (rfd < 0)
return log_full_errno(log_level, errno, "Failed to open '%s': %m", empty_to_root(root_abs));
*ret_rfd = TAKE_FD(rfd);
*ret_root = TAKE_PTR(root_abs);
*ret_rfd = TAKE_FD(rfd);
if (ret_dirs)
*ret_dirs = TAKE_PTR(dirs_abs);
return 0;
@ -135,8 +144,8 @@ static ChaseFlags conf_files_chase_flags(ConfFilesFlags flags) {
}
static int conf_file_chase_and_verify(
int rfd,
const char *root, /* for logging, can be NULL */
int rfd,
const char *original_path, /* for logging */
const char *path,
const char *name,
@ -151,7 +160,7 @@ static int conf_file_chase_and_verify(
struct stat st = {};
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(original_path);
assert(path);
assert(name);
@ -261,18 +270,25 @@ static int conf_file_chase_and_verify(
return 0;
}
int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile **ret) {
int conf_file_new_at(
const char *path,
const char *root,
int rfd,
ConfFilesFlags flags,
ConfFile **ret) {
int r;
assert(path);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret);
int log_level = conf_files_log_level(flags);
_cleanup_free_ char *root = NULL;
if (rfd >= 0)
(void) fd_get_path(rfd, &root);
_cleanup_free_ char *_root = NULL;
if (DEBUG_LOGGING && !root) {
(void) fd_get_path(rfd, &_root);
root = _root;
}
_cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1);
if (!c)
@ -286,7 +302,7 @@ int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile *
if (!c->original_path)
return log_oom_full(log_level);
r = path_extract_filename(path, &c->name);
r = path_extract_filename(path, &c->filename);
if (r < 0)
return log_full_errno(log_level, r, "Failed to extract filename from '%s': %m", path);
@ -302,16 +318,16 @@ int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile *
return log_full_errno(log_level, r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(dirpath));
}
c->result = path_join(resolved_dirpath, c->name);
c->result = path_join(resolved_dirpath, c->filename);
if (!c->result)
return log_oom_full(log_level);
r = conf_file_chase_and_verify(
rfd,
root,
rfd,
c->original_path,
c->result,
c->name,
c->filename,
/* masked= */ NULL,
flags,
&c->resolved_path,
@ -332,7 +348,7 @@ int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, Conf
_cleanup_free_ char *root_abs = NULL;
_cleanup_close_ int rfd = -EBADF;
r = prepare_dirs(root, flags, /* dirs= */ NULL, &rfd, &root_abs, /* ret_dirs= */ NULL);
r = prepare_dirs(root, flags, /* dirs= */ NULL, &root_abs, &rfd, /* ret_dirs= */ NULL);
if (r < 0)
return r;
@ -346,7 +362,7 @@ int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, Conf
}
_cleanup_(conf_file_freep) ConfFile *c = NULL;
r = conf_file_new_at(path, rfd, flags, &c);
r = conf_file_new_at(path, root_abs, rfd, flags, &c);
if (r < 0)
return r;
@ -367,8 +383,8 @@ static int files_add(
DIR *dir,
const char *original_dirpath,
const char *resolved_dirpath,
int rfd,
const char *root, /* for logging, can be NULL */
int rfd,
Hashmap **files,
Set **masked,
const char *suffix,
@ -379,7 +395,7 @@ static int files_add(
assert(dir);
assert(original_dirpath);
assert(resolved_dirpath);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(files);
assert(masked);
@ -420,8 +436,8 @@ static int files_add(
_cleanup_close_ int fd = -EBADF;
struct stat st;
r = conf_file_chase_and_verify(
rfd,
root,
rfd,
original_path,
p,
de->d_name,
@ -440,7 +456,7 @@ static int files_add(
return log_oom_full(log_level);
*c = (ConfFile) {
.name = strdup(de->d_name),
.filename = strdup(de->d_name),
.result = TAKE_PTR(p),
.original_path = TAKE_PTR(original_path),
.resolved_path = TAKE_PTR(resolved_path),
@ -448,10 +464,10 @@ static int files_add(
.st = st,
};
if (!c->name)
if (!c->filename)
return log_oom_full(log_level);
r = hashmap_ensure_put(files, &conf_file_hash_ops, c->name, c);
r = hashmap_ensure_put(files, &conf_file_hash_ops, c->filename, c);
if (r < 0) {
assert(r == -ENOMEM);
return log_oom_full(log_level);
@ -481,7 +497,7 @@ static int dump_files(Hashmap *fh, const char *root, ConfFilesFlags flags, ConfF
/* Hence, we need to remove them from the hashmap. */
FOREACH_ARRAY(i, files, n_files)
assert_se(hashmap_remove(fh, (*i)->name) == *i);
assert_se(hashmap_remove(fh, (*i)->filename) == *i);
if (root)
FOREACH_ARRAY(i, files, n_files) {
@ -522,8 +538,8 @@ static int copy_and_sort_files_from_hashmap(
const char *add = NULL;
if (FLAGS_SET(flags, CONF_FILES_BASENAME))
add = c->name;
else if (root) {
add = c->filename;
else if (root && !FLAGS_SET(flags, CONF_FILES_DONT_PREFIX_ROOT)) {
_cleanup_free_ char *p = NULL;
r = chaseat_prefix_root(c->result, root, &p);
@ -574,22 +590,22 @@ static int insert_replacement(Hashmap **fh, ConfFile *replacement, ConfFilesFlag
/* This consumes the input ConfFile. */
ConfFile *existing = hashmap_get(*fh, c->name);
ConfFile *existing = hashmap_get(*fh, c->filename);
if (existing) {
log_debug("An entry with higher priority '%s' -> '%s' already exists, ignoring the replacement: %s",
existing->name, existing->result, c->original_path);
existing->filename, existing->result, c->original_path);
*ret = NULL;
return 0;
}
r = hashmap_ensure_put(fh, &conf_file_hash_ops, c->name, c);
r = hashmap_ensure_put(fh, &conf_file_hash_ops, c->filename, c);
if (r < 0) {
assert(r == -ENOMEM);
return log_oom_full(conf_files_log_level(flags));
}
assert(r > 0);
log_debug("Inserted replacement: '%s' -> '%s'", c->name, c->result);
log_debug("Inserted replacement: '%s' -> '%s'", c->filename, c->result);
*ret = TAKE_PTR(c);
return 0;
@ -597,8 +613,8 @@ static int insert_replacement(Hashmap **fh, ConfFile *replacement, ConfFilesFlag
static int conf_files_list_impl(
const char *suffix,
int rfd,
const char *root, /* for logging, can be NULL */
int rfd,
ConfFilesFlags flags,
const char * const *dirs,
const char *replacement,
@ -611,13 +627,13 @@ static int conf_files_list_impl(
const ConfFile *inserted = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret);
root = empty_to_root(root);
if (replacement) {
r = conf_file_new_at(replacement, rfd, flags & CONF_FILES_WARN, &c);
r = conf_file_new_at(replacement, root, rfd, flags & CONF_FILES_WARN, &c);
if (r < 0)
return r;
}
@ -635,13 +651,13 @@ static int conf_files_list_impl(
continue;
}
if (c && streq_ptr(path_startswith(c->result, path), c->name)) {
if (c && streq_ptr(path_startswith(c->result, path), c->filename)) {
r = insert_replacement(&fh, TAKE_PTR(c), flags, &inserted);
if (r < 0)
return r;
}
r = files_add(dir, *p, path, rfd, root, &fh, &masked, suffix, flags);
r = files_add(dir, *p, path, root, rfd, &fh, &masked, suffix, flags);
if (r == -ENOMEM)
return r;
}
@ -673,11 +689,11 @@ int conf_files_list_strv(
assert(ret);
r = prepare_dirs(root, flags, (char**) dirs, &rfd, &root_abs, &dirs_abs);
r = prepare_dirs(root, flags, (char**) dirs, &root_abs, &rfd, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(suffix, rfd, root_abs, flags, (const char * const *) dirs_abs,
r = conf_files_list_impl(suffix, root_abs, rfd, flags, (const char * const *) dirs_abs,
/* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@ -702,11 +718,11 @@ int conf_files_list_strv_full(
assert(ret_files);
assert(ret_n_files);
r = prepare_dirs(root, flags, (char**) dirs, &rfd, &root_abs, &dirs_abs);
r = prepare_dirs(root, flags, (char**) dirs, &root_abs, &rfd, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(suffix, rfd, root_abs, flags, (const char * const *) dirs_abs,
r = conf_files_list_impl(suffix, root_abs, rfd, flags, (const char * const *) dirs_abs,
/* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@ -725,13 +741,13 @@ int conf_files_list_strv_at(
_cleanup_free_ char *root = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret);
if (rfd >= 0)
if (DEBUG_LOGGING)
(void) fd_get_path(rfd, &root); /* for logging */
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
r = conf_files_list_impl(suffix, root, rfd, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@ -750,14 +766,14 @@ int conf_files_list_strv_at_full(
_cleanup_free_ char *root = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(ret_files);
assert(ret_n_files);
if (rfd >= 0)
if (DEBUG_LOGGING)
(void) fd_get_path(rfd, &root); /* for logging */
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
r = conf_files_list_impl(suffix, root, rfd, flags, dirs, /* replacement= */ NULL, &fh, /* ret_inserted= */ NULL);
if (r < 0)
return r;
@ -848,11 +864,11 @@ int conf_files_list_with_replacement(
assert(ret_files);
r = prepare_dirs(root, flags, config_dirs, &rfd, &root_abs, &dirs_abs);
r = prepare_dirs(root, flags, config_dirs, &root_abs, &rfd, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(".conf", rfd, root_abs, flags, (const char * const *) dirs_abs,
r = conf_files_list_impl(".conf", root_abs, rfd, flags, (const char * const *) dirs_abs,
replacement, &fh, ret_inserted ? &c : NULL);
if (r < 0)
return r;
@ -878,6 +894,7 @@ int conf_files_list_dropins(
char ***ret,
const char *dropin_dirname,
const char *root,
int root_fd,
ConfFilesFlags flags,
const char * const *dirs) {
@ -894,7 +911,7 @@ int conf_files_list_dropins(
if (r < 0)
return log_oom_full(conf_files_log_level(flags));
return conf_files_list_strv(ret, ".conf", root, flags, (const char* const*) dropin_dirs);
return conf_files_list_strv_at(ret, ".conf", root_fd, flags, (const char* const*) dropin_dirs);
}
/**

View File

@ -15,14 +15,15 @@ typedef enum ConfFilesFlags {
CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY,
CONF_FILES_TRUNCATE_SUFFIX = 1 << 6, /* truncate specified suffix from return filename or path */
CONF_FILES_WARN = 1 << 7, /* warn on some errors */
CONF_FILES_DONT_PREFIX_ROOT = 1 << 8, /* don't prefix the specified root path to the resulting paths */
} ConfFilesFlags;
typedef struct ConfFile {
char *name; /* name of a file found in config directories */
char *result; /* resolved config directory with the original file name found in the directory */
char *original_path; /* original config directory with the original file name found in the directory */
char *resolved_path; /* fully resolved path, where the filename part of the path may be different from the original name */
int fd; /* O_PATH fd to resolved_path, -EBADF if the resolved_path does not exist */
char *filename; /* filename of the discovered file (i.e. without any directory prefix) */
char *result; /* full path to the file (with the directory prefix fully resolved, but the filename part left as is) */
char *original_path; /* full path to the file (original non-resolved directory prefix + filename part left as is) */
char *resolved_path; /* fully resolved path to the file with both directory prefix and filename fully resolved */
int fd; /* O_PATH fd to resolved_path, -EBADF if resolved_path does not exist */
struct stat st; /* stat of the file. */
} ConfFile;
@ -30,7 +31,7 @@ ConfFile* conf_file_free(ConfFile *c);
DEFINE_TRIVIAL_CLEANUP_FUNC(ConfFile*, conf_file_free);
void conf_file_free_many(ConfFile **array, size_t n);
int conf_file_new_at(const char *path, int rfd, ConfFilesFlags flags, ConfFile **ret);
int conf_file_new_at(const char *path, const char *root, int rfd, ConfFilesFlags flags, ConfFile **ret);
int conf_file_new(const char *path, const char *root, ConfFilesFlags flags, ConfFile **ret);
int conf_files_list(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dir);
@ -57,6 +58,7 @@ int conf_files_list_dropins(
char ***ret,
const char *dropin_dirname,
const char *root,
int root_fd,
ConfFilesFlags flags,
const char * const *dirs);

View File

@ -168,7 +168,7 @@ int open_os_release_at(int rfd, char **ret_path, int *ret_fd) {
const char *e;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
e = secure_getenv("SYSTEMD_OS_RELEASE");
if (e)
@ -184,13 +184,15 @@ int open_os_release_at(int rfd, char **ret_path, int *ret_fd) {
}
int open_os_release(const char *root, char **ret_path, int *ret_fd) {
_cleanup_close_ int rfd = -EBADF, fd = -EBADF;
_cleanup_close_ int rfd = XAT_FDROOT, fd = -EBADF;
_cleanup_free_ char *p = NULL;
int r;
rfd = open(empty_to_root(root), O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
if (!empty_or_root(root)) {
rfd = open(root, O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
}
r = open_os_release_at(rfd, ret_path ? &p : NULL, ret_fd ? &fd : NULL);
if (r < 0)
@ -223,7 +225,7 @@ int open_extension_release_at(
const char *p;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(!extension || (image_class >= 0 && image_class < _IMAGE_CLASS_MAX));
if (!extension)
@ -330,13 +332,15 @@ int open_extension_release(
char **ret_path,
int *ret_fd) {
_cleanup_close_ int rfd = -EBADF, fd = -EBADF;
_cleanup_close_ int rfd = XAT_FDROOT, fd = -EBADF;
_cleanup_free_ char *p = NULL;
int r;
rfd = open(empty_to_root(root), O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
if (!empty_or_root(root)) {
rfd = open(root, O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
}
r = open_extension_release_at(rfd, image_class, extension, relax_extension_release_check,
ret_path ? &p : NULL, ret_fd ? &fd : NULL);
@ -366,7 +370,7 @@ static int parse_extension_release_atv(
_cleanup_free_ char *p = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
r = open_extension_release_at(rfd, image_class, extension, relax_extension_release_check, &p, &fd);
if (r < 0)
@ -385,7 +389,7 @@ int parse_extension_release_at_sentinel(
va_list ap;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
va_start(ap, extension);
r = parse_extension_release_atv(rfd, image_class, extension, relax_extension_release_check, ap);
@ -400,17 +404,20 @@ int parse_extension_release_sentinel(
const char *extension,
...) {
_cleanup_close_ int rfd = -EBADF;
_cleanup_close_ int rfd = XAT_FDROOT;
va_list ap;
int r;
rfd = open(empty_to_root(root), O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
if (!empty_or_root(root)) {
rfd = open(root, O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
}
va_start(ap, extension);
r = parse_extension_release_atv(rfd, image_class, extension, relax_extension_release_check, ap);
va_end(ap);
return r;
}

View File

@ -842,11 +842,10 @@ static int parse_config_file(void) {
(const char* const*) files,
(const char* const*) dirs,
"user.conf.d",
/* root= */ NULL,
"Manager\0",
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
NULL, NULL, NULL);
/* userdata= */ NULL);
}
/* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we use

View File

@ -115,8 +115,14 @@ if [ -f "$TRIES_FILE" ]; then
if [ -f "$LOADER_ENTRY" ]; then
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
echo "Removing previous loader entry '$LOADER_ENTRY' without boot counting." >&2
rm -f "$LOADER_ENTRY" "${LOADER_ENTRY%.conf}+"*.conf
rm -f "$LOADER_ENTRY"
fi
for loaderentry in "${LOADER_ENTRY%.conf}+"*.conf; do
[ "$loaderentry" = "${LOADER_ENTRY%.conf}+*.conf" ] && break
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
echo "Removing previous loader entry '$loaderentry' that has not yet booted successfully." >&2
rm -f "$loaderentry"
done
LOADER_ENTRY="${LOADER_ENTRY%.conf}+$TRIES.conf"
fi

View File

@ -70,8 +70,14 @@ if [ -f "$TRIES_FILE" ]; then
if [ -f "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi" ]; then
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
echo "Removing previous UKI '$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi' without boot counting." >&2
rm -f "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi" "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+"*.efi
rm -f "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION.efi"
fi
for uki in "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+"*.efi; do
[ "$uki" = "$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+*.efi" ] && break
[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
echo "Removing previous UKI '$uki' that has not yet booted successfully." >&2
rm -f "$uki"
done
UKI_FILE="$UKI_DIR/$ENTRY_TOKEN-$KERNEL_VERSION+$TRIES.efi"
else

View File

@ -460,13 +460,15 @@ static int context_load_install_conf(Context *c) {
assert(c);
r = load_kernel_install_conf(arg_root,
c->conf_root,
&machine_id,
&boot_root,
&layout,
&initrd_generator,
&uki_generator);
r = load_kernel_install_conf_at(
c->conf_root ? NULL : arg_root,
c->conf_root ? XAT_FDROOT : c->rfd,
c->conf_root,
&machine_id,
&boot_root,
&layout,
&initrd_generator,
&uki_generator);
if (r <= 0)
return r;

View File

@ -255,8 +255,10 @@ typedef struct sd_bus {
uint64_t creds_mask;
/* Accumulated fds from multiple recvmsg() calls for a single D-Bus message */
int *fds;
size_t n_fds;
bool got_ctrunc; /* MSG_CTRUNC was seen during any recvmsg() */
char *exec_path;
char **exec_argv;

View File

@ -17,7 +17,7 @@
#include "utf8.h"
static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
static int message_parse_fields(sd_bus_message *m);
static int message_parse_fields(sd_bus_message *m, bool got_ctrunc);
static void* adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
@ -408,6 +408,7 @@ int bus_message_from_malloc(
size_t length,
int *fds,
size_t n_fds,
bool got_ctrunc,
const char *label,
sd_bus_message **ret) {
@ -437,7 +438,7 @@ int bus_message_from_malloc(
m->iovec = m->iovec_fixed;
m->iovec[0] = IOVEC_MAKE(buffer, length);
r = message_parse_fields(m);
r = message_parse_fields(m, got_ctrunc);
if (r < 0)
return r;
@ -4029,8 +4030,8 @@ static int message_skip_fields(
}
}
static int message_parse_fields(sd_bus_message *m) {
uint32_t unix_fds = 0;
static int message_parse_fields(sd_bus_message *m, bool got_ctrunc) {
uint32_t n_unix_fds_declared = 0;
bool unix_fds_set = false;
int r;
@ -4183,7 +4184,7 @@ static int message_parse_fields(sd_bus_message *m) {
if (!streq(signature, "u"))
return -EBADMSG;
r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
r = message_peek_field_uint32(m, &ri, item_size, &n_unix_fds_declared);
if (r < 0)
return -EBADMSG;
@ -4197,8 +4198,26 @@ static int message_parse_fields(sd_bus_message *m) {
return r;
}
if (m->n_fds != unix_fds)
return -EBADMSG;
/* Validate that the number of fds we actually received via SCM_RIGHTS matches (or is compatible
* with) the number declared in the message header.
*
* Normally these must match exactly. However, when MSG_CTRUNC was set during recvmsg(), the kernel
* might have truncated the fd array (e.g., due to LSM denials blocking fd passing). In that case,
* we also accept fewer fds than declared. Any attempt to actually use a truncated fd will fail later
* when sd_bus_message_read_basic() finds the fd index out of range. Too many fds is always wrong. */
if (m->n_fds > n_unix_fds_declared)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Received a bus message with too many fds: %" PRIu32 " received vs. %" PRIu32 " declared",
m->n_fds, n_unix_fds_declared);
if (m->n_fds < n_unix_fds_declared && !got_ctrunc)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Received a bus message with too few fds: %" PRIu32 " received vs. %" PRIu32 " declared",
m->n_fds, n_unix_fds_declared);
if (got_ctrunc)
log_error("Received a bus message with MSG_CTRUNC set with %" PRIu32 " fds received vs %" PRIu32 " declared",
m->n_fds, n_unix_fds_declared);
switch (m->header->type) {

View File

@ -177,6 +177,7 @@ int bus_message_from_malloc(
size_t length,
int *fds,
size_t n_fds,
bool got_ctrunc,
const char *label,
sd_bus_message **ret);

View File

@ -590,14 +590,25 @@ static int bus_process_cmsg(sd_bus *bus, struct msghdr *mh, bool allow_fds) {
return 0;
}
if (!GREEDY_REALLOC(bus->fds, bus->n_fds + n_fds))
return -ENOMEM;
/* Check if we previously received fds with MSG_CTRUNC set. When the kernel truncates the fd array,
* it drops all fds from the blocked one onwards - we have no way to know how many were lost or which
* indexes are affected. Any fds we receive now would be appended at the wrong indexes, corrupting
* the message's fd table. We must silently drop them to avoid a worse mess. Reading the message will
* still fail later when the user tries to access a truncated fd. */
if (!bus->got_ctrunc) {
if (!GREEDY_REALLOC(bus->fds, bus->n_fds + n_fds))
return -ENOMEM;
FOREACH_ARRAY(i, fds, n_fds)
bus->fds[bus->n_fds++] = fd_move_above_stdio(*i);
FOREACH_ARRAY(i, fds, n_fds)
bus->fds[bus->n_fds++] = fd_move_above_stdio(*i);
TAKE_PTR(fds);
n_fds = 0;
}
if (FLAGS_SET(mh->msg_flags, MSG_CTRUNC))
bus->got_ctrunc = true;
TAKE_PTR(fds);
n_fds = 0;
return 0;
}
@ -646,7 +657,7 @@ static int bus_socket_read_auth(sd_bus *b) {
.msg_controllen = sizeof(control),
};
k = recvmsg_safe(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
k = RET_NERRNO(recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC));
if (k == -ENOTSOCK) {
b->prefer_readv = true;
k = readv(b->input_fd, &iov, 1);
@ -1357,6 +1368,7 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
r = bus_message_from_malloc(bus,
bus->rbuffer, size,
bus->fds, bus->n_fds,
bus->got_ctrunc,
NULL,
&t);
if (r == -EBADMSG) {
@ -1373,6 +1385,7 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
bus->fds = NULL;
bus->n_fds = 0;
bus->got_ctrunc = false;
if (t) {
t->read_counter = ++bus->read_counter;
@ -1423,7 +1436,7 @@ int bus_socket_read_message(sd_bus *bus) {
.msg_controllen = sizeof(control),
};
k = recvmsg_safe(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
k = RET_NERRNO(recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC));
if (k == -ENOTSOCK) {
bus->prefer_readv = true;
k = readv(bus->input_fd, &iov, 1);

View File

@ -23,7 +23,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(buffer = memdup(data, size));
r = bus_message_from_malloc(bus, buffer, size, NULL, 0, NULL, &m);
r = bus_message_from_malloc(bus, buffer, size, NULL, 0, /* got_ctrunc= */ false, NULL, &m);
if (r == -EBADMSG)
return 0;
assert_se(r >= 0);

View File

@ -2,6 +2,7 @@
#include <fcntl.h>
#include <pthread.h>
#include <sys/resource.h>
#include <unistd.h>
#include "sd-bus.h"
@ -10,10 +11,13 @@
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-match.h"
#include "bus-message.h"
#include "errno-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
#include "memfd-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "tests.h"
#include "time-util.h"
@ -493,6 +497,128 @@ finish:
return INT_TO_PTR(r);
}
static ino_t get_inode(int fd) {
struct stat st;
assert_se(fstat(fd, &st) >= 0);
return st.st_ino;
}
static int get_one_message(sd_bus *bus, sd_bus_message **m) {
int r;
assert (m);
while (!*m) {
r = sd_bus_wait(bus, UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to wait: %m");
r = sd_bus_process(bus, m);
if (r < 0)
return log_error_errno(r, "Failed to process requests: %m");
}
return 0;
}
TEST(ctrunc) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *recvd = NULL, *sent = NULL;
struct rlimit orig_rl, new_rl;
const char *unique;
const int n_fds_to_send = 64;
ino_t memfd_st_ino[n_fds_to_send];
int r;
/* Connect to the session bus and eat the NamedAcquired message */
r = sd_bus_open_user(&bus);
if (r < 0)
return (void) log_error_errno(r, "Cannot connect to bus: %m");
ASSERT_OK(get_one_message(bus, &recvd));
recvd = sd_bus_message_unref(recvd);
if (!sd_bus_can_send(bus, 'h'))
return (void) log_error("Bus does not support fd passing: %m");
/* We will create a message with 64 fds in it and set a fd limit of 128 and try to receive it. We'll
* hold on to that message after we send it and then attempt to receive it back. Since various other
* fds will be open, with both copies of the message, we'll definitely hit the limit of 128.
*/
ASSERT_OK(sd_bus_get_unique_name(bus, &unique));
ASSERT_OK(sd_bus_message_new_method_call(bus, &sent, unique, "/", "org.freedesktop.systemd.test", "SendFds"));
ASSERT_OK(sd_bus_message_open_container(sent, SD_BUS_TYPE_ARRAY, "h"));
/* Create a series of memfds, appending each to the message */
for (int i = 0; i < n_fds_to_send; i++) {
_cleanup_close_ int memfd = memfd_create_wrapper("ctrunc-test", 0);
ASSERT_OK(memfd);
memfd_st_ino[i] = get_inode(memfd);
ASSERT_OK(sd_bus_message_append(sent, "h", memfd));
}
ASSERT_OK(sd_bus_message_close_container(sent));
/* Send the message - keep 'sent' alive to hold the duplicated fd references */
ASSERT_OK(sd_bus_send(bus, sent, NULL));
/* Now turn down the fd limit, receive the message, and turn it back up again */
ASSERT_OK_ERRNO(getrlimit(RLIMIT_NOFILE, &orig_rl));
new_rl.rlim_cur = n_fds_to_send * 2;
new_rl.rlim_max = orig_rl.rlim_max;
ASSERT_OK_ERRNO(setrlimit(RLIMIT_NOFILE, &new_rl));
/* The very first message should be the one we expect */
ASSERT_OK(get_one_message(bus, &recvd));
ASSERT_TRUE(sd_bus_message_is_method_call(recvd, "org.freedesktop.systemd.test", "SendFds"));
/* This needs to succeed or the following tests are going to be unhappy... */
ASSERT_EQ(setrlimit(RLIMIT_NOFILE, &orig_rl), 0);
/* Try to read all the fds. We expect at least one to fail with -EBADMSG due to
* truncation, and all subsequent reads must also fail with -EBADMSG. */
int i;
ASSERT_OK(sd_bus_message_enter_container(recvd, SD_BUS_TYPE_ARRAY, "h"));
for (i = 0; i < n_fds_to_send; i++) {
int fd; /* weakly owned: the fd belongs to the message */
r = sd_bus_message_read_basic(recvd, 'h', &fd);
if (r == -EBADMSG)
/* Good! We were expecting this! */
break;
ASSERT_OK(r);
ASSERT_EQ(get_inode(fd), memfd_st_ino[i]);
}
/* Make sure we successfully sent at least one fd but not all of them */
ASSERT_GT(i, 0);
ASSERT_LT(i, n_fds_to_send);
log_info("fds truncated at %i", i);
/* At this point we're stuck. We can call sd_bus_message_read_basic() as often as we want, but we
* won't be able to make progress and won't be able to close the array or read anything else in the
* message.
*/
for (i = 0; i < 2 * n_fds_to_send; i++) {
int fd; /* weakly owned: the fd belongs to the message */
ASSERT_ERROR(sd_bus_message_read_basic(recvd, 'h', &fd), EBADMSG);
}
ASSERT_ERROR(sd_bus_message_exit_container(recvd), EBUSY);
recvd = sd_bus_message_unref(recvd);
/* Send the message again without the fd limits to make sure the connection still works */
ASSERT_OK(sd_bus_send(bus, sent, NULL));
ASSERT_OK(get_one_message(bus, &recvd));
ASSERT_TRUE(sd_bus_message_is_method_call(recvd, "org.freedesktop.systemd.test", "SendFds"));
/* Read all the fds. */
ASSERT_EQ(sd_bus_message_enter_container(recvd, SD_BUS_TYPE_ARRAY, "h"), 1);
for (i = 0; i < n_fds_to_send; i++) {
int fd; /* weakly owned: the fd belongs to the message */
ASSERT_OK(sd_bus_message_read_basic(recvd, 'h', &fd));
ASSERT_EQ(get_inode(fd), memfd_st_ino[i]);
}
ASSERT_OK(sd_bus_message_exit_container(recvd));
log_info("MSG_CTRUNC test passed");
}
TEST(chat) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
pthread_t c1, c2;

View File

@ -19,12 +19,16 @@ REENABLE_WARNING
#include "sd-bus.h"
#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
#include "escape.h"
#include "fd-util.h"
#include "log.h"
#include "memfd-util.h"
#include "memstream-util.h"
#include "stat-util.h"
#include "tests.h"
static void test_bus_path_encode_unique(void) {
@ -99,6 +103,119 @@ static void test_bus_label_escape_one(const char *a, const char *b) {
assert_se(streq(a, y));
}
static ino_t get_inode(int fd) {
struct stat st;
assert_se(fstat(fd, &st) >= 0);
return st.st_ino;
}
static void test_bus_fds_truncated(void) {
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_close_ int memfd0 = -EBADF, memfd1 = -EBADF;
_cleanup_free_ void *blob = NULL;
_cleanup_free_ int *fds = NULL;
ino_t ino0, ino1;
size_t blob_size;
int fd;
/* Create two memfds and record their inodes for later verification */
memfd0 = ASSERT_OK(memfd_create_wrapper("test-fd-0", 0));
ino0 = get_inode(memfd0);
memfd1 = ASSERT_OK(memfd_create_wrapper("test-fd-1", 0));
ino1 = get_inode(memfd1);
/* Create a bus for message operations (no actual connection needed) */
ASSERT_OK(sd_bus_new(&bus));
bus->state = BUS_RUNNING; /* Fake state to allow message creation */
bus->can_fds = true; /* Allow fd passing */
/* Build a message containing two fds */
ASSERT_OK(sd_bus_message_new_method_call(bus, &m, "foo.bar", "/", "foo.bar", "Ping"));
ASSERT_OK(sd_bus_message_append(m, "hh", memfd0, memfd1));
ASSERT_OK(sd_bus_message_seal(m, 1, 0));
/* Serialize the message to a blob */
ASSERT_OK(bus_message_get_blob(m, &blob, &blob_size));
m = sd_bus_message_unref(m);
/* Duplicate the fds since bus_message_from_malloc() takes ownership */
fds = ASSERT_NOT_NULL(new(int, 2));
fds[0] = ASSERT_OK_ERRNO(fcntl(memfd0, F_DUPFD_CLOEXEC, 3));
fds[1] = ASSERT_OK_ERRNO(fcntl(memfd1, F_DUPFD_CLOEXEC, 3));
/* Test 1: Parse with correct fd count, no truncation - should succeed */
log_info("Test 1: Exact fd count match, got_ctrunc=false");
void *blob_copy = ASSERT_NOT_NULL(memdup(blob, blob_size));
ASSERT_OK(bus_message_from_malloc(bus, blob_copy, blob_size, fds, 2, /* got_ctrunc= */ false, NULL, &m));
/* Verify we can read both fds and they have the expected inodes */
ASSERT_OK(sd_bus_message_read_basic(m, 'h', &fd));
ASSERT_EQ(get_inode(fd), ino0);
ASSERT_OK(sd_bus_message_read_basic(m, 'h', &fd));
ASSERT_EQ(get_inode(fd), ino1);
m = sd_bus_message_unref(m);
fds = NULL; /* ownership transferred */
/* Test 2: Parse with fewer fds than declared, no truncation flag - should fail */
log_info("Test 2: Fewer fds than declared, got_ctrunc=false");
fds = ASSERT_NOT_NULL(new(int, 1));
fds[0] = ASSERT_OK_ERRNO(fcntl(memfd0, F_DUPFD_CLOEXEC, 3));
blob_copy = ASSERT_NOT_NULL(memdup(blob, blob_size));
ASSERT_ERROR(bus_message_from_malloc(bus, blob_copy, blob_size, fds, 1, /* got_ctrunc= */ false, NULL, &m), EBADMSG);
free(blob_copy);
close(fds[0]);
fds = mfree(fds);
/* Test 3: Parse with fewer fds than declared, with truncation flag - parsing should succeed */
log_info("Test 3: Fewer fds than declared, got_ctrunc=true");
fds = ASSERT_NOT_NULL(new(int, 1));
fds[0] = ASSERT_OK_ERRNO(fcntl(memfd0, F_DUPFD_CLOEXEC, 3));
blob_copy = ASSERT_NOT_NULL(memdup(blob, blob_size));
ASSERT_OK(bus_message_from_malloc(bus, blob_copy, blob_size, fds, 1, /* got_ctrunc= */ true, NULL, &m));
/* First fd should be readable and have correct inode */
ASSERT_OK(sd_bus_message_read_basic(m, 'h', &fd));
ASSERT_EQ(get_inode(fd), ino0);
/* Second fd was truncated - reading it should fail */
ASSERT_ERROR(sd_bus_message_read_basic(m, 'h', &fd), EBADMSG);
m = sd_bus_message_unref(m);
fds = NULL; /* ownership transferred */
/* Test 4: Parse with more fds than declared, with truncation flag - should fail */
log_info("Test 4: More fds than declared, got_ctrunc=true");
fds = ASSERT_NOT_NULL(new(int, 3));
fds[0] = ASSERT_OK_ERRNO(fcntl(memfd0, F_DUPFD_CLOEXEC, 3));
fds[1] = ASSERT_OK_ERRNO(fcntl(memfd1, F_DUPFD_CLOEXEC, 3));
fds[2] = ASSERT_OK_ERRNO(fcntl(memfd0, F_DUPFD_CLOEXEC, 3));
blob_copy = ASSERT_NOT_NULL(memdup(blob, blob_size));
ASSERT_ERROR(bus_message_from_malloc(bus, blob_copy, blob_size, fds, 3, /* got_ctrunc= */ true, NULL, &m), EBADMSG);
free(blob_copy);
close(fds[0]);
close(fds[1]);
close(fds[2]);
fds = mfree(fds);
/* Test 5: Parse with zero fds when two were declared, with truncation flag - should succeed */
log_info("Test 5: Zero fds when some declared, got_ctrunc=true");
blob_copy = ASSERT_NOT_NULL(memdup(blob, blob_size));
ASSERT_OK(bus_message_from_malloc(bus, blob_copy, blob_size, NULL, 0, /* got_ctrunc= */ true, NULL, &m));
/* Both fd reads should fail since all were truncated */
ASSERT_ERROR(sd_bus_message_read_basic(m, 'h', &fd), EBADMSG);
m = sd_bus_message_unref(m);
log_info("All fd truncation tests passed");
}
static void test_bus_label_escape(void) {
test_bus_label_escape_one("foo123bar", "foo123bar");
test_bus_label_escape_one("foo.bar", "foo_2ebar");
@ -243,7 +360,7 @@ int main(int argc, char *argv[]) {
m = sd_bus_message_unref(m);
r = bus_message_from_malloc(bus, buffer, sz, NULL, 0, NULL, &m);
r = bus_message_from_malloc(bus, buffer, sz, NULL, 0, /* got_ctrunc= */ false, NULL, &m);
assert_se(r >= 0);
sd_bus_message_dump(m, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER);
@ -415,6 +532,7 @@ int main(int argc, char *argv[]) {
test_bus_path_encode();
test_bus_path_encode_unique();
test_bus_path_encode_many();
test_bus_fds_truncated();
return 0;
}

View File

@ -138,7 +138,7 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
int id128_get_machine_at(int rfd, sd_id128_t *ret) {
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
r = dir_fd_is_root_or_cwd(rfd);
if (r < 0)

View File

@ -1031,13 +1031,14 @@ int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) {
dropin_dirname = strjoina(file_basename, ".d");
r = config_parse_many(
STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL,
STRV_MAKE_CONST(filename),
NETWORK_DIRS,
dropin_dirname,
NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
config_item_perf_lookup, network_netdev_gperf_lookup,
config_item_perf_lookup,
network_netdev_gperf_lookup,
CONFIG_PARSE_WARN,
netdev_raw,
NULL,
NULL);
netdev_raw);
if (r < 0)
return r; /* config_parse_many() logs internally. */
@ -1064,10 +1065,15 @@ int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) {
if (NETDEV_VTABLE(netdev)->init)
NETDEV_VTABLE(netdev)->init(netdev);
r = config_parse_many(
STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL,
r = config_parse_many_full(
STRV_MAKE_CONST(filename),
NETWORK_DIRS,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ -EBADF,
NETDEV_VTABLE(netdev)->sections,
config_item_perf_lookup, network_netdev_gperf_lookup,
config_item_perf_lookup,
network_netdev_gperf_lookup,
CONFIG_PARSE_WARN,
netdev,
&netdev->stats_by_path,

View File

@ -17,6 +17,7 @@
#include "edit-util.h"
#include "errno-util.h"
#include "extract-word.h"
#include "fd-util.h"
#include "log.h"
#include "mkdir-label.h"
#include "netlink-util.h"
@ -106,7 +107,13 @@ static int get_config_files_by_name(
if (!dropin_dirname)
return -ENOMEM;
r = conf_files_list_dropins(ret_dropins, dropin_dirname, /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS);
r = conf_files_list_dropins(
ret_dropins,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
CONF_FILES_WARN,
NETWORK_DIRS);
if (r < 0)
return r;
}

View File

@ -514,8 +514,12 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.ipoib_umcast = -1,
};
r = config_parse_many(
STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root= */ NULL,
r = config_parse_many_full(
STRV_MAKE_CONST(filename),
NETWORK_DIRS,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ -EBADF,
"Match\0"
"Link\0"
"SR-IOV\0"
@ -574,7 +578,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"StochasticFairnessQueueing\0"
"TokenBucketFilter\0"
"TrivialLinkEqualizer\0",
config_item_perf_lookup, network_network_gperf_lookup,
config_item_perf_lookup,
network_network_gperf_lookup,
CONFIG_PARSE_WARN,
network,
&network->stats_by_path,

View File

@ -2871,16 +2871,17 @@ static int partition_read_definition(
dropin_dirname = strjoina(filename, ".d");
r = config_parse_many(
r = config_parse_many_full(
STRV_MAKE_CONST(path),
conf_file_dirs,
dropin_dirname,
c->definitions ? NULL : arg_root,
/* root_fd= */ -EBADF,
"Partition\0",
config_item_table_lookup, table,
CONFIG_PARSE_WARN,
p,
NULL,
/* ret_stats_by_path= */ NULL,
&p->drop_in_files);
if (r < 0)
return r;
@ -3396,7 +3397,7 @@ static int context_read_definitions(Context *context) {
&files,
".conf",
context->definitions ? NULL : arg_root,
CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN,
CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED|CONF_FILES_WARN|CONF_FILES_DONT_PREFIX_ROOT,
dirs);
if (r < 0)
return log_error_errno(r, "Failed to enumerate *.conf files: %m");

View File

@ -188,14 +188,11 @@ static int dns_delegate_load(Manager *m, const char *path) {
STRV_MAKE_CONST(path),
DNS_DELEGATE_SEARCH_DIRS,
dropin_dirname,
/* root= */ NULL,
"Delegate\0",
config_item_perf_lookup,
resolved_dns_delegate_gperf_lookup,
/* flags= */ 0,
d,
/* ret_stats_by_path= */ NULL,
/* ret_drop_in_files= */ NULL);
d);
if (r < 0)
return r;

View File

@ -125,13 +125,13 @@ static int dnssd_registered_service_load(Manager *manager, const char *path) {
return log_oom();
r = config_parse_many(
STRV_MAKE_CONST(path), DNSSD_SERVICE_DIRS, dropin_dirname, /* root= */ NULL,
STRV_MAKE_CONST(path),
DNSSD_SERVICE_DIRS,
dropin_dirname,
"Service\0",
config_item_perf_lookup, resolved_dnssd_gperf_lookup,
CONFIG_PARSE_WARN,
service,
NULL,
NULL);
service);
if (r < 0)
return r;

View File

@ -22,7 +22,7 @@ static int entry_token_load_one(int rfd, const char *dir, BootEntryTokenType *ty
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(dir);
assert(type);
assert(*type == BOOT_ENTRY_TOKEN_AUTO);
@ -58,7 +58,7 @@ static int entry_token_load_one(int rfd, const char *dir, BootEntryTokenType *ty
static int entry_token_load(int rfd, const char *conf_root, BootEntryTokenType *type, char **token) {
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(type);
assert(*type == BOOT_ENTRY_TOKEN_AUTO);
assert(token);
@ -98,7 +98,7 @@ static int entry_token_from_os_release(int rfd, BootEntryTokenType *type, char *
_cleanup_free_ char *id = NULL, *image_id = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(type);
assert(IN_SET(*type, BOOT_ENTRY_TOKEN_AUTO, BOOT_ENTRY_TOKEN_OS_IMAGE_ID, BOOT_ENTRY_TOKEN_OS_ID));
assert(token);
@ -151,7 +151,7 @@ int boot_entry_token_ensure_at(
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(rfd >= 0 || IN_SET(rfd, AT_FDCWD, XAT_FDROOT));
assert(type);
assert(token);
@ -229,11 +229,12 @@ int boot_entry_token_ensure(
if (*token)
return 0; /* Already set. */
_cleanup_close_ int rfd = -EBADF;
rfd = open(empty_to_root(root), O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
_cleanup_close_ int rfd = XAT_FDROOT;
if (!empty_or_root(root)) {
rfd = open(root, O_CLOEXEC | O_DIRECTORY | O_PATH);
if (rfd < 0)
return -errno;
}
return boot_entry_token_ensure_at(rfd, conf_root, machine_id, machine_id_is_random, type, token);
}

View File

@ -481,6 +481,7 @@ int hashmap_put_stats_by_path(Hashmap **stats_by_path, const char *path, const s
static int config_parse_many_files(
const char *root,
int root_fd,
const char* const* conf_files,
char **files,
const char *sections,
@ -502,17 +503,17 @@ static int config_parse_many_files(
return log_oom_full(level);
}
/* Pin and stat() all dropins */
STRV_FOREACH(fn, files) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *fname = NULL;
r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", &fname, &f);
r = chase_and_fopenat_unlocked(root_fd, *fn, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
if (r == -ENOENT)
continue;
if (r < 0)
return log_full_errno(level, r, "Failed to open %s: %m", *fn);
int fd = fileno(f);
assert(fd >= 0);
r = ordered_hashmap_ensure_put(&dropins, &config_file_hash_ops_fclose, *fn, f);
if (r < 0) {
@ -537,11 +538,10 @@ static int config_parse_many_files(
return log_oom_full(level);
}
/* First read the first found main config file. */
/* First process the first found main config file. */
STRV_FOREACH(fn, conf_files) {
_cleanup_fclose_ FILE *f = NULL;
r = chase_and_fopen_unlocked(*fn, root, CHASE_AT_RESOLVE_IN_ROOT, "re", NULL, &f);
r = chase_and_fopenat_unlocked(root_fd, *fn, CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, "re", /* ret_path= */ NULL, &f);
if (r == -ENOENT)
continue;
if (r < 0)
@ -572,7 +572,6 @@ static int config_parse_many_files(
}
/* Then read all the drop-ins. */
const char *path_dropin;
FILE *f_dropin;
ORDERED_HASHMAP_FOREACH_KEY(f_dropin, path_dropin, dropins) {
@ -594,12 +593,39 @@ static int config_parse_many_files(
return 0;
}
static int normalize_root_fd(const char *root, int *root_fd, int *ret_opened_fd) {
assert(root_fd);
assert(ret_opened_fd);
/* Normalizes a root dir specification: if root_fd is already valid, keep it. Otherwise, we open the
* specified dir */
if (*root_fd >= 0 || IN_SET(*root_fd, AT_FDCWD, XAT_FDROOT)) {
*ret_opened_fd = -EBADF;
return 0;
}
if (empty_or_root(root)) {
*root_fd = XAT_FDROOT;
*ret_opened_fd = -EBADF;
return 0;
}
int fd = open(root, O_CLOEXEC|O_PATH|O_DIRECTORY);
if (fd < 0)
return log_error_errno(errno, "Failed to open root directory '%s': %m", root);
*ret_opened_fd = *root_fd = fd;
return 0;
}
/* Parse each config file in the directories specified as strv. */
int config_parse_many(
int config_parse_many_full(
const char* const* conf_files,
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *root,
int root_fd,
const char *sections,
ConfigItemLookup lookup,
const void *table,
@ -615,14 +641,33 @@ int config_parse_many(
assert(dropin_dirname);
assert(table);
r = conf_files_list_dropins(&files, dropin_dirname, root,
FLAGS_SET(flags, CONFIG_PARSE_WARN) ? CONF_FILES_WARN : 0,
conf_file_dirs);
_cleanup_close_ int opened_root_fd = -EBADF;
r = normalize_root_fd(root, &root_fd, &opened_root_fd);
if (r < 0)
return r;
r = conf_files_list_dropins(
&files,
dropin_dirname,
root,
root_fd,
FLAGS_SET(flags, CONFIG_PARSE_WARN) ? CONF_FILES_WARN : 0,
conf_file_dirs);
if (r < 0)
return log_full_errno(FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG, r,
"Failed to list drop-ins in %s: %m", dropin_dirname);
r = config_parse_many_files(root, conf_files, files, sections, lookup, table, flags, userdata, ret_stats_by_path);
r = config_parse_many_files(
root,
root_fd,
conf_files,
files,
sections,
lookup,
table,
flags,
userdata,
ret_stats_by_path);
if (r < 0)
return r; /* config_parse_many_files() logs internally. */
@ -634,6 +679,7 @@ int config_parse_many(
int config_parse_standard_file_with_dropins_full(
const char *root,
int root_fd,
const char *main_file, /* A path like "systemd/frobnicator.conf" */
const char *sections,
ConfigItemLookup lookup,
@ -643,12 +689,15 @@ int config_parse_standard_file_with_dropins_full(
Hashmap **ret_stats_by_path,
char ***ret_dropin_files) {
const char* const *conf_paths = (const char* const*) CONF_PATHS_STRV("");
_cleanup_strv_free_ char **configs = NULL;
const char* const *conf_file_dirs = (const char* const*) CONF_PATHS_STRV("");
_cleanup_strv_free_ char **conf_files = NULL;
int r, level = FLAGS_SET(flags, CONFIG_PARSE_WARN) ? LOG_WARNING : LOG_DEBUG;
/* Build the list of main config files */
r = strv_extend_strv_biconcat(&configs, root, conf_paths, main_file);
r = strv_extend_strv_concat(
&conf_files,
conf_file_dirs,
main_file);
if (r < 0)
return log_oom_full(level);
@ -656,11 +705,12 @@ int config_parse_standard_file_with_dropins_full(
if (!dropin_dirname)
return log_oom_full(level);
return config_parse_many(
(const char* const*) configs,
conf_paths,
return config_parse_many_full(
(const char* const*) conf_files,
conf_file_dirs,
dropin_dirname,
root,
root_fd,
sections,
lookup,
table,
@ -692,7 +742,13 @@ static int dropins_get_stats_by_path(
if (!strextend(&dropin_dirname, ".d"))
return -ENOMEM;
r = conf_files_list_dropins(&files, dropin_dirname, /* root= */ NULL, /* flags= */ 0, conf_file_dirs);
r = conf_files_list_dropins(
&files,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
/* flags= */ 0,
conf_file_dirs);
if (r < 0)
return r;

View File

@ -5,7 +5,7 @@
#include "alloc-util.h"
#include "conf-parser-forward.h"
#include "shared-forward.h"
#include "fd-util.h"
#include "log.h"
/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
@ -66,11 +66,12 @@ int config_parse(
void *userdata,
struct stat *ret_stat); /* possibly NULL */
int config_parse_many(
int config_parse_many_full(
const char* const* conf_files, /* possibly empty */
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *root,
int root_fd,
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
@ -79,8 +80,34 @@ int config_parse_many(
Hashmap **ret_stats_by_path, /* possibly NULL */
char ***ret_dropin_files); /* possibly NULL */
static inline int config_parse_many(
const char* const* conf_files, /* possibly empty */
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
ConfigParseFlags flags,
void *userdata) {
return config_parse_many_full(
conf_files,
conf_file_dirs,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
sections,
lookup,
table,
flags,
userdata,
/* ret_stats_by_path= */ NULL,
/* ret_drop_in_files= */ NULL);
}
int config_parse_standard_file_with_dropins_full(
const char *root,
int root_fd,
const char *main_file, /* A path like "systemd/frobnicator.conf" */
const char *sections,
ConfigItemLookup lookup,
@ -99,6 +126,7 @@ static inline int config_parse_standard_file_with_dropins(
void *userdata) {
return config_parse_standard_file_with_dropins_full(
/* root= */ NULL,
/* root_fd= */ XAT_FDROOT,
main_file,
sections,
lookup,

View File

@ -2,11 +2,13 @@
#include "alloc-util.h"
#include "conf-parser.h"
#include "fd-util.h"
#include "kernel-config.h"
#include "path-util.h"
int load_kernel_install_conf(
int load_kernel_install_conf_at(
const char *root,
int root_fd,
const char *conf_root,
char **ret_machine_id,
char **ret_boot_root,
@ -26,16 +28,19 @@ int load_kernel_install_conf(
};
int r;
assert(root_fd >= 0 || IN_SET(root_fd, AT_FDCWD, XAT_FDROOT));
if (conf_root) {
_cleanup_free_ char *conf = path_join(conf_root, "install.conf");
if (!conf)
return log_oom();
r = config_parse_many(
r = config_parse_many_full(
STRV_MAKE_CONST(conf),
STRV_MAKE_CONST(conf_root),
"install.conf.d",
/* root= */ NULL, /* $KERNEL_INSTALL_CONF_ROOT and --root are independent */
root,
root_fd,
/* sections= */ NULL,
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
@ -45,6 +50,7 @@ int load_kernel_install_conf(
} else
r = config_parse_standard_file_with_dropins_full(
root,
root_fd,
"kernel/install.conf",
/* sections= */ NULL,
config_item_table_lookup, items,

View File

@ -1,13 +1,27 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "fd-util.h"
#include "shared-forward.h"
int load_kernel_install_conf(
int load_kernel_install_conf_at(
const char *root,
int root_fd,
const char *conf_root,
char **ret_machine_id,
char **ret_boot_root,
char **ret_layout,
char **ret_initrd_generator,
char **ret_uki_generator);
static inline int load_kernel_install_conf(
const char *root,
const char *conf_root,
char **ret_machine_id,
char **ret_boot_root,
char **ret_layout,
char **ret_initrd_generator,
char **ret_uki_generator) {
return load_kernel_install_conf_at(root, XAT_FDROOT, conf_root, ret_machine_id, ret_boot_root, ret_layout, ret_initrd_generator, ret_uki_generator);
}

View File

@ -191,6 +191,7 @@ static int parse_config_file(ImageClass image_class) {
r = config_parse_standard_file_with_dropins_full(
arg_root,
/* root_fd= */ -EBADF,
config_file,
sections,
config_item_table_lookup, items,

View File

@ -101,11 +101,12 @@ int feature_read_definition(Feature *f, const char *path, const char *const *dir
if (r < 0)
return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
r = config_parse_many(
r = config_parse_many_full(
STRV_MAKE_CONST(path),
dirs,
strjoina(filename, ".d"),
arg_root,
/* root_fd= */ -EBADF,
"Feature\0",
config_item_table_lookup, table,
CONFIG_PARSE_WARN,

View File

@ -543,11 +543,12 @@ int transfer_read_definition(Transfer *t, const char *path, const char **dirs, H
if (r < 0)
return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
r = config_parse_many(
r = config_parse_many_full(
STRV_MAKE_CONST(path),
dirs,
strjoina(filename, ".d"),
arg_root,
/* root_fd= */ -EBADF,
"Transfer\0"
"Source\0"
"Target\0",

View File

@ -1568,12 +1568,12 @@ static int verb_components(int argc, char **argv, void *userdata) {
FOREACH_ARRAY(i, directories, n_directories) {
ConfFile *e = *i;
if (streq(e->name, "sysupdate.d")) {
if (streq(e->filename, "sysupdate.d")) {
has_default_component = true;
continue;
}
const char *s = startswith(e->name, "sysupdate.");
const char *s = startswith(e->filename, "sysupdate.");
if (!s)
continue;

View File

@ -444,7 +444,9 @@ TEST(config_parse_standard_file_with_dropins_full) {
};
r = config_parse_standard_file_with_dropins_full(
root, "kernel/install.conf",
root,
/* root_fd= */ -EBADF,
"kernel/install.conf",
/* sections= */ NULL,
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
@ -483,7 +485,9 @@ TEST(config_parse_standard_file_with_dropins_full) {
assert_se(symlinkat("/etc/kernel/install.conf.d/drop4.conf", rfd, "etc/kernel/install2.conf.d/drop4.conf") == 0);
r = config_parse_standard_file_with_dropins_full(
root, "kernel/install2.conf",
root,
/* root_fd= */ -EBADF,
"kernel/install2.conf",
/* sections= */ NULL,
config_item_table_lookup, items,
CONFIG_PARSE_WARN,

View File

@ -280,17 +280,20 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
return log_error_errno(r, "Failed to extract file name of '%s': %m", filename);
dropin_dirname = strjoina(file_basename, ".d");
r = config_parse_many(
r = config_parse_many_full(
STRV_MAKE_CONST(filename),
NETWORK_DIRS,
dropin_dirname,
/* root= */ NULL,
/* root_fd= */ -EBADF,
"Match\0"
"Link\0"
"SR-IOV\0"
"EnergyEfficientEthernet\0",
config_item_perf_lookup, link_config_gperf_lookup,
CONFIG_PARSE_WARN, config, &stats_by_path,
CONFIG_PARSE_WARN,
config,
&stats_by_path,
&config->dropins);
if (r < 0)
return r; /* config_parse_many() logs internally. */

View File

@ -1739,9 +1739,11 @@ static int generate_ssh_keypair(const char *key_path, const char *key_type) {
log_debug("Executing: %s", joined);
}
r = pidref_safe_fork(
r = pidref_safe_fork_full(
ssh_keygen,
FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO,
(int[]) { -EBADF, -EBADF, STDERR_FILENO },
/* except_fds= */ NULL, /* n_except_fds= */ 0,
FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG,
/* ret= */ NULL);
if (r < 0)
return r;