1
0
mirror of https://github.com/systemd/systemd synced 2026-03-31 20:24:50 +02:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Lennart Poettering
a07ab1dd8c update TODO 2021-10-22 19:20:13 +02:00
Jan Janssen
e6cab77eca sd-boot: Add keys to reboot into firmware interface
This is useful if the auto-firmware setting has been disabled. The
keys used here are based on what the majority of firmware employ in
the wild.
This also ensures there's a chance for the user to discover this in
case they were too slow during POST or simply used the wrong ones.
2021-10-22 19:12:55 +02:00
Lennart Poettering
784c249f41
Merge pull request #21094 from poettering/userns-split
util-lib: split out userns allocation into new helper function
2021-10-22 19:12:21 +02:00
Lennart Poettering
7afef7ed14
Merge pull request #21093 from poettering/homework-trivial-tweaks
homed trivial refactoring
2021-10-22 19:12:01 +02:00
Lennart Poettering
a5bf435ed7 update TODO 2021-10-22 17:57:13 +02:00
Lennart Poettering
a972ab0f25
Merge pull request #21079 from poettering/fd-reopen-directory-tweak
fd-util: when re-opening a directory with fd_reopen() go via openat(……
2021-10-22 17:41:17 +02:00
Lennart Poettering
43cac49092 process-util: move sync() out of freeze()
We are using this for creating userns namespaces, and we really
shouldn't try to sync there. Moreover the use of free() in shutdown code
doesn't need it anyway, since it just sync()ed right before anyway. Only
the third user of freeze() we have actually needs the syc(), hence do it
there and nowhere else.
2021-10-22 16:37:10 +02:00
Lennart Poettering
979b0ff2c4 namespace-util: introduce userns_acquire() as helper for allocating new unbound userns
This returns a namespace fd, and takes a uidmap/gidmap as string. This
is split out out mount-util.c's remount_idmap() logic, so that we can
allocate a userns independently.
2021-10-22 16:34:30 +02:00
Lennart Poettering
8ddefb8eef basic: move freeze() from shared/exec-util.h to basic/process-util.h
That way we can use it in other code from basic/. It fits into both
headers equally well or badly, hence let's just move this one function.
2021-10-22 16:34:30 +02:00
Lennart Poettering
7cb791bcac homework: split home_unshare_and_mount() in two
Previously the call did two things, and the second thing was optional
(depending on first arg being NULL). Let's simplify this and just make
it two distinct functions, where one calls the other.

This should make things a bit more readable, given that we called a
function called "…and_mount()" which didn't actually mount...

No actual code changes, just some refactoring.
2021-10-22 16:09:50 +02:00
Lennart Poettering
baa41cee77 homework: use bit fields where we deal with lots of separate boolean flags
No actual code changes, just making a structure a bit shorter.
2021-10-22 16:03:23 +02:00
Lennart Poettering
498abadb8c homework: add macro for "/run/systemd/user-home-mount"
We use this work dir a various places, and it's easy to mistype, hence
let the compiler detect this for us, and introduce a macro for it.

No code changes, just some search/replace.
2021-10-22 16:01:42 +02:00
Yu Watanabe
197aec7e79 network: dhcp6pd: fix the default value of subnet ID
The type of dhcp6_pd_subnet_id is int64_t.
2021-10-22 21:38:29 +09:00
Lennart Poettering
7c26a631ad varlink: disconnect varlink link in one more case
Previously we'd possibly see POLLHUP on a varlink link, and continue to
run epoll on it even though we have nothing to read nor write anymore.

Let's fix that, and once we know that there's nothing to write anymore
(or we saw a write error already) we'll disconnect after POLLHUP.

Fixes: #20062
2021-10-22 21:37:31 +09:00
Lennart Poettering
61fb966ccc test-fd-util: add test case for fd_reopen() 2021-10-22 14:06:08 +02:00
Lennart Poettering
d6274e6b8f fd-util: tweak error handling in fd_reopen()
If we know that /proc/ works, then ENOENT when reopening an fd means the
fd didn't exist. Let's return the correct error code for that, i.e.
EBADF.
2021-10-22 14:06:08 +02:00
Lennart Poettering
b4f73d1e17 fd-util: when re-opening a directory with fd_reopen() go via openat(…, ".", …)
This adds a tiny shortcut to fd_reopen(): if we are about to reopen the
fd via O_DIRECTORY then we know it#s a directory and we might as well
reopen it via opening "." using the fd as "at fd" in openat().

This has the benefit that we don't need /proc/self/fd/ around for this
special case: fewer sources of errors.
2021-10-22 14:05:12 +02:00
22 changed files with 296 additions and 104 deletions

14
TODO
View File

@ -81,6 +81,20 @@ Janitorial Clean-ups:
Features:
* userdbd: implement an additional varlink service socket that provides the
host user db in restricted form, then allow this to be bind mounted into
sandboxed environments that want the host database in minimal form. All
records would be stripped of all meta info, except the basic UID/name
info. Then use this in portabled environments that do not use PrivateUsers=1.
* logind introduce two types of sessions: "heavy" and "light". The former would
be our current sessions. But the latter would be a new type of session that
is mostly the same but does not pull in user@.service or wait for it. Then,
allow configuration which type of session is desired via pam_systemd
parameters, and then make user@.service's session one of these "light" ones.
People could then choose to make FTP sessions and suchlike "light" if they
don't want the service manager to be started for that.
* /etc/veritytab: allow that the roothash column can be specified as fs path
including a path to an AF_UNIX path, similar to how we do things with the
keys of /etc/crypttab. That way people can store/provide the roothash

View File

@ -188,8 +188,9 @@
<varlistentry>
<term>auto-firmware</term>
<listitem><para>Takes a boolean argument. Enable (the default) or disable
the "Reboot into firmware" entry.</para></listitem>
<listitem><para>A boolean controlling the presence of the "Reboot into firmware" entry
(enabled by default). If this is disabled, the firmware interface may still be reached
by using the <keycap>f</keycap> key.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -178,6 +178,15 @@
<term><keycap>F1</keycap></term>
<listitem><para>Show a help screen</para></listitem>
</varlistentry>
<varlistentry>
<term><keycap>f</keycap></term>
<listitem><para>Reboot into firmware interface.</para>
<para>For compatibility with the keybindings of several firmware implementations this operation
may also be reached with <keycap>F2</keycap>, <keycap>F10</keycap>, <keycap>Del</keycap> and
<keycap>Esc</keycap>.</para></listitem>
</varlistentry>
</variablelist>
<para>The following keys may be pressed during bootup or in the boot menu to directly boot a specific

View File

@ -645,7 +645,7 @@ finish:
}
int fd_reopen(int fd, int flags) {
int new_fd;
int new_fd, r;
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
* turn O_RDWR fds into O_RDONLY fds.
@ -654,15 +654,28 @@ int fd_reopen(int fd, int flags) {
*
* This implicitly resets the file read index to 0. */
if (FLAGS_SET(flags, O_DIRECTORY)) {
/* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
* magic /proc/ directory, and make ourselves independent of that being mounted. */
new_fd = openat(fd, ".", flags);
if (new_fd < 0)
return -errno;
return new_fd;
}
new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
if (new_fd < 0) {
if (errno != ENOENT)
return -errno;
if (proc_mounted() == 0)
r = proc_mounted();
if (r == 0)
return -ENOSYS; /* if we have no /proc/, the concept is not implementable */
return -ENOENT;
return r > 0 ? -EBADF : -ENOENT; /* If /proc/ is definitely around then this means the fd is
* not valid, otherwise let's propagate the original
* error */
}
return new_fd;

View File

@ -5,6 +5,7 @@
#include <sys/mount.h>
#include "fd-util.h"
#include "fileio.h"
#include "missing_fs.h"
#include "missing_magic.h"
#include "namespace-util.h"
@ -181,3 +182,41 @@ int detach_mount_namespace(void) {
return 0;
}
int userns_acquire(const char *uid_map, const char *gid_map) {
char path[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
_cleanup_(sigkill_waitp) pid_t pid = 0;
_cleanup_close_ int userns_fd = -1;
int r;
assert(uid_map);
assert(gid_map);
/* Forks off a process in a new userns, configures the specified uidmap/gidmap, acquires an fd to it,
* and then kills the process again. This way we have a userns fd that is not bound to any
* process. We can use that for file system mounts and similar. */
r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
if (r < 0)
return r;
if (r == 0)
/* Child. We do nothing here, just freeze until somebody kills us. */
freeze();
xsprintf(path, "/proc/" PID_FMT "/uid_map", pid);
r = write_string_file(path, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_error_errno(r, "Failed to write UID map: %m");
xsprintf(path, "/proc/" PID_FMT "/gid_map", pid);
r = write_string_file(path, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_error_errno(r, "Failed to write GID map: %m");
r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
if (r < 0)
return log_error_errno(r, "Failed to open netns fd: %m");
return TAKE_FD(userns_fd);
}

View File

@ -24,3 +24,5 @@ static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
return true;
}
int userns_acquire(const char *uid_map, const char *gid_map);

View File

@ -1618,6 +1618,25 @@ bool invoked_as(char *argv[], const char *token) {
return strstr(last_path_component(argv[0]), token);
}
_noreturn_ void freeze(void) {
log_close();
/* Make sure nobody waits for us on a socket anymore */
(void) close_all_fds_full(NULL, 0, false);
/* Let's not freeze right away, but keep reaping zombies. */
for (;;) {
siginfo_t si = {};
if (waitid(P_ALL, 0, &si, WEXITED) < 0 && errno != EINTR)
break;
}
/* waitid() failed with an unexpected error, things are really borked. Freeze now! */
for (;;)
pause();
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View File

@ -202,3 +202,5 @@ int pidfd_get_pid(int fd, pid_t *ret);
int setpriority_closest(int priority);
bool invoked_as(char *argv[], const char *token);
_noreturn_ void freeze(void);

View File

@ -543,6 +543,24 @@ static void print_status(Config *config, CHAR16 *loaded_image_path) {
}
}
static EFI_STATUS reboot_into_firmware(void) {
UINT64 osind = 0;
EFI_STATUS err;
if (!(get_os_indications_supported() & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
return log_error_status_stall(EFI_UNSUPPORTED, L"Reboot to firmware interface not supported.");
(void) efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &osind);
osind |= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", osind, EFI_VARIABLE_NON_VOLATILE);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error setting OsIndications: %r", err);
err = RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
return log_error_status_stall(err, L"Error calling ResetSystem: %r", err);
}
static BOOLEAN menu_run(
Config *config,
ConfigEntry **chosen_entry,
@ -566,7 +584,7 @@ static BOOLEAN menu_run(
UINT32 timeout_efivar_saved = config->timeout_sec_efivar;
UINT32 timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
INT16 idx;
BOOLEAN exit = FALSE, run = TRUE;
BOOLEAN exit = FALSE, run = TRUE, firmware_setup = FALSE;
INT64 console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
graphics_mode(FALSE);
@ -738,6 +756,13 @@ static BOOLEAN menu_run(
idx_highlight_prev = idx_highlight;
if (firmware_setup) {
firmware_setup = FALSE;
if (key == KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN))
reboot_into_firmware();
continue;
}
switch (key) {
case KEYPRESS(0, SCAN_UP, 0):
case KEYPRESS(0, 0, 'k'):
@ -794,7 +819,7 @@ static BOOLEAN menu_run(
case KEYPRESS(0, 0, 'h'):
case KEYPRESS(0, 0, 'H'):
case KEYPRESS(0, 0, '?'):
/* This must stay below 80 characters! Q/v/Ctrl+l deliberately not advertised. */
/* This must stay below 80 characters! Q/v/Ctrl+l/f deliberately not advertised. */
status = StrDuplicate(L"(d)efault (t/T)timeout (e)dit (r/R)resolution (p)rint (h)elp");
break;
@ -888,6 +913,20 @@ static BOOLEAN menu_run(
new_mode = TRUE;
break;
case KEYPRESS(0, 0, 'f'):
case KEYPRESS(0, 0, 'F'):
case KEYPRESS(0, SCAN_F2, 0): /* Most vendors. */
case KEYPRESS(0, SCAN_F10, 0): /* HP and Lenovo. */
case KEYPRESS(0, SCAN_DELETE, 0): /* Same as F2. */
case KEYPRESS(0, SCAN_ESC, 0): /* HP. */
if (get_os_indications_supported() & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) {
firmware_setup = TRUE;
/* Let's make sure the user really wants to do this. */
status = PoolPrint(L"Press Enter to reboot into firmware interface.");
} else
status = PoolPrint(L"Reboot into firmware interface not supported.");
break;
default:
/* jump with a hotkey directly to a matching entry */
idx = entry_lookup_key(config, idx_highlight+1, KEYCHAR(key));
@ -2180,24 +2219,6 @@ out_unload:
return err;
}
static EFI_STATUS reboot_into_firmware(void) {
UINT64 old, new;
EFI_STATUS err;
new = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
err = efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &old);
if (!EFI_ERROR(err))
new |= old;
err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", new, EFI_VARIABLE_NON_VOLATILE);
if (EFI_ERROR(err))
return err;
err = RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
return log_error_status_stall(err, L"Error calling ResetSystem: %r", err);
}
static void config_free(Config *config) {
assert(config);
for (UINTN i = 0; i < config->entry_count; i++)

View File

@ -222,6 +222,7 @@ _noreturn_ static void freeze_or_exit_or_reboot(void) {
}
log_emergency("Freezing execution.");
sync();
freeze();
}

View File

@ -28,7 +28,7 @@ int home_setup_cifs(
char **pw;
int r;
r = home_unshare_and_mount(NULL, NULL, false, user_record_mount_flags(h));
r = home_unshare_and_mkdir();
if (r < 0)
return r;
@ -68,7 +68,7 @@ int home_setup_cifs(
if (r == 0) {
/* Child */
execl("/bin/mount", "/bin/mount", "-n", "-t", "cifs",
h->cifs_service, "/run/systemd/user-home-mount",
h->cifs_service, HOME_RUNTIME_WORK_DIR,
"-o", options, NULL);
log_error_errno(errno, "Failed to execute mount: %m");
@ -89,7 +89,7 @@ int home_setup_cifs(
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
"Failed to mount home directory with supplied password.");
setup->root_fd = open("/run/systemd/user-home-mount", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
setup->root_fd = open(HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
}
if (setup->root_fd < 0)
return log_error_errno(errno, "Failed to open home directory: %m");

View File

@ -1260,7 +1260,7 @@ int home_setup_luks(
ip = force_image_path ?: user_record_image_path(h);
subdir = path_join("/run/systemd/user-home-mount/", user_record_user_name_and_realm(h));
subdir = path_join(HOME_RUNTIME_WORK_DIR, user_record_user_name_and_realm(h));
if (!subdir)
return log_oom();
@ -1374,7 +1374,7 @@ int home_setup_luks(
fail:
if (mounted)
(void) umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
(void) umount_verbose(LOG_ERR, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
if (dm_activated)
(void) sym_crypt_deactivate_by_name(cd, setup->dm_name, 0);
@ -2242,7 +2242,7 @@ int home_create_luks(
mounted = true;
subdir = path_join("/run/systemd/user-home-mount/", user_record_user_name_and_realm(h));
subdir = path_join(HOME_RUNTIME_WORK_DIR, user_record_user_name_and_realm(h));
if (!subdir) {
r = log_oom();
goto fail;
@ -2302,7 +2302,7 @@ int home_create_luks(
root_fd = safe_close(root_fd);
r = umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
r = umount_verbose(LOG_ERR, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
if (r < 0)
goto fail;
@ -2372,7 +2372,7 @@ fail:
root_fd = safe_close(root_fd);
if (mounted)
(void) umount_verbose(LOG_WARNING, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
(void) umount_verbose(LOG_WARNING, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
if (dm_activated)
(void) sym_crypt_deactivate_by_name(cd, dm_name, 0);
@ -2474,7 +2474,7 @@ static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool disc
}
if (setup->undo_mount) {
r = umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
r = umount_verbose(LOG_ERR, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
if (r < 0)
return r;
@ -2542,7 +2542,7 @@ static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool disc
}
if (re_open) {
setup->root_fd = open("/run/systemd/user-home-mount", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
setup->root_fd = open(HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
if (setup->root_fd < 0)
return log_error_errno(errno, "Failed to reopen file system: %m");
}

View File

@ -5,6 +5,7 @@
#include "alloc-util.h"
#include "homework-mount.h"
#include "homework.h"
#include "mkdir.h"
#include "mount-util.h"
#include "path-util.h"
@ -25,6 +26,9 @@ int home_mount_node(const char *node, const char *fstype, bool discard, unsigned
const char *options, *discard_option;
int r;
assert(node);
assert(fstype);
options = mount_options_for_fstype(fstype);
discard_option = discard ? "discard" : "nodiscard";
@ -38,7 +42,7 @@ int home_mount_node(const char *node, const char *fstype, bool discard, unsigned
} else
options = discard_option;
r = mount_nofollow_verbose(LOG_ERR, node, "/run/systemd/user-home-mount", fstype, flags|MS_RELATIME, strempty(options));
r = mount_nofollow_verbose(LOG_ERR, node, HOME_RUNTIME_WORK_DIR, fstype, flags|MS_RELATIME, strempty(options));
if (r < 0)
return r;
@ -46,24 +50,35 @@ int home_mount_node(const char *node, const char *fstype, bool discard, unsigned
return 0;
}
int home_unshare_and_mount(const char *node, const char *fstype, bool discard, unsigned long flags) {
int home_unshare_and_mkdir(void) {
int r;
if (unshare(CLONE_NEWNS) < 0)
return log_error_errno(errno, "Couldn't unshare file system namespace: %m");
assert(path_startswith(HOME_RUNTIME_WORK_DIR, "/run"));
r = mount_nofollow_verbose(LOG_ERR, "/run", "/run", NULL, MS_SLAVE|MS_REC, NULL); /* Mark /run as MS_SLAVE in our new namespace */
if (r < 0)
return r;
(void) mkdir_p("/run/systemd/user-home-mount", 0700);
if (node)
return home_mount_node(node, fstype, discard, flags);
(void) mkdir_p(HOME_RUNTIME_WORK_DIR, 0700);
return 0;
}
int home_unshare_and_mount(const char *node, const char *fstype, bool discard, unsigned long flags) {
int r;
assert(node);
assert(fstype);
r = home_unshare_and_mkdir();
if (r < 0)
return r;
return home_mount_node(node, fstype, discard, flags);
}
int home_move_mount(const char *user_name_and_realm, const char *target) {
_cleanup_free_ char *subdir = NULL;
const char *d;
@ -74,13 +89,13 @@ int home_move_mount(const char *user_name_and_realm, const char *target) {
/* If user_name_and_realm is set, then we'll mount a subdir of the source mount into the host. If
* it's NULL we'll move the mount itself */
if (user_name_and_realm) {
subdir = path_join("/run/systemd/user-home-mount/", user_name_and_realm);
subdir = path_join(HOME_RUNTIME_WORK_DIR, user_name_and_realm);
if (!subdir)
return log_oom();
d = subdir;
} else
d = "/run/systemd/user-home-mount/";
d = HOME_RUNTIME_WORK_DIR;
(void) mkdir_p(target, 0700);
@ -88,7 +103,7 @@ int home_move_mount(const char *user_name_and_realm, const char *target) {
if (r < 0)
return r;
r = umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
r = umount_verbose(LOG_ERR, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
if (r < 0)
return r;

View File

@ -4,5 +4,6 @@
#include <stdbool.h>
int home_mount_node(const char *node, const char *fstype, bool discard, unsigned long flags);
int home_unshare_and_mkdir(void);
int home_unshare_and_mount(const char *node, const char *fstype, bool discard, unsigned long flags);
int home_move_mount(const char *user_name_and_realm, const char *target);

View File

@ -317,7 +317,7 @@ int home_setup_done(HomeSetup *setup) {
}
if (setup->undo_mount) {
q = umount_verbose(LOG_DEBUG, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
q = umount_verbose(LOG_DEBUG, HOME_RUNTIME_WORK_DIR, UMOUNT_NOFOLLOW);
if (q < 0)
r = q;
}

View File

@ -28,12 +28,12 @@ typedef struct HomeSetup {
void *volume_key;
size_t volume_key_size;
bool undo_dm;
bool undo_mount;
bool do_offline_fitrim;
bool do_offline_fallocate;
bool do_mark_clean;
bool do_drop_caches;
bool undo_dm:1;
bool undo_mount:1; /* Whether to unmount /run/systemd/user-home-mount */
bool do_offline_fitrim:1;
bool do_offline_fallocate:1;
bool do_mark_clean:1;
bool do_drop_caches:1;
uint64_t partition_offset;
uint64_t partition_size;
@ -83,3 +83,5 @@ int home_extend_embedded_identity(UserRecord *h, UserRecord *used, HomeSetup *se
int user_record_authenticate(UserRecord *h, UserRecord *secret, PasswordCache *cache, bool strict_verify);
int home_sync_and_statfs(int root_fd, struct statfs *ret);
#define HOME_RUNTIME_WORK_DIR "/run/systemd/user-home-mount"

View File

@ -409,7 +409,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp6_pd_announce = true,
.dhcp6_pd_assign = true,
.dhcp6_pd_manage_temporary_address = true,
.dhcp6_pd_subnet_id = UINT64_MAX,
.dhcp6_pd_subnet_id = -1,
.dhcp6_pd_route_metric = DHCP6PD_ROUTE_METRIC,
.dhcp_server_bind_to_interface = true,

View File

@ -448,29 +448,6 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) {
return 1 << idx;
}
_noreturn_ void freeze(void) {
log_close();
/* Make sure nobody waits for us on a socket anymore */
(void) close_all_fds_full(NULL, 0, false);
sync();
/* Let's not freeze right away, but keep reaping zombies. */
for (;;) {
int r;
siginfo_t si = {};
r = waitid(P_ALL, 0, &si, WEXITED);
if (r < 0 && errno != EINTR)
break;
}
/* waitid() failed with an unexpected error, things are really borked. Freeze now! */
for (;;)
pause();
}
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
#if ENABLE_FEXECVE
execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);

View File

@ -47,8 +47,6 @@ extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
const char* exec_command_flags_to_string(ExecCommandFlags i);
ExecCommandFlags exec_command_flags_from_string(const char *s);
_noreturn_ void freeze(void);
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);
int fork_agent(const char *name, int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) _sentinel_;

View File

@ -995,37 +995,18 @@ int make_mount_point(const char *path) {
}
static int make_userns(uid_t uid_shift, uid_t uid_range) {
char uid_map[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(uid_t) + 1], line[DECIMAL_STR_MAX(uid_t)*3+3+1];
_cleanup_(sigkill_waitp) pid_t pid = 0;
char line[DECIMAL_STR_MAX(uid_t)*3+3+1];
_cleanup_close_ int userns_fd = -1;
int r;
/* Allocates a userns file descriptor with the mapping we need. For this we'll fork off a child
* process whose only purpose is to give us a new user namespace. It's killed when we got it. */
r = safe_fork("(sd-mkuserns)", FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NEW_USERNS, &pid);
if (r < 0)
return r;
if (r == 0)
/* Child. We do nothing here, just freeze until somebody kills us. */
freeze();
xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, uid_shift, uid_range);
xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid);
r = write_string_file(uid_map, line, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_error_errno(r, "Failed to write UID map: %m");
/* We always assign the same UID and GID ranges */
xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid);
r = write_string_file(uid_map, line, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_error_errno(r, "Failed to write GID map: %m");
r = namespace_open(pid, NULL, NULL, NULL, &userns_fd, NULL);
if (r < 0)
return r;
userns_fd = userns_acquire(line, line);
if (userns_fd < 0)
return log_debug_errno(userns_fd, "Failed to acquire new userns: %m");
return TAKE_FD(userns_fd);
}

View File

@ -416,9 +416,10 @@ static int varlink_test_disconnect(Varlink *v) {
if (IN_SET(v->state, VARLINK_IDLE_CLIENT) && (v->write_disconnected || v->got_pollhup))
goto disconnect;
/* The server is still expecting to write more, but its write end is disconnected and it got a POLLHUP
* (i.e. from a disconnected client), so disconnect. */
if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE) && v->write_disconnected && v->got_pollhup)
/* We are on the server side and still want to send out more replies, but we saw POLLHUP already, and
* either got no buffered bytes to write anymore or already saw a write error. In that case we should
* shut down the varlink link. */
if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE) && (v->write_disconnected || v->output_buffer_size == 0) && v->got_pollhup)
goto disconnect;
return 0;

View File

@ -286,6 +286,101 @@ static void test_format_proc_fd_path(void) {
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), "/proc/self/fd/2147483647"));
}
static void test_fd_reopen(void) {
_cleanup_close_ int fd1 = -1, fd2 = -1;
struct stat st1, st2;
int fl;
/* Test this with a directory */
fd1 = open("/proc", O_DIRECTORY|O_PATH|O_CLOEXEC);
assert_se(fd1 >= 0);
assert_se(fstat(fd1, &st1) >= 0);
assert_se(S_ISDIR(st1.st_mode));
fl = fcntl(fd1, F_GETFL);
assert_se(fl >= 0);
assert_se(FLAGS_SET(fl, O_DIRECTORY));
assert_se(FLAGS_SET(fl, O_PATH));
fd2 = fd_reopen(fd1, O_RDONLY|O_DIRECTORY|O_CLOEXEC); /* drop the O_PATH */
assert_se(fd2 >= 0);
assert_se(fstat(fd2, &st2) >= 0);
assert_se(S_ISDIR(st2.st_mode));
assert_se(st1.st_ino == st2.st_ino);
assert_se(st1.st_rdev == st2.st_rdev);
fl = fcntl(fd2, F_GETFL);
assert_se(fl >= 0);
assert_se(FLAGS_SET(fl, O_DIRECTORY));
assert_se(!FLAGS_SET(fl, O_PATH));
safe_close(fd1);
fd1 = fd_reopen(fd2, O_DIRECTORY|O_PATH|O_CLOEXEC); /* reacquire the O_PATH */
assert_se(fd1 >= 0);
assert_se(fstat(fd1, &st1) >= 0);
assert_se(S_ISDIR(st1.st_mode));
assert_se(st1.st_ino == st2.st_ino);
assert_se(st1.st_rdev == st2.st_rdev);
fl = fcntl(fd1, F_GETFL);
assert_se(fl >= 0);
assert_se(FLAGS_SET(fl, O_DIRECTORY));
assert_se(FLAGS_SET(fl, O_PATH));
safe_close(fd1);
/* And now, test this with a file. */
fd1 = open("/proc/version", O_PATH|O_CLOEXEC);
assert_se(fd1 >= 0);
assert_se(fstat(fd1, &st1) >= 0);
assert_se(S_ISREG(st1.st_mode));
fl = fcntl(fd1, F_GETFL);
assert_se(fl >= 0);
assert_se(!FLAGS_SET(fl, O_DIRECTORY));
assert_se(FLAGS_SET(fl, O_PATH));
assert_se(fd_reopen(fd1, O_RDONLY|O_DIRECTORY|O_CLOEXEC) == -ENOTDIR);
fd2 = fd_reopen(fd1, O_RDONLY|O_CLOEXEC); /* drop the O_PATH */
assert_se(fd2 >= 0);
assert_se(fstat(fd2, &st2) >= 0);
assert_se(S_ISREG(st2.st_mode));
assert_se(st1.st_ino == st2.st_ino);
assert_se(st1.st_rdev == st2.st_rdev);
fl = fcntl(fd2, F_GETFL);
assert_se(fl >= 0);
assert_se(!FLAGS_SET(fl, O_DIRECTORY));
assert_se(!FLAGS_SET(fl, O_PATH));
safe_close(fd1);
assert_se(fd_reopen(fd2, O_DIRECTORY|O_PATH|O_CLOEXEC) == -ENOTDIR);
fd1 = fd_reopen(fd2, O_PATH|O_CLOEXEC); /* reacquire the O_PATH */
assert_se(fd1 >= 0);
assert_se(fstat(fd1, &st1) >= 0);
assert_se(S_ISREG(st1.st_mode));
assert_se(st1.st_ino == st2.st_ino);
assert_se(st1.st_rdev == st2.st_rdev);
fl = fcntl(fd1, F_GETFL);
assert_se(fl >= 0);
assert_se(!FLAGS_SET(fl, O_DIRECTORY));
assert_se(FLAGS_SET(fl, O_PATH));
/* Also check the right error is generated if the fd is already closed */
safe_close(fd1);
assert_se(fd_reopen(fd1, O_RDONLY|O_CLOEXEC) == -EBADF);
fd1 = -1;
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@ -299,6 +394,7 @@ int main(int argc, char *argv[]) {
test_read_nr_open();
test_close_all_fds();
test_format_proc_fd_path();
test_fd_reopen();
return 0;
}