1
0
mirror of https://github.com/systemd/systemd synced 2026-03-16 01:54:45 +01:00

Compare commits

..

No commits in common. "afc5d175a23a4f4a41b1edb92d89bd5ea740901d" and "af718e05350884c0b6a9fa7248e5d2f2564c93f0" have entirely different histories.

6 changed files with 101 additions and 84 deletions

10
TODO
View File

@ -122,14 +122,8 @@ Deprecations and removals:
Features: Features:
* Maybe introducean InodeRef structure inspired by PidRef, which references a * systemd-sysupdate: add support a "best before" in manifests (ie. SHA256SUMS)
specific inode, and combines: a path, an O_PATH fd, and possibly a FID into files, to detect freshness, and refuse stale sources
one. Why? We often pass around path and fd separately in chaseat() and similar
calls. Because passing around both separately is cumbersome we sometimes only
one pass one, once the other and sometimes both. It would make the code a lot
simpler if we could path both around at the same time in a simple way, via an
InodeRef which *both* pins the inode via an fd, *and* gives us a friendly
name for it.
* systemd-sysupdate: for each transfer support looking at multiple sources, * systemd-sysupdate: for each transfer support looking at multiple sources,
pick source with newest entry. If multiple sources have the same entry, use pick source with newest entry. If multiple sources have the same entry, use

View File

@ -1179,19 +1179,15 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn21LG:pvr*
KEYBOARD_KEY_0a=!9 KEYBOARD_KEY_0a=!9
KEYBOARD_KEY_0b=!0 KEYBOARD_KEY_0b=!0
# Lenovo Legion Go Translated # Lenovo Legion Go & Go S
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83E1:* evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83E1:*
# Lenovo Legion Go S Translated
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83L3:* evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83L3:*
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83N6:* evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83N6:*
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83Q2:* evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83Q2:*
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83Q3:* evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83Q3:*
# Lenovo Legion Go 2 Translated
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83N0:*
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83N1:*
KEYBOARD_KEY_67=f16 # Power button long press KEYBOARD_KEY_67=f16 # Power button long press
# Lenovo Legion Go 2 Raw # Lenovo Legion Go 2
evdev:name:AT Raw Set 2 keyboard:dmi:*:svnLENOVO:pn83N0:* evdev:name:AT Raw Set 2 keyboard:dmi:*:svnLENOVO:pn83N0:*
evdev:name:AT Raw Set 2 keyboard:dmi:*:svnLENOVO:pn83N1:* evdev:name:AT Raw Set 2 keyboard:dmi:*:svnLENOVO:pn83N1:*
KEYBOARD_KEY_20=f16 # Power button long press KEYBOARD_KEY_20=f16 # Power button long press

View File

@ -2289,6 +2289,45 @@ static int build_pass_environment(const ExecContext *c, char ***ret) {
return 0; return 0;
} }
static int setup_private_users_child(int unshare_ready_fd, const char *uid_map, const char *gid_map, bool allow_setgroups) {
int r;
/* Child process, running in the original user namespace. Let's update the parent's UID/GID map from
* here, after the parent opened its own user namespace. */
pid_t ppid = getppid();
/* Wait until the parent unshared the user namespace */
uint64_t c;
ssize_t n = read(unshare_ready_fd, &c, sizeof(c));
if (n < 0)
return log_debug_errno(errno, "Failed to read from signaling eventfd: %m");
if (n != sizeof(c))
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Short read from signaling eventfd.");
/* Disable the setgroups() system call in the child user namespace, for good, unless PrivateUsers=full
* and using the system service manager. */
const char *a = procfs_file_alloca(ppid, "setgroups");
const char *setgroups = allow_setgroups ? "allow" : "deny";
r = write_string_file(a, setgroups, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write '%s' to %s: %m", setgroups, a);
/* First write the GID map */
a = procfs_file_alloca(ppid, "gid_map");
r = write_string_file(a, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write GID map to %s: %m", a);
/* Then write the UID map */
a = procfs_file_alloca(ppid, "uid_map");
r = write_string_file(a, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write UID map to %s: %m", a);
return 0;
}
static int bpffs_helper(const ExecContext *c, int socket_fd) { static int bpffs_helper(const ExecContext *c, int socket_fd) {
assert(c); assert(c);
assert(socket_fd >= 0); assert(socket_fd >= 0);
@ -2355,45 +2394,6 @@ static int bpffs_prepare(
return 0; return 0;
} }
static int setup_private_users_child(int unshare_ready_fd, const char *uid_map, const char *gid_map, bool allow_setgroups) {
int r;
/* Child process, running in the original user namespace. Let's update the parent's UID/GID map from
* here, after the parent opened its own user namespace. */
pid_t ppid = getppid();
/* Wait until the parent unshared the user namespace */
uint64_t c;
ssize_t n = read(unshare_ready_fd, &c, sizeof(c));
if (n < 0)
return log_debug_errno(errno, "Failed to read from signaling eventfd: %m");
if (n != sizeof(c))
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Short read from signaling eventfd.");
/* Disable the setgroups() system call in the child user namespace, for good, unless PrivateUsers=full
* and using the system service manager. */
const char *a = procfs_file_alloca(ppid, "setgroups");
const char *setgroups = allow_setgroups ? "allow" : "deny";
r = write_string_file(a, setgroups, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write '%s' to %s: %m", setgroups, a);
/* First write the GID map */
a = procfs_file_alloca(ppid, "gid_map");
r = write_string_file(a, gid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write GID map to %s: %m", a);
/* Then write the UID map */
a = procfs_file_alloca(ppid, "uid_map");
r = write_string_file(a, uid_map, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0)
return log_debug_errno(r, "Failed to write UID map to %s: %m", a);
return 0;
}
static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogid, uid_t uid, gid_t gid, bool allow_setgroups) { static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogid, uid_t uid, gid_t gid, bool allow_setgroups) {
_cleanup_free_ char *uid_map = NULL, *gid_map = NULL; _cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
_cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR; _cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR;
@ -2421,16 +2421,28 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
if (!uid_map) if (!uid_map)
return -ENOMEM; return -ENOMEM;
} else if (private_users == PRIVATE_USERS_FULL) { } else if (private_users == PRIVATE_USERS_FULL) {
/* Map all UID/GID from original to new user namespace. /* Map all UID/GID from original to new user namespace. We can't use `0 0 UINT32_MAX` because
* this is the same UID/GID map as the init user namespace and systemd's running_in_userns()
* checks whether its in a user namespace by comparing uid_map/gid_map to `0 0 UINT32_MAX`.
* Thus, we still map all UIDs/GIDs but do it using two extents to differentiate the new user
* namespace from the init namespace:
* 0 0 1
* 1 1 UINT32_MAX - 1
*
* systemd will remove the heuristic in running_in_userns() and use namespace inodes in version 258
* (PR #35382). But some users may be running a container image with older systemd < 258 so we keep
* this uid_map/gid_map hack until version 259 for version N-1 compatibility.
*
* TODO: Switch to `0 0 UINT32_MAX` in systemd v259.
* *
* Note the kernel defines the UID range between 0 and UINT32_MAX so we map all UIDs even though * Note the kernel defines the UID range between 0 and UINT32_MAX so we map all UIDs even though
* the UID range beyond INT32_MAX (e.g. i.e. the range above the signed 32-bit range) is * the UID range beyond INT32_MAX (e.g. i.e. the range above the signed 32-bit range) is
* icky. For example, setfsuid() returns the old UID as signed integer. But units can decide to * icky. For example, setfsuid() returns the old UID as signed integer. But units can decide to
* use these UIDs/GIDs so we need to map them. */ * use these UIDs/GIDs so we need to map them. */
r = asprintf(&uid_map, "0 0 " UID_FMT "\n", (uid_t) UINT32_MAX); r = asprintf(&uid_map, "0 0 1\n"
"1 1 " UID_FMT "\n", (uid_t) (UINT32_MAX - 1));
if (r < 0) if (r < 0)
return -ENOMEM; return -ENOMEM;
/* Can only set up multiple mappings with CAP_SETUID. */ /* Can only set up multiple mappings with CAP_SETUID. */
} else if (have_effective_cap(CAP_SETUID) > 0 && uid != ouid && uid_is_valid(uid)) { } else if (have_effective_cap(CAP_SETUID) > 0 && uid != ouid && uid_is_valid(uid)) {
r = asprintf(&uid_map, r = asprintf(&uid_map,
@ -2452,10 +2464,10 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
if (!gid_map) if (!gid_map)
return -ENOMEM; return -ENOMEM;
} else if (private_users == PRIVATE_USERS_FULL) { } else if (private_users == PRIVATE_USERS_FULL) {
r = asprintf(&gid_map, "0 0 " GID_FMT "\n", (gid_t) UINT32_MAX); r = asprintf(&gid_map, "0 0 1\n"
"1 1 " GID_FMT "\n", (gid_t) (UINT32_MAX - 1));
if (r < 0) if (r < 0)
return -ENOMEM; return -ENOMEM;
/* Can only set up multiple mappings with CAP_SETGID. */ /* Can only set up multiple mappings with CAP_SETGID. */
} else if (have_effective_cap(CAP_SETGID) > 0 && gid != ogid && gid_is_valid(gid)) { } else if (have_effective_cap(CAP_SETGID) > 0 && gid != ogid && gid_is_valid(gid)) {
r = asprintf(&gid_map, r = asprintf(&gid_map,

View File

@ -71,12 +71,12 @@ typedef enum {
/* Read from /etc/os-release (or /usr/lib/os-release) */ /* Read from /etc/os-release (or /usr/lib/os-release) */
PROP_OS_PRETTY_NAME, PROP_OS_PRETTY_NAME,
PROP_OS_FANCY_NAME,
PROP_OS_CPE_NAME, PROP_OS_CPE_NAME,
PROP_OS_HOME_URL, PROP_OS_HOME_URL,
PROP_OS_SUPPORT_END, PROP_OS_SUPPORT_END,
PROP_OS_IMAGE_ID, PROP_OS_IMAGE_ID,
PROP_OS_IMAGE_VERSION, PROP_OS_IMAGE_VERSION,
PROP_OS_FANCY_NAME,
_PROP_MAX, _PROP_MAX,
_PROP_INVALID = -EINVAL, _PROP_INVALID = -EINVAL,
} HostProperty; } HostProperty;
@ -110,9 +110,6 @@ static void context_reset(Context *c, uint64_t mask) {
} }
} }
#define context_reset_many(c, ...) \
context_reset((c), INDEXES_TO_MASK(uint64_t, __VA_ARGS__))
static void context_destroy(Context *c) { static void context_destroy(Context *c) {
assert(c); assert(c);
@ -136,8 +133,9 @@ static void context_read_etc_hostname(Context *c) {
stat_inode_unmodified(&c->etc_hostname_stat, &current_stat)) stat_inode_unmodified(&c->etc_hostname_stat, &current_stat))
return; return;
context_reset_many(c, PROP_STATIC_HOSTNAME, context_reset(c,
PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS); (UINT64_C(1) << PROP_STATIC_HOSTNAME) |
(UINT64_C(1) << PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS));
r = read_etc_hostname(/* path= */ NULL, /* substitute_wildcards= */ false, &c->data[PROP_STATIC_HOSTNAME]); r = read_etc_hostname(/* path= */ NULL, /* substitute_wildcards= */ false, &c->data[PROP_STATIC_HOSTNAME]);
if (r < 0) { if (r < 0) {
@ -168,15 +166,16 @@ static void context_read_machine_info(Context *c) {
stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat)) stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat))
return; return;
context_reset_many(c, PROP_PRETTY_HOSTNAME, context_reset(c,
PROP_ICON_NAME, (UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
PROP_CHASSIS, (UINT64_C(1) << PROP_ICON_NAME) |
PROP_DEPLOYMENT, (UINT64_C(1) << PROP_CHASSIS) |
PROP_LOCATION, (UINT64_C(1) << PROP_DEPLOYMENT) |
PROP_HARDWARE_VENDOR, (UINT64_C(1) << PROP_LOCATION) |
PROP_HARDWARE_MODEL, (UINT64_C(1) << PROP_HARDWARE_VENDOR) |
PROP_HARDWARE_SKU, (UINT64_C(1) << PROP_HARDWARE_MODEL) |
PROP_HARDWARE_VERSION); (UINT64_C(1) << PROP_HARDWARE_SKU) |
(UINT64_C(1) << PROP_HARDWARE_VERSION));
r = parse_env_file(NULL, etc_machine_info(), r = parse_env_file(NULL, etc_machine_info(),
"PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME], "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
@ -206,13 +205,14 @@ static void context_read_os_release(Context *c) {
stat_inode_unmodified(&c->etc_os_release_stat, &current_stat)) stat_inode_unmodified(&c->etc_os_release_stat, &current_stat))
return; return;
context_reset_many(c, PROP_OS_PRETTY_NAME, context_reset(c,
PROP_OS_FANCY_NAME, (UINT64_C(1) << PROP_OS_PRETTY_NAME) |
PROP_OS_CPE_NAME, (UINT64_C(1) << PROP_OS_CPE_NAME) |
PROP_OS_HOME_URL, (UINT64_C(1) << PROP_OS_HOME_URL) |
PROP_OS_SUPPORT_END, (UINT64_C(1) << PROP_OS_SUPPORT_END) |
PROP_OS_IMAGE_ID, (UINT64_C(1) << PROP_OS_IMAGE_ID) |
PROP_OS_IMAGE_VERSION); (UINT64_C(1) << PROP_OS_IMAGE_VERSION) |
(UINT64_C(1) << PROP_OS_FANCY_NAME));
r = parse_os_release(NULL, r = parse_os_release(NULL,
"PRETTY_NAME", &os_pretty_name, "PRETTY_NAME", &os_pretty_name,

View File

@ -1107,6 +1107,7 @@ static int register_session(
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; /* the following variables point into this message, hence pin it for longer */ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; /* the following variables point into this message, hence pin it for longer */
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; /* similar */ _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; /* similar */
const char *id = NULL, *object_path = NULL, *runtime_path = NULL, *real_seat = NULL; const char *id = NULL, *object_path = NULL, *runtime_path = NULL, *real_seat = NULL;
int existing = false;
uint32_t original_uid = UID_INVALID, real_vtnr = 0; uint32_t original_uid = UID_INVALID, real_vtnr = 0;
bool done = false; bool done = false;
@ -1168,6 +1169,7 @@ static int register_session(
uid_t uid; uid_t uid;
const char *seat; const char *seat;
unsigned vtnr; unsigned vtnr;
bool existing;
} p = { } p = {
.uid = UID_INVALID, .uid = UID_INVALID,
}; };
@ -1190,6 +1192,7 @@ static int register_session(
original_uid = p.uid; original_uid = p.uid;
real_seat = p.seat; real_seat = p.seat;
real_vtnr = p.vtnr; real_vtnr = p.vtnr;
existing = false; /* Even on D-Bus logind only returns false these days */
done = true; done = true;
} }
@ -1263,7 +1266,7 @@ static int register_session(
&original_uid, &original_uid,
&real_seat, &real_seat,
&real_vtnr, &real_vtnr,
/* existing = */ NULL); /* deprecated in b80120c4cba7d134b5437a58437a23fdf7ab2084 */ &existing);
if (r < 0) if (r < 0)
return pam_bus_log_parse_error(pamh, r); return pam_bus_log_parse_error(pamh, r);
@ -1328,6 +1331,10 @@ static int register_session(
return r; return r;
} }
r = pam_set_data(pamh, "systemd.existing", INT_TO_PTR(!!existing), NULL);
if (r != PAM_SUCCESS)
return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to install existing flag: @PAMERR@");
/* Don't set $XDG_RUNTIME_DIR if the user we now authenticated for does not match the /* Don't set $XDG_RUNTIME_DIR if the user we now authenticated for does not match the
* original user of the session. We do this in order not to result in privileged apps * original user of the session. We do this in order not to result in privileged apps
* clobbering the runtime directory unnecessarily. */ * clobbering the runtime directory unnecessarily. */
@ -1822,6 +1829,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
int flags, int flags,
int argc, const char **argv) { int argc, const char **argv) {
const void *existing = NULL;
bool debug = false; bool debug = false;
const char *id; const char *id;
int r; int r;
@ -1843,10 +1851,17 @@ _public_ PAM_EXTERN int pam_sm_close_session(
pam_debug_syslog(pamh, debug, "pam-systemd: shutting down..."); pam_debug_syslog(pamh, debug, "pam-systemd: shutting down...");
/* Only release session if it wasn't pre-existing when we
* tried to create it */
r = pam_get_data(pamh, "systemd.existing", &existing);
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
return pam_syslog_pam_error(pamh, LOG_ERR, r,
"Failed to get PAM systemd.existing data: @PAMERR@");
(void) close_osc_context(pamh, debug); (void) close_osc_context(pamh, debug);
id = pam_getenv(pamh, "XDG_SESSION_ID"); id = pam_getenv(pamh, "XDG_SESSION_ID");
if (id) { if (id && !existing) {
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL; _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
bool done = false; bool done = false;

View File

@ -12,6 +12,6 @@ systemd-run -p PrivateUsersEx=self --wait bash -c 'test "$(cat /proc/self/gid_ma
systemd-run -p PrivateUsersEx=self --wait bash -c 'test "$(cat /proc/self/setgroups)" == "deny"' systemd-run -p PrivateUsersEx=self --wait bash -c 'test "$(cat /proc/self/setgroups)" == "deny"'
systemd-run -p PrivateUsersEx=identity --wait bash -c 'test "$(cat /proc/self/uid_map)" == " 0 0 65536"' systemd-run -p PrivateUsersEx=identity --wait bash -c 'test "$(cat /proc/self/uid_map)" == " 0 0 65536"'
systemd-run -p PrivateUsersEx=identity --wait bash -c 'test "$(cat /proc/self/gid_map)" == " 0 0 65536"' systemd-run -p PrivateUsersEx=identity --wait bash -c 'test "$(cat /proc/self/gid_map)" == " 0 0 65536"'
systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/uid_map)" == " 0 0 4294967295"' systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/uid_map | tr -d "\n")" == " 0 0 1 1 1 4294967294"'
systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/gid_map)" == " 0 0 4294967295"' systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/gid_map | tr -d "\n")" == " 0 0 1 1 1 4294967294"'
systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/setgroups)" == "allow"' systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/setgroups)" == "allow"'