mirror of
https://github.com/systemd/systemd
synced 2026-03-16 01:54:45 +01:00
Compare commits
8 Commits
af718e0535
...
afc5d175a2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afc5d175a2 | ||
|
|
89e94f6369 | ||
|
|
24c73c7920 | ||
|
|
6ed05d6414 | ||
|
|
cf54b1ea57 | ||
|
|
a68c8d9ac2 | ||
|
|
2a2b5f8091 | ||
|
|
5d2e9c2ad0 |
10
TODO
10
TODO
@ -122,8 +122,14 @@ Deprecations and removals:
|
||||
|
||||
Features:
|
||||
|
||||
* systemd-sysupdate: add support a "best before" in manifests (ie. SHA256SUMS)
|
||||
files, to detect freshness, and refuse stale sources
|
||||
* Maybe introducean InodeRef structure inspired by PidRef, which references a
|
||||
specific inode, and combines: a path, an O_PATH fd, and possibly a FID into
|
||||
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,
|
||||
pick source with newest entry. If multiple sources have the same entry, use
|
||||
|
||||
@ -1179,15 +1179,19 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO:pn21LG:pvr*
|
||||
KEYBOARD_KEY_0a=!9
|
||||
KEYBOARD_KEY_0b=!0
|
||||
|
||||
# Lenovo Legion Go & Go S
|
||||
# Lenovo Legion Go Translated
|
||||
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:pn83N6:*
|
||||
evdev:name:AT Translated Set 2 keyboard:dmi:*:svnLENOVO:pn83Q2:*
|
||||
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
|
||||
|
||||
# Lenovo Legion Go 2
|
||||
# Lenovo Legion Go 2 Raw
|
||||
evdev:name:AT Raw Set 2 keyboard:dmi:*:svnLENOVO:pn83N0:*
|
||||
evdev:name:AT Raw Set 2 keyboard:dmi:*:svnLENOVO:pn83N1:*
|
||||
KEYBOARD_KEY_20=f16 # Power button long press
|
||||
|
||||
@ -2289,45 +2289,6 @@ static int build_pass_environment(const ExecContext *c, char ***ret) {
|
||||
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) {
|
||||
assert(c);
|
||||
assert(socket_fd >= 0);
|
||||
@ -2394,6 +2355,45 @@ static int bpffs_prepare(
|
||||
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) {
|
||||
_cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
|
||||
_cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR;
|
||||
@ -2421,28 +2421,16 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
|
||||
if (!uid_map)
|
||||
return -ENOMEM;
|
||||
} else if (private_users == PRIVATE_USERS_FULL) {
|
||||
/* 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.
|
||||
/* Map all UID/GID from original to new user namespace.
|
||||
*
|
||||
* 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
|
||||
* 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. */
|
||||
r = asprintf(&uid_map, "0 0 1\n"
|
||||
"1 1 " UID_FMT "\n", (uid_t) (UINT32_MAX - 1));
|
||||
r = asprintf(&uid_map, "0 0 " UID_FMT "\n", (uid_t) UINT32_MAX);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Can only set up multiple mappings with CAP_SETUID. */
|
||||
} else if (have_effective_cap(CAP_SETUID) > 0 && uid != ouid && uid_is_valid(uid)) {
|
||||
r = asprintf(&uid_map,
|
||||
@ -2464,10 +2452,10 @@ static int setup_private_users(PrivateUsers private_users, uid_t ouid, gid_t ogi
|
||||
if (!gid_map)
|
||||
return -ENOMEM;
|
||||
} else if (private_users == PRIVATE_USERS_FULL) {
|
||||
r = asprintf(&gid_map, "0 0 1\n"
|
||||
"1 1 " GID_FMT "\n", (gid_t) (UINT32_MAX - 1));
|
||||
r = asprintf(&gid_map, "0 0 " GID_FMT "\n", (gid_t) UINT32_MAX);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Can only set up multiple mappings with CAP_SETGID. */
|
||||
} else if (have_effective_cap(CAP_SETGID) > 0 && gid != ogid && gid_is_valid(gid)) {
|
||||
r = asprintf(&gid_map,
|
||||
|
||||
@ -71,12 +71,12 @@ typedef enum {
|
||||
|
||||
/* Read from /etc/os-release (or /usr/lib/os-release) */
|
||||
PROP_OS_PRETTY_NAME,
|
||||
PROP_OS_FANCY_NAME,
|
||||
PROP_OS_CPE_NAME,
|
||||
PROP_OS_HOME_URL,
|
||||
PROP_OS_SUPPORT_END,
|
||||
PROP_OS_IMAGE_ID,
|
||||
PROP_OS_IMAGE_VERSION,
|
||||
PROP_OS_FANCY_NAME,
|
||||
_PROP_MAX,
|
||||
_PROP_INVALID = -EINVAL,
|
||||
} HostProperty;
|
||||
@ -110,6 +110,9 @@ 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) {
|
||||
assert(c);
|
||||
|
||||
@ -133,9 +136,8 @@ static void context_read_etc_hostname(Context *c) {
|
||||
stat_inode_unmodified(&c->etc_hostname_stat, ¤t_stat))
|
||||
return;
|
||||
|
||||
context_reset(c,
|
||||
(UINT64_C(1) << PROP_STATIC_HOSTNAME) |
|
||||
(UINT64_C(1) << PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS));
|
||||
context_reset_many(c, PROP_STATIC_HOSTNAME,
|
||||
PROP_STATIC_HOSTNAME_SUBSTITUTED_WILDCARDS);
|
||||
|
||||
r = read_etc_hostname(/* path= */ NULL, /* substitute_wildcards= */ false, &c->data[PROP_STATIC_HOSTNAME]);
|
||||
if (r < 0) {
|
||||
@ -166,16 +168,15 @@ static void context_read_machine_info(Context *c) {
|
||||
stat_inode_unmodified(&c->etc_machine_info_stat, ¤t_stat))
|
||||
return;
|
||||
|
||||
context_reset(c,
|
||||
(UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
|
||||
(UINT64_C(1) << PROP_ICON_NAME) |
|
||||
(UINT64_C(1) << PROP_CHASSIS) |
|
||||
(UINT64_C(1) << PROP_DEPLOYMENT) |
|
||||
(UINT64_C(1) << PROP_LOCATION) |
|
||||
(UINT64_C(1) << PROP_HARDWARE_VENDOR) |
|
||||
(UINT64_C(1) << PROP_HARDWARE_MODEL) |
|
||||
(UINT64_C(1) << PROP_HARDWARE_SKU) |
|
||||
(UINT64_C(1) << PROP_HARDWARE_VERSION));
|
||||
context_reset_many(c, PROP_PRETTY_HOSTNAME,
|
||||
PROP_ICON_NAME,
|
||||
PROP_CHASSIS,
|
||||
PROP_DEPLOYMENT,
|
||||
PROP_LOCATION,
|
||||
PROP_HARDWARE_VENDOR,
|
||||
PROP_HARDWARE_MODEL,
|
||||
PROP_HARDWARE_SKU,
|
||||
PROP_HARDWARE_VERSION);
|
||||
|
||||
r = parse_env_file(NULL, etc_machine_info(),
|
||||
"PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
|
||||
@ -205,14 +206,13 @@ static void context_read_os_release(Context *c) {
|
||||
stat_inode_unmodified(&c->etc_os_release_stat, ¤t_stat))
|
||||
return;
|
||||
|
||||
context_reset(c,
|
||||
(UINT64_C(1) << PROP_OS_PRETTY_NAME) |
|
||||
(UINT64_C(1) << PROP_OS_CPE_NAME) |
|
||||
(UINT64_C(1) << PROP_OS_HOME_URL) |
|
||||
(UINT64_C(1) << PROP_OS_SUPPORT_END) |
|
||||
(UINT64_C(1) << PROP_OS_IMAGE_ID) |
|
||||
(UINT64_C(1) << PROP_OS_IMAGE_VERSION) |
|
||||
(UINT64_C(1) << PROP_OS_FANCY_NAME));
|
||||
context_reset_many(c, PROP_OS_PRETTY_NAME,
|
||||
PROP_OS_FANCY_NAME,
|
||||
PROP_OS_CPE_NAME,
|
||||
PROP_OS_HOME_URL,
|
||||
PROP_OS_SUPPORT_END,
|
||||
PROP_OS_IMAGE_ID,
|
||||
PROP_OS_IMAGE_VERSION);
|
||||
|
||||
r = parse_os_release(NULL,
|
||||
"PRETTY_NAME", &os_pretty_name,
|
||||
|
||||
@ -1107,7 +1107,6 @@ 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_varlink_unrefp) sd_varlink *vl = NULL; /* similar */
|
||||
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;
|
||||
|
||||
bool done = false;
|
||||
@ -1169,7 +1168,6 @@ static int register_session(
|
||||
uid_t uid;
|
||||
const char *seat;
|
||||
unsigned vtnr;
|
||||
bool existing;
|
||||
} p = {
|
||||
.uid = UID_INVALID,
|
||||
};
|
||||
@ -1192,7 +1190,6 @@ static int register_session(
|
||||
original_uid = p.uid;
|
||||
real_seat = p.seat;
|
||||
real_vtnr = p.vtnr;
|
||||
existing = false; /* Even on D-Bus logind only returns false these days */
|
||||
|
||||
done = true;
|
||||
}
|
||||
@ -1266,7 +1263,7 @@ static int register_session(
|
||||
&original_uid,
|
||||
&real_seat,
|
||||
&real_vtnr,
|
||||
&existing);
|
||||
/* existing = */ NULL); /* deprecated in b80120c4cba7d134b5437a58437a23fdf7ab2084 */
|
||||
if (r < 0)
|
||||
return pam_bus_log_parse_error(pamh, r);
|
||||
|
||||
@ -1331,10 +1328,6 @@ static int register_session(
|
||||
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
|
||||
* original user of the session. We do this in order not to result in privileged apps
|
||||
* clobbering the runtime directory unnecessarily. */
|
||||
@ -1829,7 +1822,6 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
int flags,
|
||||
int argc, const char **argv) {
|
||||
|
||||
const void *existing = NULL;
|
||||
bool debug = false;
|
||||
const char *id;
|
||||
int r;
|
||||
@ -1851,17 +1843,10 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
|
||||
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);
|
||||
|
||||
id = pam_getenv(pamh, "XDG_SESSION_ID");
|
||||
if (id && !existing) {
|
||||
if (id) {
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
bool done = false;
|
||||
|
||||
|
||||
@ -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=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=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 | tr -d "\n")" == " 0 0 1 1 1 4294967294"'
|
||||
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/gid_map)" == " 0 0 4294967295"'
|
||||
systemd-run -p PrivateUsersEx=full --wait bash -c 'test "$(cat /proc/self/setgroups)" == "allow"'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user