[Buildroot] [PATCH v2 11/14] package/systemd: use an upstream patch for tmpfiles
Norbert Lange
nolange79 at gmail.com
Mon Jun 15 07:20:51 UTC 2020
running systemd-tmpfiles will currently use the hosts
user/group uids, even when specifying --root=.
The next systemd release v245 will include this change.
Signed-off-by: Norbert Lange <nolange79 at gmail.com>
---
...e-rootfs-database-for-tmpfiles.patch.patch | 300 ++++++++++++++++++
1 file changed, 300 insertions(+)
create mode 100644 package/systemd/0001-use-rootfs-database-for-tmpfiles.patch.patch
diff --git a/package/systemd/0001-use-rootfs-database-for-tmpfiles.patch.patch b/package/systemd/0001-use-rootfs-database-for-tmpfiles.patch.patch
new file mode 100644
index 0000000000..5847bbd673
--- /dev/null
+++ b/package/systemd/0001-use-rootfs-database-for-tmpfiles.patch.patch
@@ -0,0 +1,300 @@
+From ab5b7df682c9e779e859a9caf9c2012d3db92dc3 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart at poettering.net>
+Date: Tue, 5 May 2020 22:45:54 +0200
+Subject: [PATCH 1/3] tmpfiles: optionally, read /etc/passwd + /etc/group
+ without NSS
+
+There are two libc APIs for accessing the user database: NSS/getpwuid(),
+and fgetpwent(). if we run in --root= mode (i.e. "offline" mode), let's
+use the latter. Otherwise the former. This means tmpfiles can use the
+database included in the root environment for chowning, which is a lot
+more appropriate.
+
+Fixes: #14806
+Signed-off-by: Norbert Lange <nolange79 at gmail.com>
+
+---
+ src/tmpfiles/tmpfiles.c | 145 +++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 137 insertions(+), 8 deletions(-)
+
+diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
+index 7137e9fbd72..6ece1b5ed16 100644
+--- a/src/tmpfiles/tmpfiles.c
++++ b/src/tmpfiles/tmpfiles.c
+@@ -2487,7 +2487,139 @@ static int patch_var_run(const char *fname, unsigned line, char **path) {
+ return 0;
+ }
+
+-static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
++DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(uid_gid_hash_ops, char, string_hash_func, string_compare_func, free);
++
++static int find_uid(const char *user, uid_t *ret_uid, Hashmap **cache) {
++ void *found;
++ int r;
++
++ assert(user);
++ assert(ret_uid);
++ assert(cache);
++
++ /* First: parse as numeric UID string */
++ r = parse_uid(user, ret_uid);
++ if (r >= 0)
++ return r;
++
++ /* Second: pass to NSS if we are running "online" */
++ if (!arg_root)
++ return get_user_creds(&user, ret_uid, NULL, NULL, NULL, 0);
++
++ /* Third: use fgetpwent() to read /etc/passwd directly, if we are "offline" */
++ if (!*cache) {
++ _cleanup_(hashmap_freep) Hashmap *uid_by_name = NULL;
++ _cleanup_fclose_ FILE *f = NULL;
++ struct passwd *pw;
++ const char *passwd_path;
++
++ passwd_path = prefix_roota(arg_root, "/etc/passwd");
++ f = fopen(passwd_path, "re");
++ if (!f)
++ return errno == ENOENT ? -ESRCH : -errno;
++
++ uid_by_name = hashmap_new(&uid_gid_hash_ops);
++ if (!uid_by_name)
++ return -ENOMEM;
++
++ while ((r = fgetpwent_sane(f, &pw)) > 0) {
++ _cleanup_free_ char *n = NULL;
++
++ n = strdup(pw->pw_name);
++ if (!n)
++ return -ENOMEM;
++
++ r = hashmap_put(uid_by_name, n, UID_TO_PTR(pw->pw_uid));
++ if (r == -EEXIST) {
++ log_warning_errno(r, "Duplicate entry in %s for %s: %m", passwd_path, pw->pw_name);
++ continue;
++ }
++ if (r < 0)
++ return r;
++
++ TAKE_PTR(n);
++ }
++
++ *cache = TAKE_PTR(uid_by_name);
++ }
++
++ found = hashmap_get(*cache, user);
++ if (!found)
++ return -ESRCH;
++
++ *ret_uid = PTR_TO_UID(found);
++ return 0;
++}
++
++static int find_gid(const char *group, gid_t *ret_gid, Hashmap **cache) {
++ void *found;
++ int r;
++
++ assert(group);
++ assert(ret_gid);
++ assert(cache);
++
++ /* First: parse as numeric GID string */
++ r = parse_gid(group, ret_gid);
++ if (r >= 0)
++ return r;
++
++ /* Second: pass to NSS if we are running "online" */
++ if (!arg_root)
++ return get_group_creds(&group, ret_gid, 0);
++
++ /* Third: use fgetgrent() to read /etc/group directly, if we are "offline" */
++ if (!*cache) {
++ _cleanup_(hashmap_freep) Hashmap *gid_by_name = NULL;
++ _cleanup_fclose_ FILE *f = NULL;
++ struct group *gr;
++ const char *group_path;
++
++ group_path = prefix_roota(arg_root, "/etc/group");
++ f = fopen(group_path, "re");
++ if (!f)
++ return errno == ENOENT ? -ESRCH : -errno;
++
++ gid_by_name = hashmap_new(&uid_gid_hash_ops);
++ if (!gid_by_name)
++ return -ENOMEM;
++
++ while ((r = fgetgrent_sane(f, &gr)) > 0) {
++ _cleanup_free_ char *n = NULL;
++
++ n = strdup(gr->gr_name);
++ if (!n)
++ return -ENOMEM;
++
++ r = hashmap_put(gid_by_name, n, GID_TO_PTR(gr->gr_gid));
++ if (r == -EEXIST) {
++ log_warning_errno(r, "Duplicate entry in %s for %s: %m", group_path, gr->gr_name);
++ continue;
++ }
++ if (r < 0)
++ return r;
++
++ TAKE_PTR(n);
++ }
++
++ *cache = TAKE_PTR(gid_by_name);
++ }
++
++ found = hashmap_get(*cache, group);
++ if (!found)
++ return -ESRCH;
++
++ *ret_gid = PTR_TO_GID(found);
++ return 0;
++}
++
++static int parse_line(
++ const char *fname,
++ unsigned line,
++ const char *buffer,
++ bool *invalid_config,
++ Hashmap **uid_cache,
++ Hashmap **gid_cache) {
+
+ _cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
+ _cleanup_(item_free_contents) Item i = {};
+@@ -2718,9 +2850,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
+ }
+
+ if (!empty_or_dash(user)) {
+- const char *u = user;
+-
+- r = get_user_creds(&u, &i.uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
++ r = find_uid(user, &i.uid, uid_cache);
+ if (r < 0) {
+ *invalid_config = true;
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", user);
+@@ -2730,9 +2860,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
+ }
+
+ if (!empty_or_dash(group)) {
+- const char *g = group;
+-
+- r = get_group_creds(&g, &i.gid, USER_CREDS_ALLOW_MISSING);
++ r = find_gid(group, &i.gid, gid_cache);
+ if (r < 0) {
+ *invalid_config = true;
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s'.", group);
+@@ -2981,6 +3109,7 @@ static int parse_argv(int argc, char *argv[]) {
+ }
+
+ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
++ _cleanup_(hashmap_freep) Hashmap *uid_cache = NULL, *gid_cache = NULL;
+ _cleanup_fclose_ FILE *_f = NULL;
+ Iterator iterator;
+ unsigned v = 0;
+@@ -3026,7 +3155,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
+ if (IN_SET(*l, 0, '#'))
+ continue;
+
+- k = parse_line(fn, v, l, &invalid_line);
++ k = parse_line(fn, v, l, &invalid_line, &uid_cache, &gid_cache);
+ if (k < 0) {
+ if (invalid_line)
+ /* Allow reporting with a special code if the caller requested this */
+
+From cc0ff79bd0f94336fc53407da7a20ff3c779456f Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart at poettering.net>
+Date: Tue, 5 May 2020 22:48:50 +0200
+Subject: [PATCH 2/3] sysusers/tmpfiles: use --root=/ as way to force offline
+ operation (i.e. without NSS)
+
+---
+ src/sysusers/sysusers.c | 2 +-
+ src/tmpfiles/tmpfiles.c | 10 ++++++----
+ 2 files changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
+index a36cfb210f6..9b57f0f933a 100644
+--- a/src/sysusers/sysusers.c
++++ b/src/sysusers/sysusers.c
+@@ -1813,7 +1813,7 @@ static int parse_argv(int argc, char *argv[]) {
+ break;
+
+ case ARG_ROOT:
+- r = parse_path_argument_and_warn(optarg, true, &arg_root);
++ r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
+ if (r < 0)
+ return r;
+ break;
+diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
+index 6ece1b5ed16..dc1dd89aecc 100644
+--- a/src/tmpfiles/tmpfiles.c
++++ b/src/tmpfiles/tmpfiles.c
+@@ -2741,7 +2741,7 @@ static int parse_line(
+
+ case COPY_FILES:
+ if (!i.argument) {
+- i.argument = path_join(arg_root, "/usr/share/factory", i.path);
++ i.argument = path_join("/usr/share/factory", i.path);
+ if (!i.argument)
+ return log_oom();
+
+@@ -2749,7 +2749,9 @@ static int parse_line(
+ *invalid_config = true;
+ return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EBADMSG), "Source path '%s' is not absolute.", i.argument);
+
+- } else if (arg_root) {
++ }
++
++ if (!empty_or_root(arg_root)) {
+ char *p;
+
+ p = path_join(arg_root, i.argument);
+@@ -2840,7 +2842,7 @@ static int parse_line(
+ return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to substitute specifiers in argument: %m");
+ }
+
+- if (arg_root) {
++ if (!empty_or_root(arg_root)) {
+ char *p;
+
+ p = path_join(arg_root, i.path);
+@@ -3068,7 +3070,7 @@ static int parse_argv(int argc, char *argv[]) {
+ break;
+
+ case ARG_ROOT:
+- r = parse_path_argument_and_warn(optarg, true, &arg_root);
++ r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root);
+ if (r < 0)
+ return r;
+ break;
+
+From 4ae0e6b69fff5ed93ec2762bc40ea59f69c68a93 Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart at poettering.net>
+Date: Tue, 5 May 2020 23:23:00 +0200
+Subject: [PATCH 3/3] man: document the new tmpfiles --root= behaviour
+ regarding users
+
+---
+ man/systemd-tmpfiles.xml | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml
+index 7720ef53fa1..998fd0911ba 100644
+--- a/man/systemd-tmpfiles.xml
++++ b/man/systemd-tmpfiles.xml
+@@ -161,10 +161,10 @@
+ <listitem><para>Takes a directory path as an argument. All paths will be prefixed with the given alternate
+ <replaceable>root</replaceable> path, including config search paths.</para>
+
+- <para>Note that this option does not alter how the users and groups specified in the configuration files are
+- resolved. With or without this option, users and groups are always resolved according to the host's user and
+- group databases, any such databases stored under the specified root directories are not
+- consulted.</para></listitem>
++ <para>When this option is used, the libc Name Service Switch (NSS) is bypassed for resolving users
++ and groups. Instead the files <filename>/etc/passwd</filename> and <filename>/etc/group</filename>
++ inside the alternate root are read directly. This means that users/groups not listed in these files
++ will not be resolved, i.e. LDAP NIS and other complex databases are not considered.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
--
2.27.0
More information about the buildroot
mailing list