mirror of
https://github.com/systemd/systemd
synced 2026-03-31 20:24:50 +02:00
Compare commits
17 Commits
e0e914eaf8
...
a07ab1dd8c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a07ab1dd8c | ||
|
|
e6cab77eca | ||
|
|
784c249f41 | ||
|
|
7afef7ed14 | ||
|
|
a5bf435ed7 | ||
|
|
a972ab0f25 | ||
|
|
43cac49092 | ||
|
|
979b0ff2c4 | ||
|
|
8ddefb8eef | ||
|
|
7cb791bcac | ||
|
|
baa41cee77 | ||
|
|
498abadb8c | ||
|
|
197aec7e79 | ||
|
|
7c26a631ad | ||
|
|
61fb966ccc | ||
|
|
d6274e6b8f | ||
|
|
b4f73d1e17 |
14
TODO
14
TODO
@ -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
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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++)
|
||||
|
||||
@ -222,6 +222,7 @@ _noreturn_ static void freeze_or_exit_or_reboot(void) {
|
||||
}
|
||||
|
||||
log_emergency("Freezing execution.");
|
||||
sync();
|
||||
freeze();
|
||||
}
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user