1
0
mirror of https://github.com/systemd/systemd synced 2025-09-19 20:04:46 +02:00

Compare commits

...

28 Commits

Author SHA1 Message Date
Lennart Poettering
bdd8728c91
various: port remaining users of setmntent() to libmount (#38929) 2025-09-19 09:26:06 +02:00
Yu Watanabe
fbbbff01fb
various tweaks for systemd-creds & related (#38979) 2025-09-19 16:21:12 +09:00
Yu Watanabe
542552612b
chase: tweaks to chase_open()/chase_openat() (#38984) 2025-09-19 16:11:24 +09:00
Yu Watanabe
9a8f2b628d
chattr-util/acl-util: add helpers that tells us if an inode type can do chattr/acl (#39003)
Split out of #38728 but I think this makes things more readable in
general and makes sense on its own.
2025-09-19 15:50:18 +09:00
Yu Watanabe
8835034df8
importd: some minor tweaks (#39008) 2025-09-19 15:48:14 +09:00
Lennart Poettering
625c2e10c6 importd: port to PidRef 2025-09-19 15:45:46 +09:00
Lennart Poettering
93dea63fab fileio: modernize xopendirat() a bit 2025-09-19 08:39:32 +02:00
ners
7b7f0983e0 localectl: use XKB path specified from environment variable 2025-09-19 15:37:52 +09:00
Lennart Poettering
7d4b0df9f8 creds-util: don't reference superblocks when decrypting creds 2025-09-18 22:11:57 +02:00
Lennart Poettering
4be269563d core: if we cannot decode a TPM credential skip over it for ImportCredential=
let's skip over credentials we cannot decode when they are found with
ImportCredential=. When installing an OS on some disk and using that
disk on a different machine than assumed we'll otherwise end up with a
broken boot, because the credentials cannot be decoded when starting
systemd-firstboot. Let's handle this somewhat gracefully.

This leaves handling for LoadCredential=/SetCredential= as it is (i.e.
failure to decrypt results in service failure), because it is a lot more
explicit and focussed as opposed to ImportCredentials= which looks
everywhere, uses globs and so on and is hence very vague and unfocussed.

Fixes: #34740
2025-09-18 22:11:57 +02:00
Lennart Poettering
ffd4b38096 creds: expose more errors as explicit varlink errors 2025-09-18 22:11:57 +02:00
Lennart Poettering
9be0a94b98 creds-util: tweak error code generation in decrypt_credential_and_warn() a bit, and add a comment listing it
Let's make some specific condition more recognizable via error codes of
their own, and in particular remove confusion between EREMOTE as
returned by tpm2_unseal() and by us.
2025-09-18 22:11:57 +02:00
Lennart Poettering
bd610b2253 creds: modernize varlink server setup a bit
Let's make use of the userdata parameter of varlink_server_new(), and
split out the code into its own helper function.
2025-09-18 22:01:25 +02:00
Lennart Poettering
c3b1aa6d73 acl-util: add new inode_type_can_acl() helper 2025-09-18 21:58:44 +02:00
Lennart Poettering
134749c1d0 chattr-util: add inode_type_can_chattr() helper 2025-09-18 21:58:00 +02:00
Mike Yuan
3b911434d6
TODO: drop completed entry 2025-09-18 20:25:15 +02:00
Mike Yuan
6b8dcb9853
codeql: taint setmntent() and getmntent() 2025-09-18 20:25:15 +02:00
Mike Yuan
873a70d28a
mount-util: drop now unused _cleanup_endmntent_ 2025-09-18 20:25:15 +02:00
Mike Yuan
9d05015bb9
remount-fs: port to libmount parser 2025-09-18 20:25:15 +02:00
Mike Yuan
7ebb2b3349
remount-fs: minor coding style cleanups 2025-09-18 20:25:15 +02:00
Mike Yuan
69fa2b6303
cryptsetup: port from setmntent() to libmount parser 2025-09-18 20:25:14 +02:00
Mike Yuan
00074c31b6
fstab-generator: port to libmount parser 2025-09-18 20:25:14 +02:00
Mike Yuan
afba4d4387
TEST-81-GENERATORS: libmount disallows omitting fstype
It's not well-formed to begin with. And util-linux's mount(8)
is pretty much ubiquitously employed, hence it will be rejected
elsewhere too. Just stop pretending it is valid just because
glibc parser is sloppy.
2025-09-18 20:22:42 +02:00
Lennart Poettering
f26a805a9f import: always use the same buffer size
Let's synchronize the buffer sizes used when passing around the disk
images, i.e. size both our internal buffers and the pipe buffers the
same (so that we can always write()/read() everything in one gone -
except for the noise compression inserts).

Let's also increase the buffer sizes from 16K to 128K, which made a
difference for me, because it reduces the number of syscalls quite a
bit.
2025-09-18 15:43:13 +02:00
Lennart Poettering
0ba1d9f6db export-tar: refuse to write tar to a TTY 2025-09-18 15:40:41 +02:00
Lennart Poettering
96deac2bf1 sd-id128: tighten rules on chasing machine-id files 2025-09-18 09:44:30 +02:00
Lennart Poettering
fb7151a350 chase: honour CHASE_MUST_BE_DIRECTORY/CHASE_MUST_BE_REGULAR properly in chase_and_openat() and related calls 2025-09-18 09:36:44 +02:00
Lennart Poettering
be1117f712 chase: mask away CHASE_MUST_BE_REGULAR in chase_openat()
We pin the parent directory of the specified directory via CHASE_PARENT,
but if we do that we really should mask off CHASE_MUST_BE_REGULAR,
because a parent dir of course is a dir, nothing else. The
CHASE_MUST_BE_REGULAR after all should apply to the file created in that
dir, not to the parent.
2025-09-18 09:36:44 +02:00
38 changed files with 394 additions and 218 deletions

View File

@ -52,6 +52,12 @@ predicate potentiallyDangerousFunction(Function f, string message) {
) or (
f.getQualifiedName() = "basename" and
message = "Call basename() is icky. Use path_extract_filename() instead."
) or (
f.getQualifiedName() = "setmntent" and
message = "Libmount parser is used instead, specifically libmount_parse_fstab()."
) or (
f.getQualifiedName() = "getmntent" and
message = "Libmount parser is used instead, specifically mnt_table_next_fs()."
)
}

5
TODO
View File

@ -522,11 +522,6 @@ Features:
* port copy.c over to use LabelOps for all labelling.
* port remaining getmntent() users over to libmount. There are subtle
differences in the parsers (see #25371 for example), and it hence makes sense
if we stick to one set of parsers on this, not mix both. Specifically:
systemd-fstab-generator, cryptsetup, remount-fs.
* get rid of compat with libidn.so.11 (retain only for libidn.so.12)
* get rid of compat with libbpf.so.0 (retainly only for libbpf.so.1)

View File

@ -380,6 +380,9 @@ All tools:
default keymap directories (/usr/share/keymaps/, /usr/share/kbd/keymaps/, and
/usr/lib/kbd/keymaps/) will be used.
* `$SYSTEMD_XKB_DIRECTORY=` — The directory must be absolute and normalized.
If unset, the default XKB directory (/usr/share/X11/xkb) will be used.
`systemd-resolved`:
* `$SYSTEMD_RESOLVED_SYNTHESIZE_HOSTNAME` — if set to "0", `systemd-resolved`

View File

@ -3915,6 +3915,13 @@ StandardInputData=V2XigLJyZSBubyBzdHJhbmdlcnMgdG8gbG92ZQpZb3Uga25vdyB0aGUgcnVsZX
<varname>LoadCredential=</varname> and <varname>LoadCredentialEncrypted=</varname> take priority over
credentials found by <varname>ImportCredential=</varname>.</para>
<para>Note that if decryption or authentication of a credential picked up as result of
<varname>ImportCredential=</varname> fails it will be skipped gracefully (a warning is generated, but
the credential will not be made available to the invoked service). This is different for those
configured via
<varname>SetCredentialEncrypted=</varname>/<varname>LoadCredentialEncrypted=</varname>, where failed
decryption/authentication will result in service failure.</para>
<xi:include href="version-info.xml" xpointer="v254"/></listitem>
</varlistentry>

View File

@ -789,14 +789,20 @@ int chase_and_open(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
XOpenFlags xopen_flags = 0;
if (FLAGS_SET(chase_flags, CHASE_MUST_BE_DIRECTORY))
open_flags |= O_DIRECTORY;
if (FLAGS_SET(chase_flags, CHASE_MUST_BE_REGULAR))
xopen_flags |= XO_REGULAR;
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(AT_FDCWD, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
/* xopen_flags = */ 0,
xopen_flags,
MODE_INVALID);
r = chase(path, root, CHASE_PARENT|chase_flags, &p, &path_fd);
r = chase(path, root, (CHASE_PARENT|chase_flags)&~CHASE_MUST_BE_REGULAR, &p, &path_fd);
if (r < 0)
return r;
assert(path_fd >= 0);
@ -808,7 +814,7 @@ int chase_and_open(
return r;
}
r = xopenat_full(path_fd, strempty(fname), open_flags|O_NOFOLLOW, /* xopen_flags = */ 0, MODE_INVALID);
r = xopenat_full(path_fd, strempty(fname), open_flags|O_NOFOLLOW, xopen_flags, MODE_INVALID);
if (r < 0)
return r;
@ -824,7 +830,7 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
DIR *d;
int r;
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR)));
assert(ret_dir);
if (empty_or_root(root) && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
@ -837,12 +843,12 @@ int chase_and_opendir(const char *path, const char *root, ChaseFlags chase_flags
return 0;
}
r = chase(path, root, chase_flags, ret_path ? &p : NULL, &path_fd);
r = chase(path, root, chase_flags|CHASE_MUST_BE_DIRECTORY, ret_path ? &p : NULL, &path_fd);
if (r < 0)
return r;
assert(path_fd >= 0);
d = xopendirat(path_fd, ".", O_NOFOLLOW);
d = xopendirat(path_fd, /* path= */ NULL, /* flags= */ 0);
if (!d)
return -errno;
@ -922,7 +928,7 @@ int chase_and_fopen_unlocked(
int mode_flags, r;
assert(path);
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT)));
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_PARENT|CHASE_MUST_BE_DIRECTORY)));
assert(open_flags);
assert(ret_file);
@ -994,14 +1000,20 @@ int chase_and_openat(
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
XOpenFlags xopen_flags = 0;
if (FLAGS_SET(chase_flags, CHASE_MUST_BE_DIRECTORY))
open_flags |= O_DIRECTORY;
if (FLAGS_SET(chase_flags, CHASE_MUST_BE_REGULAR))
xopen_flags |= XO_REGULAR;
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0)
/* Shortcut this call if none of the special features of this call are requested */
return xopenat_full(dir_fd, path,
open_flags | (FLAGS_SET(chase_flags, CHASE_NOFOLLOW) ? O_NOFOLLOW : 0),
/* xopen_flags = */ 0,
xopen_flags,
MODE_INVALID);
r = chaseat(dir_fd, path, chase_flags|CHASE_PARENT, &p, &path_fd);
r = chaseat(dir_fd, path, (chase_flags|CHASE_PARENT)&~CHASE_MUST_BE_REGULAR, &p, &path_fd);
if (r < 0)
return r;
@ -1011,7 +1023,12 @@ int chase_and_openat(
return r;
}
r = xopenat_full(path_fd, strempty(fname), open_flags|O_NOFOLLOW, /* xopen_flags= */ 0, MODE_INVALID);
r = xopenat_full(
path_fd,
strempty(fname),
open_flags|O_NOFOLLOW,
xopen_flags,
MODE_INVALID);
if (r < 0)
return r;
@ -1027,7 +1044,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
DIR *d;
int r;
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP)));
assert(!(chase_flags & (CHASE_NONEXISTENT|CHASE_STEP|CHASE_MUST_BE_REGULAR)));
assert(ret_dir);
if (dir_fd == AT_FDCWD && !ret_path && (chase_flags & CHASE_NO_SHORTCUT_MASK) == 0) {
@ -1045,7 +1062,7 @@ int chase_and_opendirat(int dir_fd, const char *path, ChaseFlags chase_flags, ch
return r;
assert(path_fd >= 0);
d = xopendirat(path_fd, ".", O_NOFOLLOW);
d = xopendirat(path_fd, /* path= */ NULL, /* flags= */ 0);
if (!d)
return -errno;

View File

@ -41,7 +41,7 @@ int chattr_full(
* drivers, where the ioctl might have different effects. Notably, DRM is using the same
* ioctl() number. */
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
if (!inode_type_can_chattr(st.st_mode))
return -ENOTTY;
if (mask == 0 && !ret_previous && !ret_final)
@ -140,7 +140,7 @@ int read_attr_fd(int fd, unsigned *ret) {
if (fstat(fd, &st) < 0)
return -errno;
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
if (!inode_type_can_chattr(st.st_mode))
return -ENOTTY;
_cleanup_close_ int fd_close = -EBADF;
@ -248,3 +248,7 @@ int set_proj_id_recursive(int fd, uint32_t proj_id) {
set_proj_id_cb,
UINT32_TO_PTR(proj_id));
}
bool inode_type_can_chattr(mode_t mode) {
return IN_SET(mode & S_IFMT, S_IFREG, S_IFDIR);
}

View File

@ -63,3 +63,5 @@ int set_proj_id_recursive(int fd, uint32_t proj_id);
static inline int chattr_secret(int fd, ChattrApplyFlags flags) {
return chattr_full(fd, NULL, CHATTR_SECRET_FLAGS, CHATTR_SECRET_FLAGS, NULL, NULL, flags|CHATTR_FALLBACK_BITWISE);
}
bool inode_type_can_chattr(mode_t mode);

View File

@ -928,17 +928,22 @@ int get_proc_field(const char *path, const char *key, char **ret) {
}
}
DIR* xopendirat(int dir_fd, const char *name, int flags) {
DIR* xopendirat(int dir_fd, const char *path, int flags) {
_cleanup_close_ int fd = -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(name);
assert(!(flags & (O_CREAT|O_TMPFILE)));
if (dir_fd == AT_FDCWD && flags == 0)
return opendir(name);
if ((dir_fd == AT_FDCWD || path_is_absolute(path)) &&
(flags &~ O_DIRECTORY) == 0)
return opendir(path);
fd = openat(dir_fd, name, O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags);
if (isempty(path)) {
path = ".";
flags |= O_NOFOLLOW;
}
fd = openat(dir_fd, path, O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags);
if (fd < 0)
return NULL;

View File

@ -92,7 +92,7 @@ int script_get_shebang_interpreter(const char *path, char **ret);
int get_proc_field(const char *path, const char *key, char **ret);
DIR* xopendirat(int dir_fd, const char *name, int flags);
DIR* xopendirat(int dir_fd, const char *path, int flags);
typedef enum XfopenFlags {
XFOPEN_UNLOCKED = 1 << 0, /* call __fsetlocking(FSETLOCKING_BYCALLER) after opened */

View File

@ -463,7 +463,8 @@ static int maybe_decrypt_and_write_credential(
struct load_cred_args *args,
const char *id,
const char *data,
size_t size) {
size_t size,
bool graceful) {
_cleanup_(iovec_done_erase) struct iovec plaintext = {};
size_t add;
@ -517,8 +518,14 @@ static int maybe_decrypt_and_write_credential(
default:
assert_not_reached();
}
if (r < 0)
if (r < 0) {
if (graceful) {
log_warning_errno(r, "Unable to decrypt credential '%s', skipping.", id);
return 0;
}
return r;
}
data = plaintext.iov_base;
size = plaintext.iov_len;
@ -607,7 +614,7 @@ static int load_credential_glob(
if (r < 0)
return log_debug_errno(r, "Failed to read credential '%s': %m", *p);
r = maybe_decrypt_and_write_credential(args, fn, data, size);
r = maybe_decrypt_and_write_credential(args, fn, data, size, /* graceful= */ true);
if (r < 0)
return r;
}
@ -732,7 +739,7 @@ static int load_credential(
if (r < 0)
return log_debug_errno(r, "Failed to read credential '%s': %m", path);
return maybe_decrypt_and_write_credential(args, id, data, size);
return maybe_decrypt_and_write_credential(args, id, data, size, /* graceful= */ true);
}
static int load_cred_recurse_dir_cb(
@ -869,7 +876,8 @@ static int acquire_credentials(
args.encrypted = false;
r = load_credential_glob(&args,
r = load_credential_glob(
&args,
ic,
search_path,
READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER);
@ -884,7 +892,8 @@ static int acquire_credentials(
args.encrypted = true;
r = load_credential_glob(&args,
r = load_credential_glob(
&args,
ic,
search_path,
READ_FULL_FILE_SECURE|READ_FULL_FILE_FAIL_WHEN_LARGER|READ_FULL_FILE_UNBASE64);
@ -905,7 +914,7 @@ static int acquire_credentials(
if (errno != ENOENT)
return log_debug_errno(errno, "Failed to test if credential %s exists: %m", sc->id);
r = maybe_decrypt_and_write_credential(&args, sc->id, sc->data, sc->size);
r = maybe_decrypt_and_write_credential(&args, sc->id, sc->data, sc->size, /* graceful= */ false);
if (r < 0)
return r;
}

View File

@ -1411,7 +1411,7 @@ static int vl_method_decrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
if (r == -EBADMSG)
return sd_varlink_error(link, "io.systemd.Credentials.BadFormat", NULL);
if (r == -EREMOTE)
if (r == -EDESTADDRREQ)
return sd_varlink_error(link, "io.systemd.Credentials.NameMismatch", NULL);
if (r == -ESTALE)
return sd_varlink_error(link, "io.systemd.Credentials.TimeMismatch", NULL);
@ -1419,6 +1419,16 @@ static int vl_method_decrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
return sd_varlink_error(link, "io.systemd.Credentials.NoSuchUser", NULL);
if (r == -EMEDIUMTYPE)
return sd_varlink_error(link, "io.systemd.Credentials.BadScope", NULL);
if (r == -EHOSTDOWN)
return sd_varlink_error(link, "io.systemd.Credentials.CantFindPCRSignature", NULL);
if (r == -EHWPOISON)
return sd_varlink_error(link, "io.systemd.Credentials.NullKeyNotAllowed", NULL);
if (r == -EREMOTE)
return sd_varlink_error(link, "io.systemd.Credentials.KeyBelongsToOtherTPM", NULL);
if (r == -ENOLCK)
return sd_varlink_error(link, "io.systemd.Credentials.TPMInDictionaryLockout", NULL);
if (IN_SET(r, -EREMCHG, -ENOANO, -EUCLEAN, -EPERM))
return sd_varlink_error(link, "io.systemd.Credentials.UnexpectedPCRState", NULL);
if (r < 0)
return r;
@ -1433,25 +1443,17 @@ static int vl_method_decrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
return sd_varlink_reply(link, reply);
}
static int run(int argc, char *argv[]) {
int r;
log_setup();
r = parse_argv(argc, argv);
if (r <= 0)
return r;
if (arg_varlink) {
static int vl_server(void) {
_cleanup_(sd_varlink_server_unrefp) sd_varlink_server *varlink_server = NULL;
_cleanup_hashmap_free_ Hashmap *polkit_registry = NULL;
int r;
/* Invocation as Varlink service */
r = varlink_server_new(
&varlink_server,
SD_VARLINK_SERVER_ACCOUNT_UID|SD_VARLINK_SERVER_INHERIT_USERDATA|SD_VARLINK_SERVER_INPUT_SENSITIVE,
NULL);
&polkit_registry);
if (r < 0)
return log_error_errno(r, "Failed to allocate Varlink server: %m");
@ -1466,14 +1468,24 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to bind Varlink methods: %m");
sd_varlink_server_set_userdata(varlink_server, &polkit_registry);
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();
return creds_main(argc, argv);
}

View File

@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <mntent.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@ -33,6 +32,7 @@
#include "hexdecoct.h"
#include "json-util.h"
#include "libfido2-util.h"
#include "libmount-util.h"
#include "log.h"
#include "main-func.h"
#include "memory-util.h"
@ -732,26 +732,37 @@ static char* disk_description(const char *path) {
return NULL;
}
static char *disk_mount_point(const char *label) {
static char* disk_mount_point(const char *label) {
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
_cleanup_free_ char *device = NULL;
_cleanup_endmntent_ FILE *f = NULL;
struct mntent *m;
int r;
/* Yeah, we don't support native systemd unit files here for now */
assert(label);
device = strjoin("/dev/mapper/", label);
if (!device)
return NULL;
f = setmntent(fstab_path(), "re");
if (!f)
r = libmount_parse_fstab(&table, &iter);
if (r < 0)
return NULL;
while ((m = getmntent(f)))
if (path_equal(m->mnt_fsname, device))
return strdup(m->mnt_dir);
for (;;) {
struct libmnt_fs *fs;
r = mnt_table_next_fs(table, iter, &fs);
if (r != 0)
return NULL;
if (path_equal(mnt_fs_get_source(fs), device)) {
const char *target = mnt_fs_get_target(fs);
if (target)
return strdup(target);
}
}
}
static char *friendly_disk_name(const char *src, const char *vol) {

View File

@ -19,6 +19,7 @@ executables += [
'sources' : systemd_cryptsetup_sources,
'dependencies' : [
libcryptsetup,
libmount,
libopenssl,
libp11kit_cflags,
],

View File

@ -24,10 +24,10 @@
#include "generator.h"
#include "in-addr-util.h"
#include "initrd-util.h"
#include "libmount-util.h"
#include "log.h"
#include "main-func.h"
#include "mount-setup.h"
#include "mount-util.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"
@ -1025,9 +1025,9 @@ static int parse_fstab_one(
}
static int parse_fstab(bool prefix_sysroot) {
_cleanup_endmntent_ FILE *f = NULL;
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
const char *fstab;
struct mntent *me;
int r, ret = 0;
if (prefix_sysroot)
@ -1039,27 +1039,31 @@ static int parse_fstab(bool prefix_sysroot) {
log_debug("Parsing %s...", fstab);
f = setmntent(fstab, "re");
if (!f) {
if (errno == ENOENT)
r = libmount_parse_full(fstab, /* source = */ NULL, &table, &iter);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to parse '%s': %m", fstab);
return log_error_errno(errno, "Failed to open %s: %m", fstab);
}
for (;;) {
struct libmnt_fs *fs;
r = mnt_table_next_fs(table, iter, &fs);
if (r < 0)
return log_error_errno(r, "Failed to get next entry from '%s': %m", fstab);
if (r > 0) /* EOF */
return ret;
while ((me = getmntent(f))) {
r = parse_fstab_one(fstab,
me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts, me->mnt_passno,
mnt_fs_get_source(fs), mnt_fs_get_target(fs),
mnt_fs_get_fstype(fs), mnt_fs_get_options(fs), mnt_fs_get_passno(fs),
prefix_sysroot,
/* accept_root = */ false,
/* use_swap_enabled = */ true);
if (r < 0 && ret >= 0)
ret = r;
if (arg_sysroot_check && r > 0)
return true; /* We found a mount or swap that would be started… */
RET_GATHER(ret, r);
}
return ret;
}
static int mount_source_is_nfsroot(const char *what) {
@ -1414,15 +1418,15 @@ static int add_mounts_from_cmdline(void) {
static int add_mounts_from_creds(bool prefix_sysroot) {
_cleanup_free_ void *b = NULL;
struct mntent *me;
size_t bs;
int r;
const char *cred;
int r, ret = 0;
assert(in_initrd() || !prefix_sysroot);
r = read_credential_with_decryption(
in_initrd() && !prefix_sysroot ? "fstab.extra.initrd" : "fstab.extra",
&b, &bs);
cred = in_initrd() && !prefix_sysroot ? "fstab.extra.initrd" : "fstab.extra";
r = read_credential_with_decryption(cred, &b, &bs);
if (r <= 0)
return r;
@ -1431,20 +1435,29 @@ static int add_mounts_from_creds(bool prefix_sysroot) {
if (!f)
return log_oom();
r = 0;
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
while ((me = getmntent(f)))
RET_GATHER(r, parse_fstab_one("/run/credentials",
me->mnt_fsname,
me->mnt_dir,
me->mnt_type,
me->mnt_opts,
me->mnt_passno,
/* prefix_sysroot = */ prefix_sysroot,
r = libmount_parse_full(cred, f, &table, &iter);
if (r < 0)
return log_error_errno(r, "Failed to parse credential '%s' (as fstab): %m", cred);
for (;;) {
struct libmnt_fs *fs;
r = mnt_table_next_fs(table, iter, &fs);
if (r < 0)
return log_error_errno(r, "Failed to get next fstab entry from credential '%s': %m", cred);
if (r > 0) /* EOF */
return ret;
RET_GATHER(ret, parse_fstab_one("/run/credentials",
mnt_fs_get_source(fs), mnt_fs_get_target(fs),
mnt_fs_get_fstype(fs), mnt_fs_get_options(fs), mnt_fs_get_passno(fs),
prefix_sysroot,
/* accept_root = */ true,
/* use_swap_enabled = */ true));
return r;
}
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {

View File

@ -4,6 +4,7 @@ executables += [
generator_template + {
'name' : 'systemd-fstab-generator',
'sources' : files('fstab-generator.c'),
'dependencies' : libmount,
},
]

View File

@ -11,6 +11,7 @@
#include "fd-util.h"
#include "format-util.h"
#include "fs-util.h"
#include "import-common.h"
#include "log.h"
#include "pretty-print.h"
#include "ratelimit.h"
@ -20,8 +21,6 @@
#include "time-util.h"
#include "tmpfile-util.h"
#define COPY_BUFFER_SIZE (16*1024)
typedef struct RawExport {
sd_event *event;
@ -161,7 +160,7 @@ static int raw_export_process(RawExport *e) {
if (!e->tried_sendfile && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
l = sendfile(e->output_fd, e->input_fd, NULL, COPY_BUFFER_SIZE);
l = sendfile(e->output_fd, e->input_fd, NULL, IMPORT_BUFFER_SIZE);
if (l < 0) {
if (errno == EAGAIN)
return 0;
@ -181,7 +180,7 @@ static int raw_export_process(RawExport *e) {
}
while (e->buffer_size <= 0) {
uint8_t input[COPY_BUFFER_SIZE];
uint8_t input[IMPORT_BUFFER_SIZE];
if (e->eof) {
r = 0;

View File

@ -12,6 +12,7 @@
#include "format-util.h"
#include "import-common.h"
#include "log.h"
#include "pidref.h"
#include "pretty-print.h"
#include "process-util.h"
#include "ratelimit.h"
@ -20,8 +21,6 @@
#include "time-util.h"
#include "tmpfile-util.h"
#define COPY_BUFFER_SIZE (16*1024)
typedef struct TarExport {
sd_event *event;
@ -45,7 +44,7 @@ typedef struct TarExport {
uint64_t written_compressed;
uint64_t written_uncompressed;
pid_t tar_pid;
PidRef tar_pid;
struct stat st;
uint64_t quota_referenced;
@ -63,8 +62,7 @@ TarExport *tar_export_unref(TarExport *e) {
sd_event_source_unref(e->output_event_source);
if (e->tar_pid > 1)
sigkill_wait(e->tar_pid);
pidref_done_sigkill_wait(&e->tar_pid);
if (e->temp_path) {
(void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA);
@ -105,6 +103,7 @@ int tar_export_new(
.quota_referenced = UINT64_MAX,
.last_percent = UINT_MAX,
.progress_ratelimit = { 100 * USEC_PER_MSEC, 1 },
.tar_pid = PIDREF_NULL,
};
if (event)
@ -160,10 +159,13 @@ static int tar_export_finish(TarExport *e) {
assert(e);
assert(e->tar_fd >= 0);
if (e->tar_pid > 0) {
r = wait_for_terminate_and_check("tar", TAKE_PID(e->tar_pid), WAIT_LOG);
if (pidref_is_set(&e->tar_pid)) {
r = pidref_wait_for_terminate_and_check("tar", &e->tar_pid, WAIT_LOG);
if (r < 0)
return r;
pidref_done(&e->tar_pid);
if (r != EXIT_SUCCESS)
return -EPROTO;
}
@ -181,7 +183,7 @@ static int tar_export_process(TarExport *e) {
if (!e->tried_splice && e->compress.type == IMPORT_COMPRESS_UNCOMPRESSED) {
l = splice(e->tar_fd, NULL, e->output_fd, NULL, COPY_BUFFER_SIZE, 0);
l = splice(e->tar_fd, NULL, e->output_fd, NULL, IMPORT_BUFFER_SIZE, 0);
if (l < 0) {
if (errno == EAGAIN)
return 0;
@ -201,7 +203,7 @@ static int tar_export_process(TarExport *e) {
}
while (e->buffer_size <= 0) {
uint8_t input[COPY_BUFFER_SIZE];
uint8_t input[IMPORT_BUFFER_SIZE];
if (e->eof) {
r = tar_export_finish(e);

View File

@ -18,6 +18,7 @@
#include "runtime-scope.h"
#include "signal-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "verbs.h"
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
@ -93,6 +94,9 @@ static int export_tar(int argc, char *argv[], void *userdata) {
} else {
_cleanup_free_ char *pretty = NULL;
if (isatty_safe(STDOUT_FILENO))
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Refusing to write archive to TTY.");
fd = STDOUT_FILENO;
(void) fd_get_path(fd, &pretty);

View File

@ -15,15 +15,16 @@
#include "import-common.h"
#include "log.h"
#include "os-util.h"
#include "pidref.h"
#include "process-util.h"
#include "selinux-util.h"
#include "stat-util.h"
#include "tmpfile-util.h"
int import_fork_tar_x(const char *path, pid_t *ret) {
int import_fork_tar_x(const char *path, PidRef *ret) {
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
_cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
bool use_selinux;
pid_t pid;
int r;
assert(path);
@ -32,12 +33,16 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
if (pipe2(pipefd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pipe for tar: %m");
(void) fcntl(pipefd[0], F_SETPIPE_SZ, IMPORT_BUFFER_SIZE);
use_selinux = mac_selinux_use();
r = safe_fork_full("(tar)",
r = pidref_safe_fork_full(
"(tar)",
(int[]) { pipefd[0], -EBADF, STDERR_FILENO },
NULL, 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG, &pid);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG,
&pid);
if (r < 0)
return r;
if (r == 0) {
@ -84,15 +89,15 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
_exit(EXIT_FAILURE);
}
*ret = pid;
*ret = TAKE_PIDREF(pid);
return TAKE_FD(pipefd[1]);
}
int import_fork_tar_c(const char *path, pid_t *ret) {
int import_fork_tar_c(const char *path, PidRef *ret) {
_cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
bool use_selinux;
pid_t pid;
int r;
assert(path);
@ -101,12 +106,16 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
if (pipe2(pipefd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pipe for tar: %m");
(void) fcntl(pipefd[0], F_SETPIPE_SZ, IMPORT_BUFFER_SIZE);
use_selinux = mac_selinux_use();
r = safe_fork_full("(tar)",
r = pidref_safe_fork_full(
"(tar)",
(int[]) { -EBADF, pipefd[1], STDERR_FILENO },
NULL, 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG, &pid);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG,
&pid);
if (r < 0)
return r;
if (r == 0) {
@ -139,7 +148,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
_exit(EXIT_FAILURE);
}
*ret = pid;
*ret = TAKE_PIDREF(pid);
return TAKE_FD(pipefd[0]);
}

View File

@ -33,11 +33,13 @@ typedef enum ImportFlags {
_IMPORT_FLAGS_INVALID = -EINVAL,
} ImportFlags;
int import_fork_tar_c(const char *path, pid_t *ret);
int import_fork_tar_x(const char *path, pid_t *ret);
int import_fork_tar_c(const char *path, PidRef *ret);
int import_fork_tar_x(const char *path, PidRef *ret);
int import_mangle_os_tree(const char *path);
bool import_validate_local(const char *name, ImportFlags flags);
int import_allocate_event_with_signals(sd_event **ret);
#define IMPORT_BUFFER_SIZE (128U*1024U)

View File

@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include "import-common.h"
#include "import-compress.h"
#include "log.h"
#include "string-table.h"
@ -148,7 +149,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
c->xz.avail_in = size;
while (c->xz.avail_in > 0) {
uint8_t buffer[16 * 1024];
uint8_t buffer[IMPORT_BUFFER_SIZE];
lzma_ret lzr;
c->xz.next_out = buffer;
@ -172,7 +173,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
c->gzip.avail_in = size;
while (c->gzip.avail_in > 0) {
uint8_t buffer[16 * 1024];
uint8_t buffer[IMPORT_BUFFER_SIZE];
c->gzip.next_out = buffer;
c->gzip.avail_out = sizeof(buffer);
@ -196,7 +197,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
c->bzip2.avail_in = size;
while (c->bzip2.avail_in > 0) {
uint8_t buffer[16 * 1024];
uint8_t buffer[IMPORT_BUFFER_SIZE];
c->bzip2.next_out = (char*) buffer;
c->bzip2.avail_out = sizeof(buffer);
@ -222,7 +223,7 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
};
while (input.pos < input.size) {
uint8_t buffer[16 * 1024];
uint8_t buffer[IMPORT_BUFFER_SIZE];
ZSTD_outBuffer output = {
.dst = buffer,
.size = sizeof(buffer),
@ -320,7 +321,7 @@ static int enlarge_buffer(void **buffer, size_t *buffer_size, size_t *buffer_all
if (*buffer_allocated > *buffer_size)
return 0;
l = MAX(16*1024U, (*buffer_size * 2));
l = MAX(IMPORT_BUFFER_SIZE, (*buffer_size * 2));
p = realloc(*buffer, l);
if (!p)
return -ENOMEM;

View File

@ -47,7 +47,7 @@ typedef struct RawImport {
sd_event_source *input_event_source;
uint8_t buffer[16*1024];
uint8_t buffer[IMPORT_BUFFER_SIZE];
size_t buffer_size;
uint64_t written_compressed;

View File

@ -19,6 +19,7 @@
#include "log.h"
#include "mkdir-label.h"
#include "path-util.h"
#include "pidref.h"
#include "pretty-print.h"
#include "process-util.h"
#include "ratelimit.h"
@ -49,7 +50,7 @@ typedef struct TarImport {
sd_event_source *input_event_source;
uint8_t buffer[16*1024];
uint8_t buffer[IMPORT_BUFFER_SIZE];
size_t buffer_size;
uint64_t written_compressed;
@ -57,7 +58,7 @@ typedef struct TarImport {
struct stat input_stat;
pid_t tar_pid;
PidRef tar_pid;
unsigned last_percent;
RateLimit progress_ratelimit;
@ -69,8 +70,7 @@ TarImport* tar_import_unref(TarImport *i) {
sd_event_source_unref(i->input_event_source);
if (i->tar_pid > 1)
sigkill_wait(i->tar_pid);
pidref_done_sigkill_wait(&i->tar_pid);
rm_rf_subvolume_and_free(i->temp_path);
@ -116,6 +116,7 @@ int tar_import_new(
.last_percent = UINT_MAX,
.image_root = TAKE_PTR(root),
.progress_ratelimit = { 100 * USEC_PER_MSEC, 1 },
.tar_pid = PIDREF_NULL,
};
if (event)
@ -174,10 +175,13 @@ static int tar_import_finish(TarImport *i) {
i->tar_fd = safe_close(i->tar_fd);
if (i->tar_pid > 0) {
r = wait_for_terminate_and_check("tar", TAKE_PID(i->tar_pid), WAIT_LOG);
if (pidref_is_set(&i->tar_pid)) {
r = pidref_wait_for_terminate_and_check("tar", &i->tar_pid, WAIT_LOG);
if (r < 0)
return r;
pidref_done(&i->tar_pid);
if (r != EXIT_SUCCESS)
return -EPROTO;
}

View File

@ -17,6 +17,7 @@
#include "log.h"
#include "mkdir-label.h"
#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "pull-common.h"
#include "pull-job.h"
@ -51,7 +52,7 @@ typedef struct TarPull {
char *local;
pid_t tar_pid;
PidRef tar_pid;
char *final_path;
char *temp_path;
@ -66,8 +67,7 @@ TarPull* tar_pull_unref(TarPull *i) {
if (!i)
return NULL;
if (i->tar_pid > 1)
sigkill_wait(i->tar_pid);
pidref_done_sigkill_wait(&i->tar_pid);
pull_job_unref(i->tar_job);
pull_job_unref(i->checksum_job);
@ -131,6 +131,7 @@ int tar_pull_new(
.image_root = TAKE_PTR(root),
.event = TAKE_PTR(e),
.glue = TAKE_PTR(g),
.tar_pid = PIDREF_NULL,
};
i->glue->on_finished = pull_job_curl_on_finished;
@ -377,10 +378,11 @@ static void tar_pull_job_on_finished(PullJob *j) {
pull_job_close_disk_fd(i->tar_job);
pull_job_close_disk_fd(i->settings_job);
if (i->tar_pid > 0) {
r = wait_for_terminate_and_check("tar", TAKE_PID(i->tar_pid), WAIT_LOG);
if (pidref_is_set(&i->tar_pid)) {
r = pidref_wait_for_terminate_and_check("tar", &i->tar_pid, WAIT_LOG);
if (r < 0)
goto finish;
pidref_done(&i->tar_pid);
if (r != EXIT_SUCCESS) {
r = -EIO;
goto finish;
@ -509,7 +511,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
i = j->userdata;
assert(i->tar_job == j);
assert(i->tar_pid <= 0);
assert(!pidref_is_set(&i->tar_pid));
if (i->flags & IMPORT_DIRECT)
where = i->local;

View File

@ -136,7 +136,6 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
}
int id128_get_machine_at(int rfd, sd_id128_t *ret) {
_cleanup_close_ int fd = -EBADF;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
@ -147,7 +146,8 @@ int id128_get_machine_at(int rfd, sd_id128_t *ret) {
if (r > 0)
return sd_id128_get_machine(ret);
fd = chase_and_openat(rfd, "/etc/machine-id", CHASE_AT_RESOLVE_IN_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
_cleanup_close_ int fd =
chase_and_openat(rfd, "/etc/machine-id", CHASE_AT_RESOLVE_IN_ROOT|CHASE_MUST_BE_REGULAR, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* ret_path= */ NULL);
if (fd < 0)
return fd;
@ -155,12 +155,11 @@ int id128_get_machine_at(int rfd, sd_id128_t *ret) {
}
int id128_get_machine(const char *root, sd_id128_t *ret) {
_cleanup_close_ int fd = -EBADF;
if (empty_or_root(root))
return sd_id128_get_machine(ret);
fd = chase_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_NOCTTY, NULL);
_cleanup_close_ int fd =
chase_and_open("/etc/machine-id", root, CHASE_PREFIX_ROOT|CHASE_MUST_BE_REGULAR, O_RDONLY|O_CLOEXEC|O_NOCTTY, /* ret_path= */ NULL);
if (fd < 0)
return fd;

View File

@ -19,6 +19,7 @@
#include "memory-util.h"
#include "pager.h"
#include "parse-argument.h"
#include "path-util.h"
#include "polkit-agent.h"
#include "pretty-print.h"
#include "runtime-scope.h"
@ -290,6 +291,14 @@ static int set_x11_keymap(int argc, char **argv, void *userdata) {
return 0;
}
static const char* xkb_directory(void) {
static const char *cached = NULL;
if (!cached)
cached = secure_getenv("SYSTEMD_XKB_DIRECTORY") ?: "/usr/share/X11/xkb";
return cached;
}
static int list_x11_keymaps(int argc, char **argv, void *userdata) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_strv_free_ char **list = NULL;
@ -302,9 +311,15 @@ static int list_x11_keymaps(int argc, char **argv, void *userdata) {
} state = NONE, look_for;
int r;
f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
_cleanup_free_ char *xkb_base = path_join(xkb_directory(), "rules/base.lst");
if (!xkb_base)
return log_oom();
f = fopen(xkb_base, "re");
if (!f)
return log_error_errno(errno, "Failed to open keyboard mapping list: %m");
return log_error_errno(errno,
"Failed to open keyboard mapping list %s: %m",
xkb_base);
if (streq(argv[0], "list-x11-keymap-models"))
look_for = MODELS;
@ -323,7 +338,9 @@ static int list_x11_keymaps(int argc, char **argv, void *userdata) {
r = read_stripped_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read keyboard mapping list: %m");
return log_error_errno(r,
"Failed to read keyboard mapping list %s: %m",
xkb_base);
if (r == 0)
break;
@ -377,7 +394,8 @@ static int list_x11_keymaps(int argc, char **argv, void *userdata) {
if (strv_isempty(list))
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
"Couldn't find any entries.");
"Couldn't find any entries in keyboard mapping list %s.",
xkb_base);
strv_sort_uniq(list);

View File

@ -4,5 +4,6 @@ executables += [
libexec_template + {
'name' : 'systemd-remount-fs',
'sources' : files('remount-fs.c'),
'dependencies' : libmount,
},
]

View File

@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <mntent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
@ -11,6 +10,7 @@
#include "format-util.h"
#include "fstab-util.h"
#include "hashmap.h"
#include "libmount-util.h"
#include "log.h"
#include "main-func.h"
#include "mount-setup.h"
@ -35,10 +35,8 @@ static int track_pid(Hashmap **h, const char *path, pid_t pid) {
return log_oom();
r = hashmap_ensure_put(h, &trivial_hash_ops_value_free, PID_TO_PTR(pid), c);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to store pid " PID_FMT, pid);
return log_error_errno(r, "Failed to store pid " PID_FMT " for mount '%s': %m", pid, path);
TAKE_PTR(c);
return 0;
@ -48,6 +46,8 @@ static int do_remount(const char *path, bool force_rw, Hashmap **pids) {
pid_t pid;
int r;
assert(path);
log_debug("Remounting %s...", path);
r = safe_fork(force_rw ? "(remount-rw)" : "(remount)",
@ -70,10 +70,10 @@ static int do_remount(const char *path, bool force_rw, Hashmap **pids) {
}
static int remount_by_fstab(Hashmap **ret_pids) {
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
_cleanup_hashmap_free_ Hashmap *pids = NULL;
_cleanup_endmntent_ FILE *f = NULL;
bool has_root = false;
struct mntent* me;
int r;
assert(ret_pids);
@ -81,24 +81,33 @@ static int remount_by_fstab(Hashmap **ret_pids) {
if (!fstab_enabled())
return 0;
f = setmntent(fstab_path(), "re");
if (!f) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to open %s: %m", fstab_path());
r = libmount_parse_fstab(&table, &iter);
if (r == -ENOENT)
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to parse fstab: %m");
while ((me = getmntent(f))) {
/* Remount the root fs, /usr, and all API VFSs */
if (!mount_point_is_api(me->mnt_dir) &&
!PATH_IN_SET(me->mnt_dir, "/", "/usr"))
for (;;) {
struct libmnt_fs *fs;
r = mnt_table_next_fs(table, iter, &fs);
if (r < 0)
return log_error_errno(r, "Failed to get next entry from fstab: %m");
if (r > 0) /* EOF */
break;
const char *target = mnt_fs_get_target(fs);
if (!target)
continue;
if (path_equal(me->mnt_dir, "/"))
has_root = true;
/* Remount the root fs, /usr/, and all API VFSs */
r = do_remount(me->mnt_dir, false, &pids);
if (path_equal(target, "/"))
has_root = true;
else if (!path_equal(target, "/usr") && !mount_point_is_api(target))
continue;
r = do_remount(target, /* force_rw = */ false, &pids);
if (r < 0)
return r;
}
@ -132,7 +141,7 @@ static int run(int argc, char *argv[]) {
log_warning_errno(r, "Failed to parse $SYSTEMD_REMOUNT_ROOT_RW, ignoring: %m");
if (r > 0) {
r = do_remount("/", true, &pids);
r = do_remount("/", /* force_rw = */ true, &pids);
if (r < 0)
return r;
}

View File

@ -648,3 +648,7 @@ int fd_acl_make_writable_fallback(int fd) {
return 1;
}
int inode_type_can_acl(mode_t mode) {
return IN_SET(mode & S_IFMT, S_IFSOCK, S_IFREG, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO);
}

View File

@ -53,3 +53,5 @@ static inline int fd_acl_make_writable(int fd) {
}
#endif
int inode_type_can_acl(mode_t mode);

View File

@ -1201,6 +1201,19 @@ int decrypt_credential_and_warn(
assert(iovec_is_valid(input));
assert(ret);
/* Relevant error codes:
*
* -EBADMSG Corrupted file
* -EOPNOTSUPP Unsupported file type (could be: requires TPM but we have no TPM)
* -EHOSTDOWN Need PCR signature file, but couldn't find it
* -EHWPOISON Attempt to decode NULL key (and CREDENTIAL_ALLOW_NULL is off), but the system has a TPM and SecureBoot is on
* -EMEDIUMTYPE File has unexpected scope, i.e. user-scoped credential is attempted to be unlocked in system scope, or vice versa
* -EDESTADDRREQ Credential is incorrectly named (i.e. the authenticated name does not match the actual name)
* -ESTALE Credential's valdity has passed
* -ESRCH User specified for scope does not exist on this system
*
* (plus the various error codes tpm2_unseal() returns) */
h = (struct encrypted_credential_header*) input->iov_base;
/* The ID must fit in, for the current and all future formats */
@ -1218,8 +1231,10 @@ int decrypt_credential_and_warn(
if (with_tpm2_pk) {
r = tpm2_load_pcr_signature(tpm2_signature_path, &signature_json);
if (r == -ENOENT)
return log_error_errno(SYNTHETIC_ERRNO(EHOSTDOWN), "Couldn't find PCR signature file: %m");
if (r < 0)
return log_error_errno(r, "Failed to load pcr signature: %m");
return log_error_errno(r, "Failed to load PCR signature: %m");
}
if (with_null && !FLAGS_SET(flags, CREDENTIAL_ALLOW_NULL)) {
@ -1234,7 +1249,7 @@ int decrypt_credential_and_warn(
if (efi_has_tpm2()) {
if (is_efi_secure_boot())
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON),
"Credential uses fixed key for fallback use when TPM2 is absent — but TPM2 is present, and SecureBoot is enabled, refusing.");
log_warning("Credential uses fixed key for use when TPM2 is absent, but TPM2 is present! Accepting anyway, since SecureBoot is disabled.");
@ -1354,7 +1369,7 @@ int decrypt_credential_and_warn(
/* srk= */ NULL,
&tpm2_key);
if (r == -EREMOTE)
return log_error_errno(r, "TPM key integrity check failed. Key enrolled in superblock most likely does not belong to this TPM.");
return log_error_errno(r, "TPM key integrity check failed. Key most likely does not belong to this TPM.");
if (ERRNO_IS_NEG_TPM2_UNSEAL_BAD_PCR(r))
return log_error_errno(r, "TPM policy does not match current system state. Either system has been tempered with or policy out-of-date: %m");
if (r < 0)
@ -1486,7 +1501,7 @@ int decrypt_credential_and_warn(
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_CREDENTIAL_VALIDATE_NAME: %m");
if (r != 0)
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Embedded credential name '%s' does not match filename '%s', refusing.", embedded_name, validate_name);
return log_error_errno(SYNTHETIC_ERRNO(EDESTADDRREQ), "Embedded credential name '%s' does not match filename '%s', refusing.", embedded_name, validate_name);
log_debug("Embedded credential name '%s' does not match expected name '%s', but configured to use credential anyway.", embedded_name, validate_name);
}
@ -1637,16 +1652,26 @@ int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp,
if (r < 0)
return log_error_errno(r, "Failed to call Decrypt() varlink call.");
if (!isempty(error_id)) {
if (streq(error_id, "io.systemd.Credentials.BadFormat"))
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Bad credential format.");
if (streq(error_id, "io.systemd.Credentials.NameMismatch"))
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE), "Name in credential doesn't match expectations.");
if (streq(error_id, "io.systemd.Credentials.TimeMismatch"))
return log_error_errno(SYNTHETIC_ERRNO(ESTALE), "Outside of credential validity time window.");
if (streq(error_id, "io.systemd.Credentials.NoSuchUser"))
return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "No such user.");
if (streq(error_id, "io.systemd.Credentials.BadScope"))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Scope mismtach.");
static struct {
const char *id;
int errnum;
const char *msg;
} table[] = {
{ "io.systemd.Credentials.BadFormat", EBADMSG, "Bad credential format." },
{ "io.systemd.Credentials.NameMismatch", EDESTADDRREQ, "Name in credential doesn't match expectations." },
{ "io.systemd.Credentials.TimeMismatch", ESTALE, "Outside of credential validity time window." },
{ "io.systemd.Credentials.NoSuchUser", ESRCH, "No such user." },
{ "io.systemd.Credentials.BadScope", EMEDIUMTYPE, "Scope mismatch." },
{ "io.systemd.Credentials.CantFindPCRSignature", EHOSTDOWN, "PCR signature required for decryption, but could not be found." },
{ "io.systemd.Credentials.NullKeyNotAllowed", EHWPOISON, "The key was encrypted with a null key, but that's now allowed during decryption." },
{ "io.systemd.Credentials.KeyBelongsToOtherTPM", EREMOTE, "The TPM integrity check for this key failed, key probably belongs to another TPM, or was corrupted." },
{ "io.systemd.Credentials.TPMInDictionaryLockout", ENOLCK, "The TPM is in dictionary lockout mode, cannot operate." },
{ "io.systemd.Credentials.UnexpectedPCRState" , EUCLEAN, "Unexpected TPM PCR state of the system." },
};
FOREACH_ELEMENT(i, table)
if (streq(i->id, error_id))
return log_error_errno(SYNTHETIC_ERRNO(i->errnum), "%s", i->msg);
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to decrypt: %s", error_id);
}

View File

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <mntent.h>
#include "forward.h"
typedef struct SubMount {
@ -37,9 +35,6 @@ static inline int mount_switch_root(const char *path, unsigned long mount_propag
return mount_switch_root_full(path, mount_propagation_flag, false);
}
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, endmntent, NULL);
#define _cleanup_endmntent_ _cleanup_(endmntentp)
int mount_verbose_full(
int error_log_level,
const char *what,

View File

@ -161,7 +161,7 @@ static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shi
assert(st);
/* ACLs are not supported on symlinks, there's no point in trying */
if (S_ISLNK(st->st_mode))
if (!inode_type_can_acl(st->st_mode))
return 0;
r = get_acl(fd, name, ACL_TYPE_ACCESS, &acl);

View File

@ -44,6 +44,11 @@ static SD_VARLINK_DEFINE_ERROR(NameMismatch);
static SD_VARLINK_DEFINE_ERROR(TimeMismatch);
static SD_VARLINK_DEFINE_ERROR(NoSuchUser);
static SD_VARLINK_DEFINE_ERROR(BadScope);
static SD_VARLINK_DEFINE_ERROR(CantFindPCRSignature);
static SD_VARLINK_DEFINE_ERROR(NullKeyNotAllowed);
static SD_VARLINK_DEFINE_ERROR(KeyBelongsToOtherTPM);
static SD_VARLINK_DEFINE_ERROR(TPMInDictionaryLockout);
static SD_VARLINK_DEFINE_ERROR(UnexpectedPCRState);
SD_VARLINK_DEFINE_INTERFACE(
io_systemd_Credentials,
@ -62,4 +67,14 @@ SD_VARLINK_DEFINE_INTERFACE(
SD_VARLINK_SYMBOL_COMMENT("The specified user does not exist."),
&vl_error_NoSuchUser,
SD_VARLINK_SYMBOL_COMMENT("The credential does not match the selected scope."),
&vl_error_BadScope);
&vl_error_BadScope,
SD_VARLINK_SYMBOL_COMMENT("PCR signature required for decryption, but not found."),
&vl_error_CantFindPCRSignature,
SD_VARLINK_SYMBOL_COMMENT("The key was encrypted with a null key, but that's now allowed during decryption."),
&vl_error_NullKeyNotAllowed,
SD_VARLINK_SYMBOL_COMMENT("The TPM integrity check for this key failed, key probably belongs to another TPM, or was corrupted."),
&vl_error_KeyBelongsToOtherTPM,
SD_VARLINK_SYMBOL_COMMENT("The TPM is in dictionary lockout mode, cannot operate."),
&vl_error_TPMInDictionaryLockout,
SD_VARLINK_SYMBOL_COMMENT("Unexpected TPM PCR state of the system."),
&vl_error_UnexpectedPCRState);

View File

@ -164,7 +164,7 @@ static void test_encrypt_decrypt_with(sd_id128_t mode, uid_t uid) {
&encrypted,
CREDENTIAL_ALLOW_NULL,
&decrypted);
ASSERT_ERROR(r, EREMOTE); /* name didn't match */
ASSERT_ERROR(r, EDESTADDRREQ); /* name didn't match */
r = decrypt_credential_and_warn(
"foo",

View File

@ -1459,8 +1459,8 @@ static int fd_set_acls(
"Refusing to set ACLs on hardlinked file %s while the fs.protected_hardlinks sysctl is turned off.",
path);
if (S_ISLNK(st->st_mode)) {
log_debug("Skipping ACL fix for symlink %s.", path);
if (!inode_type_can_acl(st->st_mode)) {
log_debug("Skipping ACL fix for '%s' (inode type does not support ACLs).", path);
return 0;
}

View File

@ -190,7 +190,7 @@ static int stack_directory_find_prioritized_devnode(sd_device *dev, int dirfd, b
return -ENOMEM;
}
dir = xopendirat(dirfd, ".", O_NOFOLLOW);
dir = xopendirat(dirfd, /* path= */ NULL, /* flags= */ 0);
if (!dir)
return -errno;

View File

@ -49,10 +49,9 @@ FSTAB_GENERAL=(
"/dev/test25 /x-systemd.validatefs xfs x-systemd.validatefs 0 0"
# Incomplete, but valid entries
"/dev/incomplete1 /incomplete1"
"/dev/incomplete2 /incomplete2 ext4"
"/dev/incomplete3 /incomplete3 ext4 defaults"
"/dev/incomplete4 /incomplete4 ext4 defaults 0"
"/dev/incomplete1 /incomplete1 ext4"
"/dev/incomplete2 /incomplete2 ext4 defaults"
"/dev/incomplete3 /incomplete3 ext4 defaults 0"
# Remote filesystems
"/dev/remote1 /nfs nfs bg 0 0"