CVE-2020-13776

This commit is contained in:
yangmingtaip 2022-02-16 11:53:41 +08:00
parent 54e8778bc2
commit 9c9e3cf238
16 changed files with 2159 additions and 1 deletions

View File

@ -0,0 +1,105 @@
From 93c23c9297e48e594785e0bb9c51504aae5fbe3e Mon Sep 17 00:00:00 2001
From: Balint Reczey <balint.reczey@canonical.com>
Date: Wed, 18 Mar 2020 18:29:02 +0100
Subject: [PATCH] user-util: Allow names starting with a digit
In 1a29610f5fa1bcb2eeb37d2c6b79d8d1a6dbb865 the change inadvertedly
disabled names with digit as the first character. This follow-up change
allows a digit as the first character in compat mode.
Fixes: #15141
Reference: https://github.com/systemd/systemd/commit/93c23c9297e48e594785e0bb9c51504aae5fbe3e
Conflict: NA
---
src/basic/user-util.c | 20 +++++++++++++++++---
src/test/test-user-util.c | 4 ++--
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index a491f5505e..e998a46e72 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -701,16 +701,18 @@ int take_etc_passwd_lock(const char *root) {
bool valid_user_group_name_full(const char *u, bool strict) {
const char *i;
long sz;
+ bool warned = false;
/* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
* 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
*
* - We require that names fit into the appropriate utmp field
* - We don't allow empty user names
- * - No dots or digits in the first character
+ * - No dots in the first character
*
* If strict==true, additionally:
* - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
+ * - We don't allow a digit as the first character
*
* Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
*/
@@ -720,17 +722,26 @@ bool valid_user_group_name_full(const char *u, bool strict) {
if (!(u[0] >= 'a' && u[0] <= 'z') &&
!(u[0] >= 'A' && u[0] <= 'Z') &&
+ !(u[0] >= '0' && u[0] <= '9' && !strict) &&
u[0] != '_')
return false;
- bool warned = false;
+ bool only_digits_seen = u[0] >= '0' && u[0] <= '9';
+
+ if (only_digits_seen) {
+ log_warning("User or group name \"%s\" starts with a digit, accepting for compatibility.", u);
+ warned = true;
+ }
for (i = u+1; *i; i++) {
if (((*i >= 'a' && *i <= 'z') ||
(*i >= 'A' && *i <= 'Z') ||
(*i >= '0' && *i <= '9') ||
- IN_SET(*i, '_', '-')))
+ IN_SET(*i, '_', '-'))) {
+ if (!(*i >= '0' && *i <= '9'))
+ only_digits_seen = false;
continue;
+ }
if (*i == '.' && !strict) {
if (!warned) {
@@ -744,6 +755,9 @@ bool valid_user_group_name_full(const char *u, bool strict) {
return false;
}
+ if (only_digits_seen)
+ return false;
+
sz = sysconf(_SC_LOGIN_NAME_MAX);
assert_se(sz > 0);
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index 084a584876..11c01e5189 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -96,7 +96,7 @@ static void test_valid_user_group_name_compat(void) {
assert_se(valid_user_group_name_compat("eff."));
assert_se(valid_user_group_name_compat("some5"));
- assert_se(!valid_user_group_name_compat("5some"));
+ assert_se(valid_user_group_name_compat("5some"));
assert_se(valid_user_group_name_compat("INNER5NUMBER"));
}
@@ -166,7 +166,7 @@ static void test_valid_user_group_name_or_id_compat(void) {
assert_se(valid_user_group_name_or_id_compat("kk-k"));
assert_se(valid_user_group_name_or_id_compat("some5"));
- assert_se(!valid_user_group_name_or_id_compat("5some"));
+ assert_se(valid_user_group_name_or_id_compat("5some"));
assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
}
--
2.23.0

View File

@ -0,0 +1,39 @@
From a85daa0dfb3eb03be9845760e90e54b9af8fb00e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 30 Mar 2020 21:46:01 +0200
Subject: [PATCH] user-util: switch order of checks in
valid_user_group_name_or_id_full()
When we are supposed to accept numeric UIDs formatted as string, then
let's check that first, before passing things on to
valid_user_group_name_full(), since that might log about, and not the
other way round.
See: #15201
Follow-up for: 93c23c9297e48e594785e0bb9c51504aae5fbe3e
Reference: https://github.com/systemd/systemd/commit/a85daa0dfb3eb03be9845760e90e54b9af8fb00e
Conflict: NA
---
src/basic/user-util.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index e998a46e72..1510fc96ef 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -778,10 +778,10 @@ bool valid_user_group_name_or_id_full(const char *u, bool strict) {
if (isempty(u))
return false;
- if (valid_user_group_name_full(u, strict))
+ if (parse_uid(u, NULL) >= 0)
return true;
- return parse_uid(u, NULL) >= 0;
+ return valid_user_group_name_full(u, strict);
}
bool valid_gecos(const char *d) {
--
2.23.0

View File

@ -0,0 +1,793 @@
From 7a8867abfab10e5bbca10590ec2aa40c5b27d8fb Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Sat, 4 Apr 2020 12:23:02 +0200
Subject: [PATCH] user-util: rework how we validate user names
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reworks the user validation infrastructure. There are now two
modes. In regular mode we are strict and test against a strict set of
valid chars. And in "relaxed" mode we just filter out some really
obvious, dangerous stuff. i.e. strict is whitelisting what is OK, but
"relaxed" is blacklisting what is really not OK.
The idea is that we use strict mode whenver we allocate a new user
(i.e. in sysusers.d or homed), while "relaxed" mode is when we process
users registered elsewhere, (i.e. userdb, logind, …)
The requirements on user name validity vary wildly. SSSD thinks its fine
to embedd "@" for example, while the suggested NAME_REGEX field on
Debian does not even allow uppercase chars…
This effectively liberaralizes a lot what we expect from usernames.
The code that warns about questionnable user names is now optional and
only used at places such as unit file parsing, so that it doesn't show
up on every userdb query, but only when processing configuration files
that know better.
Fixes: #15149 #15090
Reference: https://github.com/systemd/systemd/commit/7a8867abfab10e5bbca10590ec2aa40c5b27d8fb
Conflict: Remove unneeded file and change the context.
---
src/basic/user-util.c | 185 +++++++++++++----------
src/basic/user-util.h | 21 +--
src/core/dbus-execute.c | 6 +-
src/core/dbus-manager.c | 2 +-
src/core/dbus-socket.c | 4 +-
src/core/dbus-util.c | 7 +-
src/core/dbus-util.h | 2 +-
src/core/dynamic-user.c | 2 +-
src/core/load-fragment.c | 4 +-
src/core/unit.c | 2 +-
src/nss-systemd/nss-systemd.c | 6 +-
src/systemd/sd-messages.h | 3 +
src/sysusers/sysusers.c | 4 +-
src/test/test-user-util.c | 271 ++++++++++++++++++----------------
14 files changed, 287 insertions(+), 232 deletions(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 1510fc96ef..2e3580017d 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -10,6 +10,8 @@
#include <unistd.h>
#include <utmp.h>
+#include "sd-messages.h"
+
#include "alloc-util.h"
#include "errno-util.h"
#include "fd-util.h"
@@ -698,90 +701,123 @@ int take_etc_passwd_lock(const char *root) {
return fd;
}
-bool valid_user_group_name_full(const char *u, bool strict) {
+bool valid_user_group_name(const char *u, ValidUserFlags flags) {
const char *i;
- long sz;
- bool warned = false;
- /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
- * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
- *
- * - We require that names fit into the appropriate utmp field
- * - We don't allow empty user names
- * - No dots in the first character
- *
- * If strict==true, additionally:
- * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
- * - We don't allow a digit as the first character
+ /* Checks if the specified name is a valid user/group name. There are two flavours of this call:
+ * strict mode is the default which is POSIX plus some extra rules; and relaxed mode where we accept
+ * pretty much everything except the really worst offending names.
*
- * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
- */
+ * Whenever we synthesize users ourselves we should use the strict mode. But when we process users
+ * created by other stuff, let's be more liberal. */
- if (isempty(u))
+ if (isempty(u)) /* An empty user name is never valid */
return false;
- if (!(u[0] >= 'a' && u[0] <= 'z') &&
- !(u[0] >= 'A' && u[0] <= 'Z') &&
- !(u[0] >= '0' && u[0] <= '9' && !strict) &&
- u[0] != '_')
- return false;
-
- bool only_digits_seen = u[0] >= '0' && u[0] <= '9';
+ if (parse_uid(u, NULL) >= 0) /* Something that parses as numeric UID string is valid exactly when the
+ * flag for it is set */
+ return FLAGS_SET(flags, VALID_USER_ALLOW_NUMERIC);
+
+ if (FLAGS_SET(flags, VALID_USER_RELAX)) {
+
+ /* In relaxed mode we just check very superficially. Apparently SSSD and other stuff is
+ * extremely liberal (way too liberal if you ask me, even inserting "@" in user names, which
+ * is bound to cause problems for example when used with an MTA), hence only filter the most
+ * obvious cases, or where things would result in an invalid entry if such a user name would
+ * show up in /etc/passwd (or equivalent getent output).
+ *
+ * Note that we stepped far out of POSIX territory here. It's not our fault though, but
+ * SSSD's, Samba's and everybody else who ignored POSIX on this. (I mean, I am happy to step
+ * outside of POSIX' bounds any day, but I must say in this case I probably wouldn't
+ * have...) */
+
+ if (startswith(u, " ") || endswith(u, " ")) /* At least expect whitespace padding is removed
+ * at front and back (accept in the middle, since
+ * that's apparently a thing on Windows). Note
+ * that this also blocks usernames consisting of
+ * whitespace only. */
+ return false;
- if (only_digits_seen) {
- log_warning("User or group name \"%s\" starts with a digit, accepting for compatibility.", u);
- warned = true;
- }
+ if (!utf8_is_valid(u)) /* We want to synthesize JSON from this, hence insist on UTF-8 */
+ return false;
- for (i = u+1; *i; i++) {
- if (((*i >= 'a' && *i <= 'z') ||
- (*i >= 'A' && *i <= 'Z') ||
- (*i >= '0' && *i <= '9') ||
- IN_SET(*i, '_', '-'))) {
- if (!(*i >= '0' && *i <= '9'))
- only_digits_seen = false;
- continue;
- }
-
- if (*i == '.' && !strict) {
- if (!warned) {
- log_warning("Bad user or group name \"%s\", accepting for compatibility.", u);
- warned = true;
- }
-
- continue;
- }
+ if (string_has_cc(u, NULL)) /* CC characters are just dangerous (and \n in particular is the
+ * record separator in /etc/passwd), so we can't allow that. */
+ return false;
- return false;
- }
+ if (strpbrk(u, ":/")) /* Colons are the field separator in /etc/passwd, we can't allow
+ * that. Slashes are special to file systems paths and user names
+ * typically show up in the file system as home directories, hence
+ * don't allow slashes. */
+ return false;
- if (only_digits_seen)
- return false;
+ if (in_charset(u, "0123456789")) /* Don't allow fully numeric strings, they might be confused
+ * with with UIDs (note that this test is more broad than
+ * the parse_uid() test above, as it will cover more than
+ * the 32bit range, and it will detect 65535 (which is in
+ * invalid UID, even though in the unsigned 32 bit range) */
+ return false;
- sz = sysconf(_SC_LOGIN_NAME_MAX);
- assert_se(sz > 0);
+ if (u[0] == '-' && in_charset(u + 1, "0123456789")) /* Don't allow negative fully numeric
+ * strings either. After all some people
+ * write 65535 as -1 (even though that's
+ * not even true on 32bit uid_t
+ * anyway) */
+ return false;
- if ((size_t) (i-u) > (size_t) sz)
- return false;
+ if (dot_or_dot_dot(u)) /* User names typically become home directory names, and these two are
+ * special in that context, don't allow that. */
+ return false;
- if ((size_t) (i-u) > UT_NAMESIZE - 1)
- return false;
+ /* Compare with strict result and warn if result doesn't match */
+ if (FLAGS_SET(flags, VALID_USER_WARN) && !valid_user_group_name(u, 0))
+ log_struct(LOG_NOTICE,
+ "MESSAGE=Accepting user/group name '%s', which does not match strict user/group name rules.", u,
+ "USER_GROUP_NAME=%s", u,
+ "MESSAGE_ID=" SD_MESSAGE_UNSAFE_USER_NAME_STR);
- return true;
-}
+ /* Note that we make no restrictions on the length in relaxed mode! */
+ } else {
+ long sz;
+ size_t l;
+
+ /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.437. We are a bit stricter here
+ * however. Specifically we deviate from POSIX rules:
+ *
+ * - We don't allow empty user names (see above)
+ * - We require that names fit into the appropriate utmp field
+ * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
+ * - We don't allow dashes or digit as the first character
+ *
+ * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
+ */
+
+ if (!(u[0] >= 'a' && u[0] <= 'z') &&
+ !(u[0] >= 'A' && u[0] <= 'Z') &&
+ u[0] != '_')
+ return false;
-bool valid_user_group_name_or_id_full(const char *u, bool strict) {
+ for (i = u+1; *i; i++)
+ if (!(*i >= 'a' && *i <= 'z') &&
+ !(*i >= 'A' && *i <= 'Z') &&
+ !(*i >= '0' && *i <= '9') &&
+ !IN_SET(*i, '_', '-'))
+ return false;
- /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the
- * right range, and not the invalid user ids. */
+ l = i - u;
- if (isempty(u))
- return false;
+ sz = sysconf(_SC_LOGIN_NAME_MAX);
+ assert_se(sz > 0);
- if (parse_uid(u, NULL) >= 0)
- return true;
+ if (l > (size_t) sz)
+ return false;
+ if (l > FILENAME_MAX)
+ return false;
+ if (l > UT_NAMESIZE - 1)
+ return false;
+ }
- return valid_user_group_name_full(u, strict);
+ return true;
}
bool valid_gecos(const char *d) {
diff --git a/src/basic/user-util.h b/src/basic/user-util.h
index 6796ac42c1..1f267d21a3 100644
--- a/src/basic/user-util.h
+++ b/src/basic/user-util.h
@@ -97,20 +97,13 @@ static inline bool userns_supported(void) {
return access("/proc/self/uid_map", F_OK) >= 0;
}
-bool valid_user_group_name_full(const char *u, bool strict);
-bool valid_user_group_name_or_id_full(const char *u, bool strict);
-static inline bool valid_user_group_name(const char *u) {
- return valid_user_group_name_full(u, true);
-}
-static inline bool valid_user_group_name_or_id(const char *u) {
- return valid_user_group_name_or_id_full(u, true);
-}
-static inline bool valid_user_group_name_compat(const char *u) {
- return valid_user_group_name_full(u, false);
-}
-static inline bool valid_user_group_name_or_id_compat(const char *u) {
- return valid_user_group_name_or_id_full(u, false);
-}
+typedef enum ValidUserFlags {
+ VALID_USER_RELAX = 1 << 0,
+ VALID_USER_WARN = 1 << 1,
+ VALID_USER_ALLOW_NUMERIC = 1 << 2,
+} ValidUserFlags;
+
+bool valid_user_group_name(const char *u, ValidUserFlags flags);
bool valid_gecos(const char *d);
bool valid_home(const char *p);
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 5696a60ba8..93857436b4 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -1204,10 +1204,10 @@ int bus_exec_context_set_transient_property(
flags |= UNIT_PRIVATE;
if (streq(name, "User"))
- return bus_set_transient_user_compat(u, name, &c->user, message, flags, error);
+ return bus_set_transient_user_relaxed(u, name, &c->user, message, flags, error);
if (streq(name, "Group"))
- return bus_set_transient_user_compat(u, name, &c->group, message, flags, error);
+ return bus_set_transient_user_relaxed(u, name, &c->group, message, flags, error);
if (streq(name, "TTYPath"))
return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
@@ -1392,7 +1392,7 @@ int bus_exec_context_set_transient_property(
return r;
STRV_FOREACH(p, l)
- if (!isempty(*p) && !valid_user_group_name_or_id_compat(*p))
+ if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
"Invalid supplementary group names");
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 60f55aef5f..ef4bb316cc 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1643,7 +1643,7 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
- if (!valid_user_group_name(name))
+ if (!valid_user_group_name(name, VALID_USER_RELAX))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name);
r = dynamic_user_lookup_name(m, name, &uid);
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index c8253c7940..ad7b41a95b 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -278,10 +278,10 @@ static int bus_socket_set_transient_property(
return bus_set_transient_fdname(u, name, &s->fdname, message, flags, error);
if (streq(name, "SocketUser"))
- return bus_set_transient_user_compat(u, name, &s->user, message, flags, error);
+ return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
if (streq(name, "SocketGroup"))
- return bus_set_transient_user_compat(u, name, &s->group, message, flags, error);
+ return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
if (streq(name, "BindIPv6Only"))
return bus_set_transient_bind_ipv6_only(u, name, &s->bind_ipv6_only, message, flags, error);
diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c
index 7862beaacb..951450e53d 100644
--- a/src/core/dbus-util.c
+++ b/src/core/dbus-util.c
@@ -30,7 +30,12 @@ int bus_property_get_triggered_unit(
BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
-BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_compat, valid_user_group_name_or_id_compat);
+
+static inline bool valid_user_group_name_or_id_relaxed(const char *u) {
+ return valid_user_group_name(u, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX);
+}
+
+BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed);
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
int bus_set_transient_string(
diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h
index ec8c245fff..654ceb5279 100644
--- a/src/core/dbus-util.h
+++ b/src/core/dbus-util.h
@@ -236,7 +236,7 @@ int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *i
int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
-int bus_set_transient_user_compat(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
+int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
diff --git a/src/core/dynamic-user.c b/src/core/dynamic-user.c
index f1819b36bc..58b37925bf 100644
--- a/src/core/dynamic-user.c
+++ b/src/core/dynamic-user.c
@@ -116,7 +116,7 @@ static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret)
return 0;
}
- if (!valid_user_group_name_or_id(name))
+ if (!valid_user_group_name(name, VALID_USER_ALLOW_NUMERIC))
return -EINVAL;
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, storage_socket) < 0)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 646364eb89..f3fe73535e 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2068,7 +2068,7 @@ int config_parse_user_group_compat(
return -ENOEXEC;
}
- if (!valid_user_group_name_or_id_compat(k)) {
+ if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
return -ENOEXEC;
}
@@ -2122,7 +2122,7 @@ int config_parse_user_group_strv_compat(
return -ENOEXEC;
}
- if (!valid_user_group_name_or_id_compat(k)) {
+ if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
return -ENOEXEC;
}
diff --git a/src/core/unit.c b/src/core/unit.c
index 96e1a6c320..95d574d8d4 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -4287,7 +4287,7 @@ static int user_from_unit_name(Unit *u, char **ret) {
if (r < 0)
return r;
- if (valid_user_group_name(n)) {
+ if (valid_user_group_name(n, 0)) {
*ret = TAKE_PTR(n);
return 0;
}
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index 8ef1cd5..25d034a 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -124,7 +124,7 @@ static int direct_lookup_uid(uid_t uid, char **ret) {
r = readlink_malloc(path, &s);
if (r < 0)
return r;
- if (!valid_user_group_name(s)) { /* extra safety check */
+ if (!valid_user_group_name(s, VALID_USER_RELAX)) { /* extra safety check */
free(s);
return -EINVAL;
}
@@ -154,7 +154,7 @@ enum nss_status _nss_systemd_getpwnam_r(
/* If the username is not valid, then we don't know it. Ideally libc would filter these for us anyway. We don't
* generate EINVAL here, because it isn't really out business to complain about invalid user names. */
- if (!valid_user_group_name(name))
+ if (!valid_user_group_name(name, VALID_USER_RELAX))
return NSS_STATUS_NOTFOUND;
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
@@ -357,7 +357,7 @@ enum nss_status _nss_systemd_getgrnam_r(
assert(name);
assert(gr);
- if (!valid_user_group_name(name))
+ if (!valid_user_group_name(name, VALID_USER_RELAX))
return NSS_STATUS_NOTFOUND;
/* Synthesize records for root and nobody, in case they are missing form /etc/group */
diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h
index e8d26ab71b..162b650e64 100644
--- a/src/systemd/sd-messages.h
+++ b/src/systemd/sd-messages.h
@@ -158,6 +158,9 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
+#define SD_MESSAGE_UNSAFE_USER_NAME SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
+#define SD_MESSAGE_UNSAFE_USER_NAME_STR SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
+
_SD_END_DECLARATIONS;
#endif
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 08a2df7..3e3da47 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -1417,7 +1417,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
if (r < 0)
log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, name);
- if (!valid_user_group_name(resolved_name))
+ if (!valid_user_group_name(resolved_name, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] '%s' is not a valid user or group name.",
fname, line, resolved_name);
@@ -1520,7 +1520,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
"[%s:%u] Lines of type 'm' require a group name in the third field.",
fname, line);
- if (!valid_user_group_name(resolved_id))
+ if (!valid_user_group_name(resolved_id, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] '%s' is not a valid user or group name.",
fname, line, resolved_id);
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index 11c01e5189..a0e1495186 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -63,144 +63,163 @@ static void test_uid_ptr(void) {
assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
}
-static void test_valid_user_group_name_compat(void) {
+static void test_valid_user_group_name_relaxed(void) {
log_info("/* %s */", __func__);
- assert_se(!valid_user_group_name_compat(NULL));
- assert_se(!valid_user_group_name_compat(""));
- assert_se(!valid_user_group_name_compat("1"));
- assert_se(!valid_user_group_name_compat("65535"));
- assert_se(!valid_user_group_name_compat("-1"));
- assert_se(!valid_user_group_name_compat("-kkk"));
- assert_se(!valid_user_group_name_compat("rööt"));
- assert_se(!valid_user_group_name_compat("."));
- assert_se(!valid_user_group_name_compat(".eff"));
- assert_se(!valid_user_group_name_compat("foo\nbar"));
- assert_se(!valid_user_group_name_compat("0123456789012345678901234567890123456789"));
- assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
- assert_se(!valid_user_group_name_compat("."));
- assert_se(!valid_user_group_name_compat(".1"));
- assert_se(!valid_user_group_name_compat(".65535"));
- assert_se(!valid_user_group_name_compat(".-1"));
- assert_se(!valid_user_group_name_compat(".-kkk"));
- assert_se(!valid_user_group_name_compat(".rööt"));
- assert_se(!valid_user_group_name_or_id_compat(".aaa:bbb"));
-
- assert_se(valid_user_group_name_compat("root"));
- assert_se(valid_user_group_name_compat("lennart"));
- assert_se(valid_user_group_name_compat("LENNART"));
- assert_se(valid_user_group_name_compat("_kkk"));
- assert_se(valid_user_group_name_compat("kkk-"));
- assert_se(valid_user_group_name_compat("kk-k"));
- assert_se(valid_user_group_name_compat("eff.eff"));
- assert_se(valid_user_group_name_compat("eff."));
-
- assert_se(valid_user_group_name_compat("some5"));
- assert_se(valid_user_group_name_compat("5some"));
- assert_se(valid_user_group_name_compat("INNER5NUMBER"));
+ assert_se(!valid_user_group_name(NULL, VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("1", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("65535", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("-1", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("foo\nbar", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_RELAX|VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name(".aaa:bbb", VALID_USER_RELAX|VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name(".", VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("..", VALID_USER_RELAX));
+
+ assert_se(valid_user_group_name("root", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("lennart", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("LENNART", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("_kkk", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("kkk-", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("kk-k", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("eff.eff", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("eff.", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("-kkk", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("rööt", VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".eff", VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".1", VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".65535", VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".-1", VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".-kkk", VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".rööt", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("...", VALID_USER_RELAX));
+
+ assert_se(valid_user_group_name("some5", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("5some", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_RELAX));
+
+ assert_se(valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_RELAX));
+ assert_se(valid_user_group_name("Dāvis", VALID_USER_RELAX));
}
static void test_valid_user_group_name(void) {
log_info("/* %s */", __func__);
- assert_se(!valid_user_group_name(NULL));
- assert_se(!valid_user_group_name(""));
- assert_se(!valid_user_group_name("1"));
- assert_se(!valid_user_group_name("65535"));
- assert_se(!valid_user_group_name("-1"));
- assert_se(!valid_user_group_name("-kkk"));
- assert_se(!valid_user_group_name("rööt"));
- assert_se(!valid_user_group_name("."));
- assert_se(!valid_user_group_name(".eff"));
- assert_se(!valid_user_group_name("foo\nbar"));
- assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
- assert_se(!valid_user_group_name_or_id("aaa:bbb"));
- assert_se(!valid_user_group_name("."));
- assert_se(!valid_user_group_name(".1"));
- assert_se(!valid_user_group_name(".65535"));
- assert_se(!valid_user_group_name(".-1"));
- assert_se(!valid_user_group_name(".-kkk"));
- assert_se(!valid_user_group_name(".rööt"));
- assert_se(!valid_user_group_name_or_id(".aaa:bbb"));
-
- assert_se(valid_user_group_name("root"));
- assert_se(valid_user_group_name("lennart"));
- assert_se(valid_user_group_name("LENNART"));
- assert_se(valid_user_group_name("_kkk"));
- assert_se(valid_user_group_name("kkk-"));
- assert_se(valid_user_group_name("kk-k"));
- assert_se(!valid_user_group_name("eff.eff"));
- assert_se(!valid_user_group_name("eff."));
-
- assert_se(valid_user_group_name("some5"));
- assert_se(!valid_user_group_name("5some"));
- assert_se(valid_user_group_name("INNER5NUMBER"));
+ assert_se(!valid_user_group_name(NULL, 0));
+ assert_se(!valid_user_group_name("", 0));
+ assert_se(!valid_user_group_name("1", 0));
+ assert_se(!valid_user_group_name("65535", 0));
+ assert_se(!valid_user_group_name("-1", 0));
+ assert_se(!valid_user_group_name("-kkk", 0));
+ assert_se(!valid_user_group_name("rööt", 0));
+ assert_se(!valid_user_group_name(".", 0));
+ assert_se(!valid_user_group_name(".eff", 0));
+ assert_se(!valid_user_group_name("foo\nbar", 0));
+ assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", 0));
+ assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name(".", 0));
+ assert_se(!valid_user_group_name("..", 0));
+ assert_se(!valid_user_group_name("...", 0));
+ assert_se(!valid_user_group_name(".1", 0));
+ assert_se(!valid_user_group_name(".65535", 0));
+ assert_se(!valid_user_group_name(".-1", 0));
+ assert_se(!valid_user_group_name(".-kkk", 0));
+ assert_se(!valid_user_group_name(".rööt", 0));
+ assert_se(!valid_user_group_name(".aaa:bbb", VALID_USER_ALLOW_NUMERIC));
+
+ assert_se(valid_user_group_name("root", 0));
+ assert_se(valid_user_group_name("lennart", 0));
+ assert_se(valid_user_group_name("LENNART", 0));
+ assert_se(valid_user_group_name("_kkk", 0));
+ assert_se(valid_user_group_name("kkk-", 0));
+ assert_se(valid_user_group_name("kk-k", 0));
+ assert_se(!valid_user_group_name("eff.eff", 0));
+ assert_se(!valid_user_group_name("eff.", 0));
+
+ assert_se(valid_user_group_name("some5", 0));
+ assert_se(!valid_user_group_name("5some", 0));
+ assert_se(valid_user_group_name("INNER5NUMBER", 0));
+
+ assert_se(!valid_user_group_name("piff.paff@ad.domain.example", 0));
+ assert_se(!valid_user_group_name("Dāvis", 0));
}
-static void test_valid_user_group_name_or_id_compat(void) {
+static void test_valid_user_group_name_or_numeric_relaxed(void) {
log_info("/* %s */", __func__);
- assert_se(!valid_user_group_name_or_id_compat(NULL));
- assert_se(!valid_user_group_name_or_id_compat(""));
- assert_se(valid_user_group_name_or_id_compat("0"));
- assert_se(valid_user_group_name_or_id_compat("1"));
- assert_se(valid_user_group_name_or_id_compat("65534"));
- assert_se(!valid_user_group_name_or_id_compat("65535"));
- assert_se(valid_user_group_name_or_id_compat("65536"));
- assert_se(!valid_user_group_name_or_id_compat("-1"));
- assert_se(!valid_user_group_name_or_id_compat("-kkk"));
- assert_se(!valid_user_group_name_or_id_compat("rööt"));
- assert_se(!valid_user_group_name_or_id_compat("."));
- assert_se(!valid_user_group_name_or_id_compat(".eff"));
- assert_se(valid_user_group_name_or_id_compat("eff.eff"));
- assert_se(valid_user_group_name_or_id_compat("eff."));
- assert_se(!valid_user_group_name_or_id_compat("foo\nbar"));
- assert_se(!valid_user_group_name_or_id_compat("0123456789012345678901234567890123456789"));
- assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
-
- assert_se(valid_user_group_name_or_id_compat("root"));
- assert_se(valid_user_group_name_or_id_compat("lennart"));
- assert_se(valid_user_group_name_or_id_compat("LENNART"));
- assert_se(valid_user_group_name_or_id_compat("_kkk"));
- assert_se(valid_user_group_name_or_id_compat("kkk-"));
- assert_se(valid_user_group_name_or_id_compat("kk-k"));
-
- assert_se(valid_user_group_name_or_id_compat("some5"));
- assert_se(valid_user_group_name_or_id_compat("5some"));
- assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
+ assert_se(!valid_user_group_name(NULL, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("0", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("1", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("65534", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("65535", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("65536", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("-1", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("foo\nbar", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name(".", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(!valid_user_group_name("..", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+
+ assert_se(valid_user_group_name("root", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("lennart", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("LENNART", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("_kkk", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("kkk-", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("kk-k", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("-kkk", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("rööt", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name(".eff", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("eff.eff", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("eff.", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("...", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+
+ assert_se(valid_user_group_name("some5", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("5some", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+
+ assert_se(valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
+ assert_se(valid_user_group_name("Dāvis", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
}
-static void test_valid_user_group_name_or_id(void) {
+static void test_valid_user_group_name_or_numeric(void) {
log_info("/* %s */", __func__);
- assert_se(!valid_user_group_name_or_id(NULL));
- assert_se(!valid_user_group_name_or_id(""));
- assert_se(valid_user_group_name_or_id("0"));
- assert_se(valid_user_group_name_or_id("1"));
- assert_se(valid_user_group_name_or_id("65534"));
- assert_se(!valid_user_group_name_or_id("65535"));
- assert_se(valid_user_group_name_or_id("65536"));
- assert_se(!valid_user_group_name_or_id("-1"));
- assert_se(!valid_user_group_name_or_id("-kkk"));
- assert_se(!valid_user_group_name_or_id("rööt"));
- assert_se(!valid_user_group_name_or_id("."));
- assert_se(!valid_user_group_name_or_id(".eff"));
- assert_se(!valid_user_group_name_or_id("eff.eff"));
- assert_se(!valid_user_group_name_or_id("eff."));
- assert_se(!valid_user_group_name_or_id("foo\nbar"));
- assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789"));
- assert_se(!valid_user_group_name_or_id("aaa:bbb"));
-
- assert_se(valid_user_group_name_or_id("root"));
- assert_se(valid_user_group_name_or_id("lennart"));
- assert_se(valid_user_group_name_or_id("LENNART"));
- assert_se(valid_user_group_name_or_id("_kkk"));
- assert_se(valid_user_group_name_or_id("kkk-"));
- assert_se(valid_user_group_name_or_id("kk-k"));
-
- assert_se(valid_user_group_name_or_id("some5"));
- assert_se(!valid_user_group_name_or_id("5some"));
- assert_se(valid_user_group_name_or_id("INNER5NUMBER"));
+ assert_se(!valid_user_group_name(NULL, VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("0", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("1", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("65534", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("65535", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("65536", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("-1", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("-kkk", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("rööt", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name(".", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("..", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("...", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name(".eff", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("eff.eff", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("eff.", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("foo\nbar", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC));
+
+ assert_se(valid_user_group_name("root", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("lennart", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("LENNART", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("_kkk", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("kkk-", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("kk-k", VALID_USER_ALLOW_NUMERIC));
+
+ assert_se(valid_user_group_name("some5", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("5some", VALID_USER_ALLOW_NUMERIC));
+ assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_ALLOW_NUMERIC));
+
+ assert_se(!valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_ALLOW_NUMERIC));
+ assert_se(!valid_user_group_name("Dāvis", VALID_USER_ALLOW_NUMERIC));
}
static void test_valid_gecos(void) {
@@ -355,10 +374,10 @@ int main(int argc, char *argv[]) {
test_parse_uid();
test_uid_ptr();
- test_valid_user_group_name_compat();
+ test_valid_user_group_name_relaxed();
test_valid_user_group_name();
- test_valid_user_group_name_or_id_compat();
- test_valid_user_group_name_or_id();
+ test_valid_user_group_name_or_numeric_relaxed();
+ test_valid_user_group_name_or_numeric();
test_valid_gecos();
test_valid_home();
--
2.23.0

View File

@ -0,0 +1,191 @@
From cafed7b32cdac13024c4093b7942a49ee8602dcf Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 7 Apr 2020 10:38:39 +0200
Subject: [PATCH] docs: add a longer document explaining our rules on
user/group names
Reference: https://github.com/systemd/systemd/commit/cafed7b32cdac13024c4093b7942a49ee8602dcf
Conflict: NA
---
docs/USER_NAMES.md | 169 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 169 insertions(+)
create mode 100644 docs/USER_NAMES.md
diff --git a/docs/USER_NAMES.md b/docs/USER_NAMES.md
new file mode 100644
index 0000000000..ccbb0a360d
--- /dev/null
+++ b/docs/USER_NAMES.md
@@ -0,0 +1,169 @@
+--
+title: User/Group Name Syntax
+category: Concepts
+layout: default
+---
+
+# User/Group Name Syntax
+
+The precise set of allowed user and group names on Linux systems is weakly
+defined. Depending on the distribution a different set of requirements and
+restrictions on the syntax of user/group names are enforced — on some
+distributions the accepted syntax is even configurable by the administrator. In
+the interest of interoperability systemd enforces different rules when
+processing users/group defined by other subsystems and when defining users/groups
+itself, following the principle of "Be conservative in what you send, be
+liberal in what you accept". Also in the interest of interoperability systemd
+will enforce the same rules everywhere and not make them configurable or
+distribution dependent. The precise rules are described below.
+
+Generally, the same rules apply for user as for group names.
+
+## Other Systems
+
+* On POSIX the set of [valid user
+ names](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_437)
+ is defined as [lower and upper case ASCII letters, digits, period,
+ underscore, and
+ hyphen](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_282),
+ with the restriction that hyphen is now allowed as first character of the
+ user name. Interestingly no size limit is declared, i.e. in neither
+ direction, meaning that strictly speaking according to POSIX both the empty
+ string is a valid user name as well as a string of gigabytes in length.
+
+* Debian/Ubuntu based systems enforce the regular expression
+ `^[a-z][-a-z0-9]*$`, i.e. only lower case ASCII letters, digits and
+ hyphens. As first character only lowercase ASCII letters are allowed. This
+ regular expression is configurable by the administrator at runtime
+ though. This rule enforces a minimum length of one character but no maximum
+ length.
+
+* Upstream shadow-utils enforces the regular expression
+ `^[a-z_][a-z0-9_-]*[$]$`, i.e. is similar to the Debian/Ubuntu rule, but
+ allows underscores and hyphens, but the latter not as first character. Also,
+ an optional trailing dollar character is permitted.
+
+* Fedora/Red Hat based systems enforce the regular expression of
+ `^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,30}[a-zA-Z0-9_.$-]?$`, i.e. a size limit of
+ 32 characters, with upper and lower case letters, digits, underscores,
+ hyphens and periods. No hyphen as first character though, and the last
+ character may be a dollar character. On top of that, `.` and `..` are not
+ allowed as user/group names.
+
+* sssd is known to generate user names with embedded `@` and white-space
+ characters, as well as non-ASCII (i.e. UTF-8) user/group names.
+
+* winbindd is known to generate user/group names with embedded `\` and
+ white-space characters, as well as non-ASCII (i.e. UTF-8) user/group names.
+
+Other operating systems enforce different rules; in this documentation we'll
+focus on Linux systems only however, hence those are out of scope. That said,
+software like Samba is frequently deployed on Linux for providing compatibility
+with Windows systems; on such systems it might be wise to stick to user/group
+names also valid according to Windows rules.
+
+## Rules systemd enforces
+
+Distilled from the above, below are the rules systemd enforces on user/group
+names. An additional, common rule between both modes listed below is that empty
+strings are not valid user/group names.
+
+Philosophically, the strict mode described below enforces a white-list of what's
+allowed and prohibits everything else, while the relaxed mode described below
+implements a blacklist of what's not allowed and permits everything else.
+
+### Strict mode
+
+Strict user/group name syntax is enforced whenever a systemd component is used
+to register a user or group in the system, for example a system user/group
+using
+[`systemd-sysusers.service`](https://www.freedesktop.org/software/systemd/man/systemd-sysusers.html)
+or a regular user with
+[`systemd-homed.service`](https://www.freedesktop.org/software/systemd/man/systemd-homed.html).
+
+In strict mode, only uppercase and lowercase characters are allowed, as well as
+digits, underscores and hyphens. The first character may not be a digit or
+hyphen. A size limit is enforced: the minimum of `sysconf(_SC_LOGIN_NAME_MAX)`
+(typically 256 on Linux; rationale: this is how POSIX suggests to detect the
+limit), `UT_NAMESIZE-1` (typically 31 on Linux; rationale: names longer than
+this cannot correctly appear in `utmp`/`wtmp` and create ambiguity with login
+accounting) and `FILENAME_MAX` (4096 on Linux; rationale: user names typically
+appear in directory names, i.e. the home directory), thus MIN(256, 31, 4096) =
+31.
+
+Note that these rules are both more strict and more relaxed than all of the
+rules enforced by other systems listed above. A user/group name conforming to
+systemd's strict rules will not necessarily pass a test by the rules enforced
+by these other subsystems.
+
+Written as regular expression the above is: `^[a-zA-Z_][a-zA-Z0-9_-]{0,30}$`
+
+### Relaxed mode
+
+Relaxed user/group name syntax is enforced whenever a systemd component accepts
+and makes use of user/group names registered by other (non-systemd)
+components of the system, for example in
+[`systemd-logind.service`](https://www.freedesktop.org/software/systemd/man/systemd-logind.html).
+
+Relaxed syntax is also enforced by the `User=` setting in service unit files,
+i.e. for system services used for running services. Since these users may be
+registered by a variety of tools relaxed mode is used, but since the primary
+purpose of these users is to run a system service and thus a job for systemd a
+warning is shown if the specified user name does not qualify by the strict
+rules above.
+
+* No embedded NUL bytes (rationale: handling in C must be possible and
+ straight-forward)
+
+* No names consisting fully of digits (rationale: avoid confusion with numeric
+ UID/GID specifications)
+
+* Similar, no names consisting of an initial hyphen and otherwise entirely made
+ up of digits (rationale: avoid confusion with negative, numeric UID/GID
+ specifications, e.g. `-1`)
+
+* No strings that do not qualify as valid UTF-8 (rationale: we want to be able
+ to embed these strings in JSON, with permits only valid UTF-8 in its strings;
+ user names using other character sets, such as JIS/Shift-JIS will cause
+ validation errors)
+
+* No control characters (i.e. characters in ASCII range 1…31; rationale: they
+ tend to have special meaning when output on a terminal in other contexts,
+ moreover the newline character — as a specific control character — is used as
+ record separator in `/etc/passwd`, and hence it's crucial to avoid
+ ambiguities here)
+
+* No colon characters (rationale: it is used as field separator in `/etc/passwd`)
+
+* The two strings `.` and `..` are not permitted, as these have special meaning
+ in file system paths, and user names are frequently included in file system
+ paths, in particular for the purpose of home directories.
+
+* Similar, no slashes, as these have special meaning in file system paths
+
+* No leading or trailing white-space is permitted; and hence no user/group names
+ consisting of white-space only either (rationale: this typically indicates
+ parsing errors, and creates confusion since not visible on screen)
+
+Note that these relaxed rules are implied by the strict rules above, i.e. all
+user/group names accepted by the strict rules are also accepted by the relaxed
+rules, but not vice versa.
+
+Note that this relaxed mode does not refuse a couple of very questionable
+syntaxes. For example it permits a leading or embedded period. A leading period
+is problematic because the matching home directory would typically be hidden
+from the user's/administrator's view. An embedded period is problematic since
+it creates ambiguity in traditional `chown` syntax (which is still accepted
+today) that uses it to separate user and group names in the command's
+parameter: without consulting the user/group databases it is not possible to
+determine if a `chown` invocation would change just the owning user or both the
+owning user and group. It also allows embeddeding `@` (which is confusing to
+MTAs).
+
+## Common Core
+
+Combining all rules listed above, user/group names that shall be considered
+valid in all systemd contexts and on all Linux systems should match the
+following regular expression (at least according to our understanding):
+
+`^[a-z][a-z0-9-]{0,30}$`
--
2.23.0

View File

@ -0,0 +1,58 @@
From 887a8fa341d9b24a7c9cd3f1fce328f8e43a1b4f Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 7 Apr 2020 11:04:59 +0200
Subject: [PATCH] docs: hook up the new USER_NAMES document everywhere
(Also correct the set of names we accept in User=, which was forgotten
to be updated in ae480f0b09aec815b64579bb1828ea935d8ee236.
Reference: https://github.com/systemd/systemd/commit/887a8fa341d9b24a7c9cd3f1fce328f8e43a1b4f
Conflict: Remove unneeded file changes.
---
man/systemd.exec.xml | 15 +++++++++------
man/sysusers.d.xml | 3 +++
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index a52d8fa..bf9b030 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -186,12 +186,15 @@
is set, the default group of the user is used. This setting does not affect commands whose command line is
prefixed with <literal>+</literal>.</para>
- <para>Note that restrictions on the user/group name syntax are enforced: the specified name must consist only
- of the characters a-z, A-Z, 0-9, <literal>_</literal> and <literal>-</literal>, except for the first character
- which must be one of a-z, A-Z or <literal>_</literal> (i.e. numbers and <literal>-</literal> are not permitted
- as first character). The user/group name must have at least one character, and at most 31. These restrictions
- are enforced in order to avoid ambiguities and to ensure user/group names and unit files remain portable among
- Linux systems.</para>
+ <para>Note that this enforces only weak restrictions on the user/group name syntax, but will generate
+ warnings in many cases where user/group names do not adhere to the following rules: the specified
+ name should consist only of the characters a-z, A-Z, 0-9, <literal>_</literal> and
+ <literal>-</literal>, except for the first character which must be one of a-z, A-Z and
+ <literal>_</literal> (i.e. digits and <literal>-</literal> are not permitted as first character). The
+ user/group name must have at least one character, and at most 31. These restrictions are made in
+ order to avoid ambiguities and to ensure user/group names and unit files remain portable among Linux
+ systems. For further details on the names accepted and the names warned about see <ulink
+ url="https://systemd.io/USER_NAMES">User/Group Name Syntax</ulink>.</para>
<para>When used in conjunction with <varname>DynamicUser=</varname> the user/group name specified is
dynamically allocated at the time the service is started, and released at the time the service is stopped —
diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml
index e47d36c..840da44 100644
--- a/man/sysusers.d.xml
+++ b/man/sysusers.d.xml
@@ -143,6 +143,9 @@ u root 0 "Superuser" /root /bin/zsh</pro
A-Z or <literal>_</literal> (i.e. numbers and <literal>-</literal> are not permitted as first character). The
user/group name must have at least one character, and at most 31.</para>
+ <para>For further details about the syntax of user/group names, see <ulink
+ url="https://systemd.io/USER_NAMES">User/Group Name Syntax</ulink>.</para>
+
<para>It is strongly recommended to pick user and group names that are unlikely to clash with normal users
created by the administrator. A good scheme to guarantee this is by prefixing all system and group names with the
underscore, and avoiding too generic names.</para>
--
2.23.0

View File

@ -0,0 +1,45 @@
From ad313ec33bb367624c25c9264994d6e43b8a7e2e Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Tue, 7 Apr 2020 11:15:49 +0200
Subject: [PATCH] catalog: add entry for SD_MESSAGE_UNSAFE_USER_NAME
Reference: https://github.com/systemd/systemd/commit/ad313ec33bb367624c25c9264994d6e43b8a7e2e
Conflict: NA
---
catalog/systemd.catalog.in | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in
index db275d7c50..3342d59422 100644
--- a/catalog/systemd.catalog.in
+++ b/catalog/systemd.catalog.in
@@ -412,3 +412,26 @@ as the best process to terminate and has been forcibly terminated by the
kernel.
Note that the memory pressure might or might not have been caused by @UNIT@.
+
+-- b61fdac612e94b9182285b998843061f
+Subject: Accepting user/group name @USER_GROUP_NAME@, which does not match strict user/group name rules.
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+The user/group name @USER_GROUP_NAME@ has been specified, which is accepted
+according the relaxed user/group name rules, but does not qualify under the
+strict rules.
+
+The strict user/group name rules written as regular expression are:
+
+^[a-zA-Z_][a-zA-Z0-9_-]{0,30}$
+
+The relaxed user/group name rules accept all names, except for the empty
+string; names containing NUL bytes, control characters, colon or slash
+characters; names not valid UTF-8; names with leading or trailing whitespace;
+the strings "." or ".."; fully numeric strings, or strings beginning in a
+hyphen and otherwise fully numeric.
+
+For further details on strict and relaxed user/group name rules, see:
+
+https://systemd.io/USER_NAMES
--
2.23.0

View File

@ -0,0 +1,73 @@
From 156a5fd297b61bce31630d7a52c15614bf784843 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Sun, 31 May 2020 18:21:09 +0200
Subject: [PATCH] basic/user-util: always use base 10 for user/group numbers
We would parse numbers with base prefixes as user identifiers. For example,
"0x2b3bfa0" would be interpreted as UID==45334432 and "01750" would be
interpreted as UID==1000. This parsing was used also in cases where either a
user/group name or number may be specified. This means that names like
0x2b3bfa0 would be ambiguous: they are a valid user name according to our
documented relaxed rules, but they would also be parsed as numeric uids.
This behaviour is definitely not expected by users, since tools generally only
accept decimal numbers (e.g. id, getent passwd), while other tools only accept
user names and thus will interpret such strings as user names without even
attempting to convert them to numbers (su, ssh). So let's follow suit and only
accept numbers in decimal notation. Effectively this means that we will reject
such strings as a username/uid/groupname/gid where strict mode is used, and try
to look up a user/group with such a name in relaxed mode.
Since the function changed is fairly low-level and fairly widely used, this
affects multiple tools: loginctl show-user/enable-linger/disable-linger foo',
the third argument in sysusers.d, fourth and fifth arguments in tmpfiles.d,
etc.
Fixes #15985.
Reference: https://github.com/systemd/systemd/commit/156a5fd297b61bce31630d7a52c15614bf784843
Conflict: NA
---
src/basic/user-util.c | 2 +-
src/test/test-user-util.c | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 2e3580017d..2db8ef6abf 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -49,7 +49,7 @@ int parse_uid(const char *s, uid_t *ret) {
assert(s);
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
- r = safe_atou32(s, &uid);
+ r = safe_atou32_full(s, 10, &uid);
if (r < 0)
return r;
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index a0e1495186..3165232fef 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -48,9 +48,19 @@ static void test_parse_uid(void) {
r = parse_uid("65535", &uid);
assert_se(r == -ENXIO);
+ assert_se(uid == 100);
+
+ r = parse_uid("0x1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("01234", &uid);
+ assert_se(r == 0);
+ assert_se(uid == 1234);
r = parse_uid("asdsdas", &uid);
assert_se(r == -EINVAL);
+ assert_se(uid == 1234);
}
static void test_uid_ptr(void) {
--
2.23.0

View File

@ -0,0 +1,151 @@
From 22810041c2200fe72b0e0c985d0e404f8b80f9e2 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Thu, 14 Nov 2019 14:49:40 +0100
Subject: [PATCH] parse-util: sometimes it is useful to check if a string is a
valid integer, but not actually parse it
Reference: https://github.com/systemd/systemd/commit/22810041c2200fe72b0e0c985d0e404f8b80f9e2
Conflict: NA
---
src/basic/parse-util.c | 34 ++++++++++++++++++++--------------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index aec6099c9c..b81db04989 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -365,7 +365,6 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
unsigned long l;
assert(s);
- assert(ret_u);
assert(base <= 16);
/* strtoul() is happy to parse negative values, and silently
@@ -389,7 +388,9 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
if ((unsigned long) (unsigned) l != l)
return -ERANGE;
- *ret_u = (unsigned) l;
+ if (ret_u)
+ *ret_u = (unsigned) l;
+
return 0;
}
@@ -398,7 +399,6 @@ int safe_atoi(const char *s, int *ret_i) {
long l;
assert(s);
- assert(ret_i);
errno = 0;
l = strtol(s, &x, 0);
@@ -409,7 +409,9 @@ int safe_atoi(const char *s, int *ret_i) {
if ((long) (int) l != l)
return -ERANGE;
- *ret_i = (int) l;
+ if (ret_i)
+ *ret_i = (int) l;
+
return 0;
}
@@ -418,7 +420,6 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
unsigned long long l;
assert(s);
- assert(ret_llu);
s += strspn(s, WHITESPACE);
@@ -431,7 +432,9 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
if (*s == '-')
return -ERANGE;
- *ret_llu = l;
+ if (ret_llu)
+ *ret_llu = l;
+
return 0;
}
@@ -440,7 +443,6 @@ int safe_atolli(const char *s, long long int *ret_lli) {
long long l;
assert(s);
- assert(ret_lli);
errno = 0;
l = strtoll(s, &x, 0);
@@ -449,7 +451,9 @@ int safe_atolli(const char *s, long long int *ret_lli) {
if (!x || x == s || *x != 0)
return -EINVAL;
- *ret_lli = l;
+ if (ret_lli)
+ *ret_lli = l;
+
return 0;
}
@@ -458,7 +462,6 @@ int safe_atou8(const char *s, uint8_t *ret) {
unsigned long l;
assert(s);
- assert(ret);
s += strspn(s, WHITESPACE);
@@ -473,7 +476,8 @@ int safe_atou8(const char *s, uint8_t *ret) {
if ((unsigned long) (uint8_t) l != l)
return -ERANGE;
- *ret = (uint8_t) l;
+ if (ret)
+ *ret = (uint8_t) l;
return 0;
}
@@ -507,7 +511,6 @@ int safe_atoi16(const char *s, int16_t *ret) {
long l;
assert(s);
- assert(ret);
errno = 0;
l = strtol(s, &x, 0);
@@ -518,7 +521,9 @@ int safe_atoi16(const char *s, int16_t *ret) {
if ((long) (int16_t) l != l)
return -ERANGE;
- *ret = (int16_t) l;
+ if (ret)
+ *ret = (int16_t) l;
+
return 0;
}
@@ -528,7 +533,6 @@ int safe_atod(const char *s, double *ret_d) {
double d = 0;
assert(s);
- assert(ret_d);
loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0);
if (loc == (locale_t) 0)
@@ -541,7 +545,9 @@ int safe_atod(const char *s, double *ret_d) {
if (!x || x == s || *x != 0)
return -EINVAL;
- *ret_d = (double) d;
+ if (ret_d)
+ *ret_d = (double) d;
+
return 0;
}
--
2.23.0

View File

@ -0,0 +1,132 @@
From ce51632a357d347737bf40d3817df331cd8874cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
Date: Thu, 9 Apr 2020 11:18:26 +0200
Subject: [PATCH] basic/parse-util: add safe_atoux64()
Reference: https://github.com/systemd/systemd/commit/ce51632a357d347737bf40d3817df331cd8874cb
Conflict: NA
---
src/basic/parse-util.c | 4 ++--
src/basic/parse-util.h | 12 +++++++++++-
src/test/test-parse-util.c | 39 ++++++++++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+), 3 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index e0094b0f37..8de5cd5c56 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -395,7 +395,7 @@ int safe_atoi(const char *s, int *ret_i) {
return 0;
}
-int safe_atollu(const char *s, long long unsigned *ret_llu) {
+int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
char *x = NULL;
unsigned long long l;
@@ -404,7 +404,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
s += strspn(s, WHITESPACE);
errno = 0;
- l = strtoull(s, &x, 0);
+ l = strtoull(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 36d76ba576..970bdefbf0 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -28,7 +28,6 @@ static inline int safe_atou(const char *s, unsigned *ret_u) {
}
int safe_atoi(const char *s, int *ret_i);
-int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);
int safe_atou8(const char *s, uint8_t *ret);
@@ -59,6 +58,12 @@ static inline int safe_atoi32(const char *s, int32_t *ret_i) {
return safe_atoi(s, (int*) ret_i);
}
+int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu);
+
+static inline int safe_atollu(const char *s, long long unsigned *ret_llu) {
+ return safe_atollu_full(s, 0, ret_llu);
+}
+
static inline int safe_atou64(const char *s, uint64_t *ret_u) {
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
@@ -69,6 +74,11 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
return safe_atolli(s, (long long int*) ret_i);
}
+static inline int safe_atoux64(const char *s, uint64_t *ret) {
+ assert_cc(sizeof(int64_t) == sizeof(long long unsigned));
+ return safe_atollu_full(s, 16, (long long unsigned*) ret);
+}
+
#if LONG_MAX == INT_MAX
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));
diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c
index d732f402f0..1627bc747d 100644
--- a/src/test/test-parse-util.c
+++ b/src/test/test-parse-util.c
@@ -561,6 +561,44 @@ static void test_safe_atoi64(void) {
assert_se(r == -EINVAL);
}
+static void test_safe_atoux64(void) {
+ int r;
+ uint64_t l;
+
+ r = safe_atoux64("12345", &l);
+ assert_se(r == 0);
+ assert_se(l == 0x12345);
+
+ r = safe_atoux64(" 12345", &l);
+ assert_se(r == 0);
+ assert_se(l == 0x12345);
+
+ r = safe_atoux64("0x12345", &l);
+ assert_se(r == 0);
+ assert_se(l == 0x12345);
+
+ r = safe_atoux64("18446744073709551617", &l);
+ assert_se(r == -ERANGE);
+
+ r = safe_atoux64("-1", &l);
+ assert_se(r == -ERANGE);
+
+ r = safe_atoux64(" -1", &l);
+ assert_se(r == -ERANGE);
+
+ r = safe_atoux64("junk", &l);
+ assert_se(r == -EINVAL);
+
+ r = safe_atoux64("123x", &l);
+ assert_se(r == -EINVAL);
+
+ r = safe_atoux64("12.3", &l);
+ assert_se(r == -EINVAL);
+
+ r = safe_atoux64("", &l);
+ assert_se(r == -EINVAL);
+}
+
static void test_safe_atod(void) {
int r;
double d;
@@ -838,6 +876,7 @@ int main(int argc, char *argv[]) {
test_safe_atoux16();
test_safe_atou64();
test_safe_atoi64();
+ test_safe_atoux64();
test_safe_atod();
test_parse_percent();
test_parse_percent_unbounded();
--
2.23.0

View File

@ -0,0 +1,155 @@
From 707e93aff8f358f8a62117e54b857530d6594e4b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Jun 2020 17:06:19 +0200
Subject: [PATCH] parse-util: allow tweaking how to parse integers
This allows disabling a few alternative ways to decode integers
formatted as strings, for safety reasons.
See: #15991
Reference: https://github.com/systemd/systemd/commit/707e93aff8f358f8a62117e54b857530d6594e4b
Conflict: Add inline function safe_atou32_full.
---
src/basic/parse-util.c | 65 +++++++++++++++++++++++++++++++++---------
src/basic/parse-util.h | 13 ++++++++-
2 files changed, 64 insertions(+), 14 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 59f8a31cec..15818958e4 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -359,20 +359,35 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
unsigned long l;
assert(s);
- assert(base <= 16);
+ assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
- /* strtoul() is happy to parse negative values, and silently
- * converts them to unsigned values without generating an
- * error. We want a clean error, hence let's look for the "-"
- * prefix on our own, and generate an error. But let's do so
- * only after strtoul() validated that the string is clean
- * otherwise, so that we return EINVAL preferably over
- * ERANGE. */
+ /* strtoul() is happy to parse negative values, and silently converts them to unsigned values without
+ * generating an error. We want a clean error, hence let's look for the "-" prefix on our own, and
+ * generate an error. But let's do so only after strtoul() validated that the string is clean
+ * otherwise, so that we return EINVAL preferably over ERANGE. */
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
+ strchr(WHITESPACE, s[0]))
+ return -EINVAL;
s += strspn(s, WHITESPACE);
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
+ IN_SET(s[0], '+', '-'))
+ return -EINVAL; /* Note that we check the "-" prefix again a second time below, but return a
+ * different error. I.e. if the SAFE_ATO_REFUSE_PLUS_MINUS flag is set we
+ * blanket refuse +/- prefixed integers, while if it is missing we'll just
+ * return ERANGE, because the string actually parses correctly, but doesn't
+ * fit in the return type. */
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
+ s[0] == '0' && !streq(s, "0"))
+ return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
+ * notation and assumed-to-be-decimal integers with a leading zero. */
+
errno = 0;
- l = strtoul(s, &x, base);
+ l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
+ * base is left */);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -414,11 +429,24 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
unsigned long long l;
assert(s);
+ assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
+ strchr(WHITESPACE, s[0]))
+ return -EINVAL;
s += strspn(s, WHITESPACE);
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
+ IN_SET(s[0], '+', '-'))
+ return -EINVAL;
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
+ s[0] == '0' && s[1] != 0)
+ return -EINVAL;
+
errno = 0;
- l = strtoull(s, &x, base);
+ l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -480,13 +508,24 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
unsigned long l;
assert(s);
- assert(ret);
- assert(base <= 16);
+ assert(SAFE_ATO_MASK_FLAGS(base) <= 16);
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_WHITESPACE) &&
+ strchr(WHITESPACE, s[0]))
+ return -EINVAL;
s += strspn(s, WHITESPACE);
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_PLUS_MINUS) &&
+ IN_SET(s[0], '+', '-'))
+ return -EINVAL;
+
+ if (FLAGS_SET(base, SAFE_ATO_REFUSE_LEADING_ZERO) &&
+ s[0] == '0' && s[1] != 0)
+ return -EINVAL;
+
errno = 0;
- l = strtoul(s, &x, base);
+ l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 84a2c8a..ae7fca7 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -22,6 +22,12 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper);
int parse_errno(const char *t);
int parse_syscall_and_errno(const char *in, char **name, int *error);
+#define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30)
+#define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29)
+#define SAFE_ATO_REFUSE_LEADING_WHITESPACE (1U << 28)
+#define SAFE_ATO_ALL_FLAGS (SAFE_ATO_REFUSE_PLUS_MINUS|SAFE_ATO_REFUSE_LEADING_ZERO|SAFE_ATO_REFUSE_LEADING_WHITESPACE)
+#define SAFE_ATO_MASK_FLAGS(base) ((base) & ~SAFE_ATO_ALL_FLAGS)
+
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
static inline int safe_atou(const char *s, unsigned *ret_u) {
@@ -45,9 +51,14 @@ static inline int safe_atoux16(const char *s, uint16_t *ret) {
int safe_atoi16(const char *s, int16_t *ret);
+static inline int safe_atou32_full(const char *s, unsigned base, uint32_t *ret_u) {
+ assert_cc(sizeof(uint32_t) == sizeof(unsigned));
+ return safe_atou_full(s, base, (unsigned*) ret_u);
+}
+
static inline int safe_atou32(const char *s, uint32_t *ret_u) {
assert_cc(sizeof(uint32_t) == sizeof(unsigned));
- return safe_atou(s, (unsigned*) ret_u);
+ return safe_atou32_full(s, 0, (unsigned*) ret_u);
}
static inline int safe_atoi32(const char *s, int32_t *ret_i) {
--
2.23.0

View File

@ -0,0 +1,61 @@
From c78eefc13562a8fc0c22c00a6d3001af89860258 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Jun 2020 17:08:38 +0200
Subject: [PATCH] parse-util: allow '-0' as alternative to '0' and '+0'
Let's allow "-0" as alternative to "+0" and "0" when parsing integers,
unless the new SAFE_ATO_REFUSE_PLUS_MINUS flag is specified.
In cases where allowing the +/- syntax shall not be allowed
SAFE_ATO_REFUSE_PLUS_MINUS is the right flag to use, but this also means
that -0 as only negative integer that fits into an unsigned value should
be acceptable if the flag is not specified.
Reference: https://github.com/systemd/systemd/commit/c78eefc13562a8fc0c22c00a6d3001af89860258
Conflict: NA
---
src/basic/parse-util.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 15818958e4..7344dc4311 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -392,7 +392,7 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (s[0] == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if ((unsigned long) (unsigned) l != l)
return -ERANGE;
@@ -451,7 +451,7 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (*s == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if (ret_llu)
@@ -493,7 +493,7 @@ int safe_atou8(const char *s, uint8_t *ret) {
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (s[0] == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint8_t) l != l)
return -ERANGE;
@@ -530,7 +530,7 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
return -errno;
if (!x || x == s || *x != 0)
return -EINVAL;
- if (s[0] == '-')
+ if (l != 0 && s[0] == '-')
return -ERANGE;
if ((unsigned long) (uint16_t) l != l)
return -ERANGE;
--
2.23.0

View File

@ -0,0 +1,32 @@
From aa85e4d3cef8ca8436e480bce9fa4ce72876b636 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Jun 2020 17:10:27 +0200
Subject: [PATCH] parse-util: make return parameter optional in
safe_atou16_full()
All other safe_atoXYZ_full() functions have the parameter optional,
let's make it optoinal here, too.
Reference: https://github.com/systemd/systemd/commit/aa85e4d3cef8ca8436e480bce9fa4ce72876b636
Conflict: NA
---
src/basic/parse-util.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 7344dc4311..c58f2cdda1 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -535,7 +535,9 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
if ((unsigned long) (uint16_t) l != l)
return -ERANGE;
- *ret = (uint16_t) l;
+ if (ret)
+ *ret = (uint16_t) l;
+
return 0;
}
--
2.23.0

View File

@ -0,0 +1,60 @@
From c44702a8bd8cc8b7f2f1df21db9308d9af7dda5b Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Jun 2020 17:16:04 +0200
Subject: [PATCH] parse-util: rewrite parse_mode() on top of safe_atou_full()
Parsing is hard, hence let's use our own careful wrappers wherever
possible.
Reference: https://github.com/systemd/systemd/commit/c44702a8bd8cc8b7f2f1df21db9308d9af7dda5b
Conflict: NA
---
src/basic/parse-util.c | 28 +++++++++++++---------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index c58f2cdda1..0f6d24f590 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -70,26 +70,24 @@ int parse_pid(const char *s, pid_t* ret_pid) {
}
int parse_mode(const char *s, mode_t *ret) {
- char *x;
- long l;
+ unsigned m;
+ int r;
assert(s);
- assert(ret);
- s += strspn(s, WHITESPACE);
- if (s[0] == '-')
- return -ERANGE;
-
- errno = 0;
- l = strtol(s, &x, 8);
- if (errno > 0)
- return -errno;
- if (!x || x == s || *x != 0)
- return -EINVAL;
- if (l < 0 || l > 07777)
+ r = safe_atou_full(s, 8 |
+ SAFE_ATO_REFUSE_PLUS_MINUS, /* Leading '+' or even '-' char? that's just weird,
+ * refuse. User might have wanted to add mode flags or
+ * so, but this parser doesn't allow that, so let's
+ * better be safe. */
+ &m);
+ if (r < 0)
+ return r;
+ if (m > 07777)
return -ERANGE;
- *ret = (mode_t) l;
+ if (ret)
+ *ret = m;
return 0;
}
--
2.23.0

View File

@ -0,0 +1,79 @@
From f5979b63cc305ba217dfd174b1bf0583bcf75a73 Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Jun 2020 17:16:46 +0200
Subject: [PATCH] user-util: be stricter in parse_uid()
Let's refuse "+" and "-" prefixed UIDs. Let's refuse whitespace-prefixed
UIDS, Let's refuse zero-prefixed UIDs. Let's be safe than sorry.
Reference: https://github.com/systemd/systemd/commit/f5979b63cc305ba217dfd174b1bf0583bcf75a73
Conflict: NA
---
src/basic/user-util.c | 10 +++++++++-
src/test/test-user-util.c | 26 +++++++++++++++++++++++---
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 2db8ef6abf..4d087b1d3e 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -49,7 +49,15 @@ int parse_uid(const char *s, uid_t *ret) {
assert(s);
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
- r = safe_atou32_full(s, 10, &uid);
+
+ /* We are very strict when parsing UIDs, and prohibit +/- as prefix, leading zero as prefix, and
+ * whitespace. We do this, since this call is often used in a context where we parse things as UID
+ * first, and if that doesn't work we fall back to NSS. Thus we really want to make sure that UIDs
+ * are parsed as UIDs only if they really really look like UIDs. */
+ r = safe_atou32_full(s, 10
+ | SAFE_ATO_REFUSE_PLUS_MINUS
+ | SAFE_ATO_REFUSE_LEADING_ZERO
+ | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &uid);
if (r < 0)
return r;
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index 3165232fef..7d2efc8c59 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -54,13 +54,33 @@ static void test_parse_uid(void) {
assert_se(r == -EINVAL);
assert_se(uid == 100);
+ r = parse_uid("+1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("-1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid(" 1234", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
r = parse_uid("01234", &uid);
- assert_se(r == 0);
- assert_se(uid == 1234);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("-0", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
+
+ r = parse_uid("+0", &uid);
+ assert_se(r == -EINVAL);
+ assert_se(uid == 100);
r = parse_uid("asdsdas", &uid);
assert_se(r == -EINVAL);
- assert_se(uid == 1234);
+ assert_se(uid == 100);
}
static void test_uid_ptr(void) {
--
2.23.0

View File

@ -0,0 +1,165 @@
From fc80cabcf584a8b486bdff5be0c074fec4059cdc Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Mon, 1 Jun 2020 17:31:51 +0200
Subject: [PATCH] parse-util: also parse integers prefixed with 0b and 0o
Let's adopt Python 3 style 0b and 0x syntaxes, because it makes a ton of
sense, in particular in bitmask settings.
Reference: https://github.com/systemd/systemd/commit/fc80cabcf584a8b486bdff5be0c074fec4059cdc
Conflict: Also include strv.h.
---
src/basic/parse-util.c | 57 ++++++++++++++++++++++++++++++++++++++----
1 file changed, 52 insertions(+), 5 deletions(-)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index b4c7f0d..bf56410 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -20,6 +20,7 @@
#include "process-util.h"
#include "stat-util.h"
#include "string-util.h"
+#include "strv.h"
int parse_boolean(const char *v) {
if (!v)
@@ -360,6 +361,32 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
return 0;
}
+static const char *mangle_base(const char *s, unsigned *base) {
+ const char *k;
+
+ assert(s);
+ assert(base);
+
+ /* Base already explicitly specified, then don't do anything. */
+ if (SAFE_ATO_MASK_FLAGS(*base) != 0)
+ return s;
+
+ /* Support Python 3 style "0b" and 0x" prefixes, because they truly make sense, much more than C's "0" prefix for octal. */
+ k = STARTSWITH_SET(s, "0b", "0B");
+ if (k) {
+ *base = 2 | (*base & SAFE_ATO_ALL_FLAGS);
+ return k;
+ }
+
+ k = STARTSWITH_SET(s, "0o", "0O");
+ if (k) {
+ *base = 8 | (*base & SAFE_ATO_ALL_FLAGS);
+ return k;
+ }
+
+ return s;
+}
+
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
char *x = NULL;
unsigned long l;
@@ -391,6 +418,8 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
return -EINVAL; /* This is particularly useful to avoid ambiguities between C's octal
* notation and assumed-to-be-decimal integers with a leading zero. */
+ s = mangle_base(s, &base);
+
errno = 0;
l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base) /* Let's mask off the flags bits so that only the actual
* base is left */);
@@ -410,13 +439,17 @@ int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
}
int safe_atoi(const char *s, int *ret_i) {
+ unsigned base = 0;
char *x = NULL;
long l;
assert(s);
+ s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtol(s, &x, 0);
+ l = strtol(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -451,6 +484,8 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
s[0] == '0' && s[1] != 0)
return -EINVAL;
+ s = mangle_base(s, &base);
+
errno = 0;
l = strtoull(s, &x, SAFE_ATO_MASK_FLAGS(base));
if (errno > 0)
@@ -467,13 +502,17 @@ int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu)
}
int safe_atolli(const char *s, long long int *ret_lli) {
+ unsigned base = 0;
char *x = NULL;
long long l;
assert(s);
+ s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtoll(s, &x, 0);
+ l = strtoll(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -486,15 +525,17 @@ int safe_atolli(const char *s, long long int *ret_lli) {
}
int safe_atou8(const char *s, uint8_t *ret) {
- char *x = NULL;
+ unsigned base = 0;
unsigned long l;
+ char *x = NULL;
assert(s);
s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
errno = 0;
- l = strtoul(s, &x, 0);
+ l = strtoul(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
@@ -530,6 +571,8 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
s[0] == '0' && s[1] != 0)
return -EINVAL;
+ s = mangle_base(s, &base);
+
errno = 0;
l = strtoul(s, &x, SAFE_ATO_MASK_FLAGS(base));
if (errno > 0)
@@ -548,13 +591,17 @@ int safe_atou16_full(const char *s, unsigned base, uint16_t *ret) {
}
int safe_atoi16(const char *s, int16_t *ret) {
+ unsigned base = 0;
char *x = NULL;
long l;
assert(s);
+ s += strspn(s, WHITESPACE);
+ s = mangle_base(s, &base);
+
errno = 0;
- l = strtol(s, &x, 0);
+ l = strtol(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)
--
2.23.0

View File

@ -16,7 +16,7 @@
Name: systemd
Url: https://www.freedesktop.org/wiki/Software/systemd
Version: 243
Release: 53
Release: 54
License: MIT and LGPLv2+ and GPLv2+
Summary: System and Service Manager
@ -156,6 +156,22 @@ Patch0108: backport-udevadm-fix-tag-match-help-description.patch
Patch0109: backport-fix-ConditionDirectoryNotEmpty-when-it-comes-to-a-No.patch
Patch0110: backport-fix-ConditionPathIsReadWrite-when-path-does-not-exis.patch
Patch0111: backport-fix-DirectoryNotEmpty-when-it-comes-to-a-Non-directo.patch
Patch0112: backport-0001-CVE-2020-13776-user-util-Allow-names-starting-with-a-digit.patch
Patch0113: backport-0002-CVE-2020-13776-user-util-switch-order-of-checks-in-valid_user_group.patch
Patch0114: backport-0003-CVE-2020-13776-user-util-rework-how-we-validate-user-names.patch
Patch0115: backport-0004-CVE-2020-13776-docs-add-a-longer-document-explaining-our-rules-on-u.patch
Patch0116: backport-0005-CVE-2020-13776-docs-hook-up-the-new-USER_NAMES-document-everywhere.patch
Patch0117: backport-0006-CVE-2020-13776-catalog-add-entry-for-SD_MESSAGE_UNSAFE_USER_NAME.patch
Patch0118: backport-0007-CVE-2020-13776-basic-user-util-always-use-base-10-for-user-group-nu.patch
Patch0119: backport-0008-CVE-2020-13776-parse-util-sometimes-it-is-useful-to-check-if-a-stri.patch
Patch0120: backport-0009-CVE-2020-13776-basic-parse-util-add-safe_atoux64.patch
Patch0121: backport-0010-CVE-2020-13776-parse-util-allow-tweaking-how-to-parse-integers.patch
Patch0122: backport-0011-CVE-2020-13776-parse-util-allow-0-as-alternative-to-0-and-0.patch
Patch0123: backport-0012-CVE-2020-13776-parse-util-make-return-parameter-optional-in-safe_at.patch
Patch0124: backport-0013-CVE-2020-13776-parse-util-rewrite-parse_mode-on-top-of-safe_atou_fu.patch
Patch0125: backport-0014-CVE-2020-13776-user-util-be-stricter-in-parse_uid.patch
Patch0126: backport-0015-CVE-2020-13776-parse-util-also-parse-integers-prefixed-with-0b-and-.patch
#openEuler
Patch9002: 1509-fix-journal-file-descriptors-leak-problems.patch
@ -1544,6 +1560,9 @@ fi
%exclude /usr/share/man/man3/*
%changelog
* Wed Feb 16 2021 yangmingtai <yangmingtai@huawei.com> - 243-54
- fix CVE-2020-13776
* Wed Jan 26 2021 yangmingtai <yangmingtai@huawei.com> - 243-53
- fix ConditionDirectoryNotEmpty,ConditionPathIsReadWrite and DirectoryNotEmpty