From e80c5e5371ab77792bae94e0f8c5e85a4237e6eb Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Mon, 17 Aug 2020 21:43:29 +0200 Subject: [PATCH] New upstream version 246.2 --- man/org.freedesktop.systemd1.xml | 2 +- man/systemd.service.xml | 2 +- src/basic/user-util.c | 31 +++++++++++++++++++++++++++++++ src/basic/user-util.h | 1 + src/boot/bless-boot.c | 1 + src/core/namespace.c | 14 +++++++------- src/shared/seccomp-util.c | 1 + src/shared/user-record-nss.c | 24 ++++++++++++++++++++---- src/shared/user-record.c | 19 +++++++++++++------ src/test/test-fs-util.c | 11 ++++++----- src/test/test-user-util.c | 20 ++++++++++++++++++++ tools/make-man-index.py | 3 ++- 12 files changed, 104 insertions(+), 25 deletions(-) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 6b16ae16d..8a7990ff7 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -8778,7 +8778,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice { Scope Unit Objects - All slice unit objects implement the org.freedesktop.systemd1.Scope + All scope unit objects implement the org.freedesktop.systemd1.Scope interface (described here) in addition to the generic org.freedesktop.systemd1.Unit interface (see above). diff --git a/man/systemd.service.xml b/man/systemd.service.xml index cc13bff75..fbb2987d0 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -217,7 +217,7 @@ this notification message has been sent. If this option is used, NotifyAccess= (see below) should be set to open access to the notification socket provided by systemd. If NotifyAccess= is missing or set to , it will be forcibly set to - . + . Behavior of is very similar to ; however, actual execution of the service program is delayed until all active jobs are dispatched. This may be used diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 8115065b5..0e96a7579 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -863,6 +863,37 @@ bool valid_gecos(const char *d) { return true; } +char *mangle_gecos(const char *d) { + char *mangled; + + /* Makes sure the provided string becomes valid as a GEGOS field, by dropping bad chars. glibc's + * putwent() only changes \n and : to spaces. We do more: replace all CC too, and remove invalid + * UTF-8 */ + + mangled = strdup(d); + if (!mangled) + return NULL; + + for (char *i = mangled; *i; i++) { + int len; + + if ((uint8_t) *i < (uint8_t) ' ' || *i == ':') { + *i = ' '; + continue; + } + + len = utf8_encoded_valid_unichar(i, (size_t) -1); + if (len < 0) { + *i = ' '; + continue; + } + + i += len - 1; + } + + return mangled; +} + bool valid_home(const char *p) { /* Note that this function is also called by valid_shell(), any * changes must account for that. */ diff --git a/src/basic/user-util.h b/src/basic/user-util.h index 1f267d21a..7c142dd1e 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -105,6 +105,7 @@ typedef enum ValidUserFlags { bool valid_user_group_name(const char *u, ValidUserFlags flags); bool valid_gecos(const char *d); +char *mangle_gecos(const char *d); bool valid_home(const char *p); static inline bool valid_shell(const char *p) { diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c index b96e1f927..0824266a8 100644 --- a/src/boot/bless-boot.c +++ b/src/boot/bless-boot.c @@ -34,6 +34,7 @@ static int help(int argc, char *argv[], void *userdata) { printf("%s [OPTIONS...] COMMAND\n" "\n%sMark the boot process as good or bad.%s\n" "\nCommands:\n" + " status Show status of current boot loader entry\n" " good Mark this boot as good\n" " bad Mark this boot as bad\n" " indeterminate Undo any marking as good or bad\n" diff --git a/src/core/namespace.c b/src/core/namespace.c index 36d5ff67a..d30c81088 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1830,11 +1830,11 @@ static int make_tmp_prefix(const char *prefix) { static int make_tmp_subdir(const char *parent, char **ret) { _cleanup_free_ char *y = NULL; - RUN_WITH_UMASK(0000) { - y = strjoin(parent, "/tmp"); - if (!y) - return -ENOMEM; + y = path_join(parent, "/tmp"); + if (!y) + return -ENOMEM; + RUN_WITH_UMASK(0000) { if (mkdir(y, 0777 | S_ISVTX) < 0) return -errno; } @@ -1890,9 +1890,9 @@ static int setup_one_tmp_dir(const char *id, const char *prefix, char **path, ch if (r < 0) return r; - x = strdup(RUN_SYSTEMD_EMPTY); - if (!x) - return -ENOMEM; + r = free_and_strdup(&x, RUN_SYSTEMD_EMPTY); + if (r < 0) + return r; } *path = TAKE_PTR(x); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index a8dd069a7..45bf309bc 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -402,6 +402,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { "close\0" "creat\0" "faccessat\0" + "faccessat2\0" "fallocate\0" "fchdir\0" "fchmod\0" diff --git a/src/shared/user-record-nss.c b/src/shared/user-record-nss.c index f265a2af9..b27a12c55 100644 --- a/src/shared/user-record-nss.c +++ b/src/shared/user-record-nss.c @@ -5,6 +5,7 @@ #include "libcrypt-util.h" #include "strv.h" #include "user-record-nss.h" +#include "user-util.h" #define SET_IF(field, condition, value, fallback) \ field = (condition) ? (value) : (fallback) @@ -34,10 +35,25 @@ int nss_passwd_to_user_record( if (r < 0) return r; - r = free_and_strdup(&hr->real_name, - streq_ptr(pwd->pw_gecos, hr->user_name) ? NULL : empty_to_null(pwd->pw_gecos)); - if (r < 0) - return r; + /* Some bad NSS modules synthesize GECOS fields with embedded ":" or "\n" characters, which are not + * something we can output in /etc/passwd compatible format, since these are record separators + * there. We normally refuse that, but we need to maintain compatibility with arbitrary NSS modules, + * hence let's do what glibc does: mangle the data to fit the format. */ + if (isempty(pwd->pw_gecos) || streq_ptr(pwd->pw_gecos, hr->user_name)) + hr->real_name = mfree(hr->real_name); + else if (valid_gecos(pwd->pw_gecos)) { + r = free_and_strdup(&hr->real_name, pwd->pw_gecos); + if (r < 0) + return r; + } else { + _cleanup_free_ char *mangled = NULL; + + mangled = mangle_gecos(pwd->pw_gecos); + if (!mangled) + return -ENOMEM; + + free_and_replace(hr->real_name, mangled); + } r = free_and_strdup(&hr->home_directory, empty_to_null(pwd->pw_dir)); if (r < 0) diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 16edaa45f..2c0de383e 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -206,7 +206,6 @@ int json_dispatch_realm(const char *name, JsonVariant *variant, JsonDispatchFlag static int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { char **s = userdata; const char *n; - int r; if (json_variant_is_null(variant)) { *s = mfree(*s); @@ -217,12 +216,20 @@ static int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispa return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); n = json_variant_string(variant); - if (!valid_gecos(n)) - return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible real name.", strna(name)); + if (valid_gecos(n)) { + if (free_and_strdup(s, n) < 0) + return json_log_oom(variant, flags); + } else { + _cleanup_free_ char *m = NULL; - r = free_and_strdup(s, n); - if (r < 0) - return json_log(variant, flags, r, "Failed to allocate string: %m"); + json_log(variant, flags|JSON_DEBUG, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible string, mangling.", strna(name)); + + m = mangle_gecos(n); + if (!m) + return json_log_oom(variant, flags); + + free_and_replace(*s, m); + } return 0; } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index dfea70ca2..1ea845dd9 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -850,11 +850,12 @@ static void test_path_is_encrypted_one(const char *p, int expect) { int r; r = path_is_encrypted(p); - if (r == -ENOENT) /* This might fail, if btrfs is used and we run in a container. In that case we - * cannot resolve the device node paths that BTRFS_IOC_DEV_INFO returns, because - * the device nodes are unlikely to exist in the container. But if we can't stat() - * them we cannot determine the dev_t of them, and thus cannot figure out if they - * are enrypted. Hence let's just ignore ENOENT here. */ + if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* This might fail, if btrfs is used and we run in a + * container. In that case we cannot resolve the device node paths that + * BTRFS_IOC_DEV_INFO returns, because the device nodes are unlikely to exist in + * the container. But if we can't stat() them we cannot determine the dev_t of + * them, and thus cannot figure out if they are enrypted. Hence let's just ignore + * ENOENT here. Also skip the test if we lack privileges. */ return; assert_se(r >= 0); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index c9bff941b..306d08a28 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -452,6 +452,25 @@ static void test_parse_uid_range(void) { assert_se(parse_uid_range(" 01", &a, &b) == -EINVAL && a == 4 && b == 5); } +static void test_mangle_gecos_one(const char *input, const char *expected) { + _cleanup_free_ char *p = NULL; + + assert_se(p = mangle_gecos(input)); + assert_se(streq(p, expected)); + assert_se(valid_gecos(p)); +} + +static void test_mangle_gecos(void) { + test_mangle_gecos_one("", ""); + test_mangle_gecos_one("root", "root"); + test_mangle_gecos_one("wuff\nwuff", "wuff wuff"); + test_mangle_gecos_one("wuff:wuff", "wuff wuff"); + test_mangle_gecos_one("wuff\r\n:wuff", "wuff wuff"); + test_mangle_gecos_one("\n--wüff-wäff-wöff::", " --wüff-wäff-wöff "); + test_mangle_gecos_one("\xc3\x28", " ("); + test_mangle_gecos_one("\xe2\x28\xa1", " ( "); +} + int main(int argc, char *argv[]) { test_uid_to_name_one(0, "root"); test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME); @@ -482,6 +501,7 @@ int main(int argc, char *argv[]) { test_valid_user_group_name_or_numeric_relaxed(); test_valid_user_group_name_or_numeric(); test_valid_gecos(); + test_mangle_gecos(); test_valid_home(); test_make_salt(); diff --git a/tools/make-man-index.py b/tools/make-man-index.py index 4d206ca0b..37c708d81 100755 --- a/tools/make-man-index.py +++ b/tools/make-man-index.py @@ -55,7 +55,8 @@ def make_index(pages): check_id(p, t) section = t.find('./refmeta/manvolnum').text refname = t.find('./refnamediv/refname').text - purpose = ' '.join(t.find('./refnamediv/refpurpose').text.split()) + purpose_text = ' '.join(t.find('./refnamediv/refpurpose').itertext()) + purpose = ' '.join(purpose_text.split()) for f in t.findall('./refnamediv/refname'): infos = (f.text, section, purpose, refname) index[f.text[0].upper()].append(infos)