From 65796105a9c8d32e1c1fd65f56c34c38c384db14 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jul 2026 15:36:01 +0200 Subject: [PATCH 1/6] userdb: drop redundant check --- src/shared/userdb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/userdb.c b/src/shared/userdb.c index 14848150c5..7e028baf0a 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -1418,13 +1418,13 @@ static int groupdb_by_gid_fallbacks( assert(iterator); assert(ret); - if (!FLAGS_SET(flags, USERDB_EXCLUDE_DROPIN) && !(iterator && iterator->dropin_covered)) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_DROPIN) && !iterator->dropin_covered) { r = dropin_group_record_by_gid(gid, NULL, flags, ret); if (r >= 0) return r; } - if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && !(iterator && iterator->nss_covered)) { + if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && !iterator->nss_covered) { r = userdb_iterator_block_nss_systemd(iterator); if (r >= 0) { r = nss_group_record_by_gid(gid, !FLAGS_SET(flags, USERDB_SUPPRESS_SHADOW), ret); From 00a7b1d2d8d5de7548da69123832b913467235c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Jul 2026 15:35:38 +0200 Subject: [PATCH 2/6] userdb: suppress lookups outside of indicated ranges When doing a userdb lookup we might end up issuing a lot of IPC calls in parallel to backends and cause them all to do work, with us waiting for it. Let's optimize this a bit, and indicate on the socket inodes via xattrs hints which kind of records are provided by a backend. That way we can suppress lookups to them and optimize runtime behaviour. This only works on Linux 7.1 and newer where socket inodes gained support for extended attributes. --- docs/USER_GROUP_API.md | 31 ++++++ src/shared/userdb.c | 238 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 260 insertions(+), 9 deletions(-) diff --git a/docs/USER_GROUP_API.md b/docs/USER_GROUP_API.md index cf83f19f22..c4e187c666 100644 --- a/docs/USER_GROUP_API.md +++ b/docs/USER_GROUP_API.md @@ -327,6 +327,37 @@ Services which are asked for enumeration may return the `EnumerationNotSupported And that's really all there is to it. +## Reducing IPC Requests + +In many cases backends are only interested in responding to certain UID/GID +ranges, or only to user/group names matching a specific pattern. To optimize +look-ups in this case it is possible to indicate on the Varlink entrypoint +socket inode of the service which ranges or patterns these are: if the kernel +supports extended attributes on socket inodes (Linux >= 7.1), the following +extended attributes may be set: + +* `user.userdb.uid` takes a comma separated list of UIDs or dash-separated UID + range pairs. If set, then the service will not be contacted for any UID + look-ups outside of this range. Example: setting the extended attribute to + `61184-65519,524288-1879048191,4711` will have the effect that a lookup for + UID 1051 will not be attempted against this service, but one for 62334 will be. + +* `user.userdb.gid` is similar, but for GIDs and GID ranges. + +* `user.userdb.username` takes a NUL separated list of `fnmatch()` style glob + expressions. If set only look-ups for user names matching at least one of + these expressions will be routed to this service. Example: setting the + extended attribute to `foo-*\0www*h?` (where `\0` shall indicate the NUL + byte) will route only look-ups for `foo-bar` and `wwwooosh7` to this service, + but not `waldo`. + +* `user.userdb.groupname` is similar, but for group names. + +Note that these extended attributes are intended for optimization only: any +backend *must* be prepared to answer look-ups for any UID, GID, user and group +name, and respond with `NoRecordFound` for requests outside of the +ranges/patterns defined this way. + ## Command Line Access For command line access you can use the diff --git a/src/shared/userdb.c b/src/shared/userdb.c index 7e028baf0a..7dd9ac7496 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include #include @@ -18,6 +19,7 @@ #include "log.h" #include "parse-util.h" #include "set.h" +#include "socket-util.h" #include "string-util.h" #include "strv.h" #include "uid-classification.h" @@ -25,6 +27,7 @@ #include "user-util.h" #include "userdb.h" #include "userdb-dropin.h" +#include "xattr-util.h" DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(link_hash_ops, void, trivial_hash_func, trivial_compare_func, sd_varlink, sd_varlink_unref); @@ -35,6 +38,14 @@ typedef enum LookupWhat { _LOOKUP_WHAT_MAX, } LookupWhat; +typedef struct SocketFilter { + /* Restricts the sockets to connect to */ + uid_t uid; + gid_t gid; + const char *username; + const char *groupname; +} SocketFilter; + struct UserDBIterator { LookupWhat what; UserDBFlags flags; @@ -505,11 +516,138 @@ static int userdb_connect( return r; } +static int socket_filter_id_test( + id_t id, + const char *xattr, + int dir_fd, + const char *fname, + const char *full_path /* for logging only */) { + + int r; + + assert(xattr); + assert(dir_fd >= 0); + assert(fname); + assert(full_path); + + /* Generic implementation for both UIDs and GIDs */ + + if (!uid_is_valid(id)) + return true; + + /* Looks for an xattr of the specified name on the referenced socket entrypoint inode. Parses this + * as a pair of start UID/end UID. Matches the specified UID against it. If it matches yay. If it + * doesn't nay. If no UID is specified or no xattr set, also yay. */ + + _cleanup_free_ char *t = NULL; + r = getxattr_at_malloc(dir_fd, fname, xattr, AT_SYMLINK_FOLLOW, &t, /* ret_size= */ NULL); + if (r == -ENODATA) + return true; /* no such xattr? match! */ + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) { + log_debug_errno(r, "Extended attributes on sockets not supported after all, ignoring: %m"); + return true; /* if sockets don't support xattrs here, then this is a match */ + } + if (r < 0) + return log_debug_errno(r, "Unexpected error while reading extended attribute '%s' of '%s', ignoring: %m", xattr, full_path); + + _cleanup_strv_free_ char **l = strv_split(t, ","); + if (!l) + return log_oom_debug(); + + STRV_FOREACH(i, l) { + /* Single UID or UID range */ + uid_t x, y; + r = parse_uid_range(*i, &x, &y); + if (r < 0) + return log_debug_errno(r, "Malformed extended attribute '%s' on '%s', ignoring.", xattr, full_path); + + if (id >= x && id <= y) + return true; + } + + return false; +} + +static int socket_filter_name_test( + const char *name, + const char *xattr, + int dir_fd, + const char *fname, + const char *full_path /* for logging only */) { + + int r; + + assert(xattr); + assert(dir_fd >= 0); + assert(fname); + assert(full_path); + + /* Looks for an xattr of the specified name on the referenced socket entrypoint inode. Parses this + * as a NUL terminated string list. Matches the specified name against it via fnmatch(). If it matches + * yay. If it doesn't nay. If no name is specified or no xattr set, also yay. */ + + if (!name) + return true; + + _cleanup_strv_free_ char **l = NULL; + r = getxattr_at_strv(dir_fd, fname, xattr, AT_SYMLINK_FOLLOW, &l); + if (r == -ENODATA) + return true; /* no such xattr? match! */ + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) { + log_debug_errno(r, "Extended attributes on sockets not supported after all, ignoring: %m"); + return true; /* if sockets don't support xattrs here, then this is a match */ + } + if (r < 0) + return log_debug_errno(r, "Unexpected error while reading extended attribute '%s' of '%s', ignoring: %m", xattr, full_path); + + return strv_fnmatch_full(l, name, FNM_NOESCAPE, /* ret_matched_pos= */ NULL); +} + +static int socket_filter_test( + const SocketFilter *sfilter, + int dir_fd, + const char *fname, + const char *full_path /* for logging only */) { + + assert(dir_fd >= 0); + assert(fname); + assert(full_path); + + /* Before we contact a Varlink service, let's see if there's any chance it might answer our questions + * at all. For such pre-filtering a userdb backend can install xattrs on their entrypoint inode to + * indicate that it's never going to answer outside of a certain UID/GID range or username/groupname + * pattern */ + + /* No filter means all sockets match */ + if (!sfilter) + return 1; + + /* No xattr support? then all sockets match. This check mostly exists to take benefit of the internal caching + * of the test. Either way we'll check below again. */ + if (socket_xattr_supported() == 0) + return 1; + + if (socket_filter_id_test(sfilter->uid, "user.userdb.uid", dir_fd, fname, full_path) == 0) + return 0; + + if (socket_filter_id_test(sfilter->gid, "user.userdb.gid", dir_fd, fname, full_path) == 0) + return 0; + + if (socket_filter_name_test(sfilter->username, "user.userdb.username", dir_fd, fname, full_path) == 0) + return 0; + + if (socket_filter_name_test(sfilter->groupname, "user.userdb.groupname", dir_fd, fname, full_path) == 0) + return 0; + + return 1; +} + static int userdb_start_query( UserDBIterator *iterator, const char *method, /* must be a static string, we are not going to copy this here! */ bool more, sd_json_variant *query, + const SocketFilter *sfilter, UserDBFlags flags) { _cleanup_strv_free_ char **except = NULL, **only = NULL; @@ -601,6 +739,12 @@ static int userdb_start_query( if (!p) return -ENOMEM; + r = socket_filter_test(sfilter, dirfd(d), de->d_name, p); + if (r < 0) + log_debug_errno(r, "Failed to filter sockets, ignoring: %m"); + else if (r == 0) + continue; + r = userdb_connect(iterator, p, method, more, query); if (is_nss && r >= 0) /* Turn off fallback NSS + dropin if we found the NSS/dropin service * and could connect to it */ @@ -928,8 +1072,20 @@ int userdb_by_name(const char *name, const UserDBMatch *match, UserDBFlags flags if (!iterator) return -ENOMEM; + SocketFilter sfilter = { + .uid = UID_INVALID, + .gid = GID_INVALID, + .username = name, + }; + _cleanup_(user_record_unrefp) UserRecord *ur = NULL; - r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", /* more= */ false, query, flags); + r = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetUserRecord", + /* more= */ false, + query, + &sfilter, + flags); if (r >= 0) { r = userdb_process(iterator, &ur, /* ret_group_record= */ NULL, /* ret_user_name= */ NULL, /* ret_group_name= */ NULL); if (r == -ENOEXEC) /* Found a user matching UID or name, but not filter. In this case the @@ -1018,8 +1174,19 @@ int userdb_by_uid(uid_t uid, const UserDBMatch *match, UserDBFlags flags, UserRe if (!iterator) return -ENOMEM; + SocketFilter sfilter = { + .uid = uid, + .gid = GID_INVALID, + }; + _cleanup_(user_record_unrefp) UserRecord *ur = NULL; - r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", /* more= */ false, query, flags); + r = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetUserRecord", + /* more= */ false, + query, + &sfilter, + flags); if (r >= 0) { r = userdb_process(iterator, &ur, /* ret_group_record= */ NULL, /* ret_user_name= */ NULL, /* ret_group_name= */ NULL); if (r == -ENOEXEC) @@ -1055,7 +1222,13 @@ int userdb_all(const UserDBMatch *match, UserDBFlags flags, UserDBIterator **ret if (!iterator) return -ENOMEM; - qr = userdb_start_query(iterator, "io.systemd.UserDatabase.GetUserRecord", /* more= */ true, query, flags); + qr = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetUserRecord", + /* more= */ true, + query, + /* sfilter= */ NULL, + flags); if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (qr < 0 || !iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); @@ -1384,8 +1557,20 @@ int groupdb_by_name(const char *name, const UserDBMatch *match, UserDBFlags flag if (!iterator) return -ENOMEM; + SocketFilter sfilter = { + .uid = UID_INVALID, + .gid = GID_INVALID, + .groupname = name, + }; + _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; - r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", /* more= */ false, query, flags); + r = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetGroupRecord", + /* more= */ false, + query, + &sfilter, + flags); if (r >= 0) { r = userdb_process(iterator, /* ret_user_record= */ NULL, &gr, /* ret_user_name= */ NULL, /* ret_group_name= */ NULL); if (r == -ENOEXEC) @@ -1470,8 +1655,19 @@ int groupdb_by_gid(gid_t gid, const UserDBMatch *match, UserDBFlags flags, Group if (!iterator) return -ENOMEM; + SocketFilter sfilter = { + .uid = UID_INVALID, + .gid = gid, + }; + _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; - r = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", /* more= */ false, query, flags); + r = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetGroupRecord", + /* more= */ false, + query, + &sfilter, + flags); if (r >= 0) { r = userdb_process(iterator, /* ret_user_record= */ NULL, &gr, /* ret_user_name= */ NULL, /* ret_group_name= */ NULL); if (r == -ENOEXEC) @@ -1507,7 +1703,13 @@ int groupdb_all(const UserDBMatch *match, UserDBFlags flags, UserDBIterator **re if (!iterator) return -ENOMEM; - qr = userdb_start_query(iterator, "io.systemd.UserDatabase.GetGroupRecord", /* more= */ true, query, flags); + qr = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetGroupRecord", + /* more= */ true, + query, + /* sfilter= */ NULL, + flags); if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (qr < 0 || !iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); @@ -1698,7 +1900,13 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r if (!iterator->filter_user_name) return -ENOMEM; - qr = userdb_start_query(iterator, "io.systemd.UserDatabase.GetMemberships", true, query, flags); + qr = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetMemberships", + /* more= */ true, + query, + /* sfilter= */ NULL, + flags); if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (qr < 0 || !iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); @@ -1743,7 +1951,13 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator ** if (!iterator->filter_group_name) return -ENOMEM; - qr = userdb_start_query(iterator, "io.systemd.UserDatabase.GetMemberships", true, query, flags); + qr = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetMemberships", + /* more= */ true, + query, + /* sfilter= */ NULL, + flags); if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (qr < 0 || !iterator->nss_covered)) { _cleanup_(group_record_unrefp) GroupRecord *gr = NULL; @@ -1789,7 +2003,13 @@ int membershipdb_all(UserDBFlags flags, UserDBIterator **ret) { if (!iterator) return -ENOMEM; - qr = userdb_start_query(iterator, "io.systemd.UserDatabase.GetMemberships", true, NULL, flags); + qr = userdb_start_query( + iterator, + "io.systemd.UserDatabase.GetMemberships", + /* more= */ true, + /* query= */ NULL, + /* sfilter= */ NULL, + flags); if (!FLAGS_SET(flags, USERDB_EXCLUDE_NSS) && (qr < 0 || !iterator->nss_covered)) { r = userdb_iterator_block_nss_systemd(iterator); From 845786f60b1cc045e2f56ddc2710ad152f1f3828 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jul 2026 06:31:30 +0200 Subject: [PATCH 3/6] core: tag dynamic user userdb provider with dynamic uid/gid ranges Let's optimize lookups to PID 1's dynamic UID/GID range feature. --- src/core/varlink.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/core/varlink.c b/src/core/varlink.c index fa6a5e1565..79a198f14d 100644 --- a/src/core/varlink.c +++ b/src/core/varlink.c @@ -4,12 +4,14 @@ #include "constants.h" #include "errno-util.h" +#include "format-util.h" #include "job.h" #include "json-util.h" #include "manager.h" #include "metrics.h" #include "path-util.h" #include "pidref.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "unit.h" @@ -27,6 +29,7 @@ #include "varlink-serialize.h" #include "varlink-unit.h" #include "varlink-util.h" +#include "xattr-util.h" static const char* const managed_oom_mode_properties[] = { "ManagedOOMSwap", @@ -481,10 +484,14 @@ int manager_setup_varlink_metrics_server(Manager *m) { if (MANAGER_IS_SYSTEM(m)) flags |= SD_VARLINK_SERVER_ACCOUNT_UID; - return metrics_setup_varlink_server(&m->metrics_varlink_server, flags, - m->event, EVENT_PRIORITY_IPC, - vl_method_list_metrics, vl_method_describe_metrics, - m); + return metrics_setup_varlink_server( + &m->metrics_varlink_server, + flags, + m->event, + EVENT_PRIORITY_IPC, + vl_method_list_metrics, + vl_method_describe_metrics, + m); } static int varlink_server_listen_many_idempotent_sentinel( @@ -549,6 +556,12 @@ static int manager_varlink_init_system_api(Manager *m) { VARLINK_PATH_MANAGED_OOM_SYSTEM); if (r < 0) return r; + + /* Reduce the noise routed to us: advertise that only look-ups for the dynamic UID range should go to us */ + char text[DECIMAL_STR_MAX(uid_t) + 1 + DECIMAL_STR_MAX(gid_t) + 1]; + xsprintf(text, UID_FMT "-" UID_FMT, (uid_t) DYNAMIC_UID_MIN, (uid_t) DYNAMIC_UID_MAX); + FOREACH_STRING(xattr, "user.userdb.uid", "user.userdb.gid") + (void) xsetxattr(AT_FDCWD, "/run/systemd/userdb/io.systemd.DynamicUser", /* at_flags= */ 0, xattr, text); } return 0; From e3876f7559252ba6fb7581c9f6649ddd180422e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jul 2026 09:07:49 +0200 Subject: [PATCH 4/6] homed: set user.userdb xattrs on homed's userdb socket We can't make a lot of restrictions here, since users are allowed to basically freely pick their user names and UIDs too. But let's at least exclude system UID ranges and those beyond the 16bit range. --- src/home/homed-manager.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index b949c4b8fd..a19dc3f6c8 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -65,6 +65,7 @@ #include "varlink-io.systemd.UserDatabase.h" #include "varlink-io.systemd.service.h" #include "varlink-util.h" +#include "xattr-util.h" /* Where to look for private/public keys that are used to sign the user records. We are not using * CONF_PATHS_NULSTR() here since we want to insert /var/lib/systemd/home/ in the middle. And we insert that @@ -1102,6 +1103,13 @@ static int manager_bind_varlink(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to bind to varlink socket '%s': %m", socket_path); + /* Reduce the noise routed to us: advertise that only look-ups for non-system users in the 16bit + * range are routed to us (excluding 'nobody', i.e. 0xfffe) */ + char text[DECIMAL_STR_MAX(uid_t) + 1 + DECIMAL_STR_MAX(gid_t) + 1]; + xsprintf(text, UID_FMT "-" UID_FMT, (uid_t) (SYSTEM_UID_MAX + 1), UID_NOBODY - 1); + FOREACH_STRING(xattr, "user.userdb.uid", "user.userdb.gid") + (void) xsetxattr(AT_FDCWD, socket_path, /* at_flags= */ 0, xattr, text); + r = sd_varlink_server_attach_event(m->varlink_server, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); From 33b2db3c8f819f5e6067aaebb81d957a1d644346 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jul 2026 09:09:13 +0200 Subject: [PATCH 5/6] machined: set user.userdb.* xattrs on machined socket --- src/machine/machined-varlink.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c index acc2137f83..b136ccf2a2 100644 --- a/src/machine/machined-varlink.c +++ b/src/machine/machined-varlink.c @@ -31,6 +31,7 @@ #include "varlink-io.systemd.Resolve.Hook.h" #include "varlink-io.systemd.service.h" #include "varlink-util.h" +#include "xattr-util.h" typedef struct LookupParameters { const char *user_name; @@ -774,6 +775,14 @@ static int manager_varlink_init_userdb(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to bind to varlink socket %s: %m", VARLINK_PATH_MACHINED_USERDB); + /* Reduce the noise routed to us: advertise that only look-ups for the higher UID range */ + char text[DECIMAL_STR_MAX(uid_t) + 1 + DECIMAL_STR_MAX(gid_t) + 1]; + xsprintf(text, UID_FMT "-" UID_FMT, (uid_t) 0x10000U, (uid_t) UINT32_C(0xfffffffe)); + FOREACH_STRING(xattr, "user.userdb.uid", "user.userdb.gid") + (void) xsetxattr(AT_FDCWD, VARLINK_PATH_MACHINED_USERDB, /* at_flags= */ 0, xattr, text); + (void) xsetxattr(AT_FDCWD, VARLINK_PATH_MACHINED_USERDB, /* at_flags= */ 0, "user.userdb.username", "vu-*"); + (void) xsetxattr(AT_FDCWD, VARLINK_PATH_MACHINED_USERDB, /* at_flags= */ 0, "user.userdb.groupname", "vg-*"); + r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) return log_error_errno(r, "Failed to attach varlink connection to event loop: %m"); From 649ab380e1de1e6e643fe12af20d3d5f1b353897 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jul 2026 09:13:34 +0200 Subject: [PATCH 6/6] nresourced: add user.userbd.* xattrs to nsresourced userdb socket --- src/nsresourced/nsresourced-manager.c | 12 ++++++++++++ units/meson.build | 2 +- ...esourced.socket => systemd-nsresourced.socket.in} | 4 ++++ 3 files changed, 17 insertions(+), 1 deletion(-) rename units/{systemd-nsresourced.socket => systemd-nsresourced.socket.in} (72%) diff --git a/src/nsresourced/nsresourced-manager.c b/src/nsresourced/nsresourced-manager.c index 4e671de833..df12e352b0 100644 --- a/src/nsresourced/nsresourced-manager.c +++ b/src/nsresourced/nsresourced-manager.c @@ -33,10 +33,12 @@ #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "uid-classification.h" #include "umask-util.h" #include "unaligned.h" #include "userns-registry.h" #include "userns-restrict.h" +#include "xattr-util.h" #define LISTEN_TIMEOUT_USEC (25 * USEC_PER_SEC) @@ -450,6 +452,16 @@ static int manager_make_listen_socket(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to symlink userdb socket: %m"); + /* Reduce the noise routed to us: advertise that only look-ups for the higher UID range */ + char text[2 * (DECIMAL_STR_MAX(uid_t) + 1 + DECIMAL_STR_MAX(uid_t) + 1)]; + xsprintf(text, UID_FMT "-" UID_FMT "," UID_FMT "-" UID_FMT, + CONTAINER_UID_MIN, CONTAINER_UID_MAX, + (uid_t) DYNAMIC_UID_MIN, (uid_t) DYNAMIC_UID_MAX); + FOREACH_STRING(xattr, "user.userdb.uid", "user.userdb.gid") + (void) xsetxattr(AT_FDCWD, sockaddr.un.sun_path, /* at_flags= */ 0, xattr, text); + (void) xsetxattr(AT_FDCWD, sockaddr.un.sun_path, /* at_flags= */ 0, "user.userdb.username", "ns-*"); + (void) xsetxattr(AT_FDCWD, sockaddr.un.sun_path, /* at_flags= */ 0, "user.userdb.groupname", "ns-*"); + if (listen(m->listen_fd, SOMAXCONN) < 0) return log_error_errno(errno, "Failed to listen on socket: %m"); diff --git a/units/meson.build b/units/meson.build index ca50475ebe..c07e5712b0 100644 --- a/units/meson.build +++ b/units/meson.build @@ -1040,7 +1040,7 @@ units = [ 'conditions' : ['ENABLE_NSRESOURCED'], }, { - 'file' : 'systemd-nsresourced.socket', + 'file' : 'systemd-nsresourced.socket.in', 'conditions' : ['ENABLE_NSRESOURCED'], }, { diff --git a/units/systemd-nsresourced.socket b/units/systemd-nsresourced.socket.in similarity index 72% rename from units/systemd-nsresourced.socket rename to units/systemd-nsresourced.socket.in index 2840be43e2..3798b9a1e4 100644 --- a/units/systemd-nsresourced.socket +++ b/units/systemd-nsresourced.socket.in @@ -22,6 +22,10 @@ FileDescriptorName=varlink SocketMode=0666 XAttrEntryPoint=user.varlink=entrypoint XAttrListen=user.varlink=listen +XAttrEntryPoint=user.userdb.uid={{DYNAMIC_UID_MIN}}-{{DYNAMIC_UID_MAX}},{{CONTAINER_UID_BASE_MIN}}-{{CONTAINER_UID_BASE_MAX+65535}} +XAttrEntryPoint=user.userdb.gid={{DYNAMIC_UID_MIN}}-{{DYNAMIC_UID_MAX}},{{CONTAINER_UID_BASE_MIN}}-{{CONTAINER_UID_BASE_MAX+65535}} +XAttrEntryPoint=user.userdb.username=ns-* +XAttrEntryPoint=user.userdb.groupname=ns-* [Install] WantedBy=sockets.target