mirror of
https://github.com/systemd/systemd
synced 2024-07-21 10:17:21 +00:00
Look at /etc/login.defs for the system_max_[ug]id values
It makes little sense to make the boundary between systemd and user guids configurable. Nevertheless, a completely fixed compile-time define is not enough in two scenarios: - the systemd_uid_max boundary has moved over time. The default used to be 500 for a long time. Systems which are upgraded over time might have users in the wrong range, but changing existing systems is complicated and expensive (offline disks, backups, remote systems, read-only media, etc.) - systems are used in a heterogenous enviornment, where some vendors pick one value and others another. So let's make this boundary overridable using /etc/login.defs. Fixes #3855, #10184.
This commit is contained in:
parent
28add648a8
commit
53393c894d
|
@ -171,10 +171,11 @@ pick — given that 64K UIDs are assigned to each container according to this
|
||||||
allocation logic, the maximum UID used for this range is hence
|
allocation logic, the maximum UID used for this range is hence
|
||||||
1878982656+65535=1879048191.)
|
1878982656+65535=1879048191.)
|
||||||
|
|
||||||
Note that systemd does not make any of these values runtime-configurable. All
|
Systemd has compile-time default for these boundaries. Using those defaults is
|
||||||
these boundaries are chosen during build time. That said, the system UID/GID
|
recommended. It will nevertheless query `/etc/login.defs` at runtime, when
|
||||||
boundary is traditionally configured in /etc/login.defs, though systemd won't
|
compiled with `-Dcompat-mutable-uid-boundaries=true` and that file is present.
|
||||||
look there during runtime.
|
Support for this is considered only a compatibility feature and should not be
|
||||||
|
used except when upgrading systems which were creating with different defaults.
|
||||||
|
|
||||||
## Considerations for container managers
|
## Considerations for container managers
|
||||||
|
|
||||||
|
|
|
@ -1443,6 +1443,7 @@ foreach term : ['analyze',
|
||||||
'idn',
|
'idn',
|
||||||
'ima',
|
'ima',
|
||||||
'initrd',
|
'initrd',
|
||||||
|
'compat-mutable-uid-boundaries',
|
||||||
'ldconfig',
|
'ldconfig',
|
||||||
'localed',
|
'localed',
|
||||||
'logind',
|
'logind',
|
||||||
|
@ -3627,6 +3628,7 @@ foreach tuple : [
|
||||||
['libcurl'],
|
['libcurl'],
|
||||||
['idn'],
|
['idn'],
|
||||||
['initrd'],
|
['initrd'],
|
||||||
|
['compat-mutable-uid-boundaries'],
|
||||||
['libidn2'],
|
['libidn2'],
|
||||||
['libidn'],
|
['libidn'],
|
||||||
['libiptc'],
|
['libiptc'],
|
||||||
|
|
|
@ -28,9 +28,9 @@ option('static-libsystemd', type : 'combo',
|
||||||
description : '''install a static library for libsystemd''')
|
description : '''install a static library for libsystemd''')
|
||||||
option('static-libudev', type : 'combo',
|
option('static-libudev', type : 'combo',
|
||||||
choices : ['false', 'true', 'pic', 'no-pic'],
|
choices : ['false', 'true', 'pic', 'no-pic'],
|
||||||
description : '''install a static library for libudev''')
|
description : 'install a static library for libudev')
|
||||||
option('standalone-binaries', type : 'boolean', value : 'false',
|
option('standalone-binaries', type : 'boolean', value : 'false',
|
||||||
description : '''also build standalone versions of supported binaries''')
|
description : 'also build standalone versions of supported binaries')
|
||||||
|
|
||||||
option('sysvinit-path', type : 'string', value : '/etc/init.d',
|
option('sysvinit-path', type : 'string', value : '/etc/init.d',
|
||||||
description : 'the directory where the SysV init scripts are located')
|
description : 'the directory where the SysV init scripts are located')
|
||||||
|
@ -40,8 +40,10 @@ option('telinit-path', type : 'string', value : '/lib/sysvinit/telinit',
|
||||||
description : 'path to telinit')
|
description : 'path to telinit')
|
||||||
option('rc-local', type : 'string',
|
option('rc-local', type : 'string',
|
||||||
value : '/etc/rc.local')
|
value : '/etc/rc.local')
|
||||||
option('initrd', type: 'boolean',
|
option('initrd', type : 'boolean',
|
||||||
description : 'install services for use when running systemd in initrd')
|
description : 'install services for use when running systemd in initrd')
|
||||||
|
option('compat-mutable-uid-boundaries', type : 'boolean', value : 'false',
|
||||||
|
description : 'look at uid boundaries in /etc/login.defs for compatibility')
|
||||||
|
|
||||||
option('quotaon-path', type : 'string', description : 'path to quotaon')
|
option('quotaon-path', type : 'string', description : 'path to quotaon')
|
||||||
option('quotacheck-path', type : 'string', description : 'path to quotacheck')
|
option('quotacheck-path', type : 'string', description : 'path to quotacheck')
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include "cgroup-util.h"
|
#include "cgroup-util.h"
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
#include "env-util.h"
|
#include "env-util.h"
|
||||||
|
#include "fd-util.h"
|
||||||
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
|
@ -21,6 +23,100 @@
|
||||||
#define DEFAULT_RATELIMIT_BURST 30
|
#define DEFAULT_RATELIMIT_BURST 30
|
||||||
#define DEFAULT_RATELIMIT_INTERVAL_USEC (1*USEC_PER_MINUTE)
|
#define DEFAULT_RATELIMIT_INTERVAL_USEC (1*USEC_PER_MINUTE)
|
||||||
|
|
||||||
|
#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
|
||||||
|
static int parse_alloc_uid(const char *path, const char *name, const char *t, uid_t *ret_uid) {
|
||||||
|
uid_t uid;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = parse_uid(t, &uid);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "%s: failed to parse %s %s, ignoring: %m", path, name, t);
|
||||||
|
if (uid == 0)
|
||||||
|
uid = 1;
|
||||||
|
|
||||||
|
*ret_uid = uid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_login_defs(UGIDAllocationRange *ret_defs, const char *path) {
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
UGIDAllocationRange defs = {
|
||||||
|
.system_uid_max = SYSTEM_UID_MAX,
|
||||||
|
.system_gid_max = SYSTEM_GID_MAX,
|
||||||
|
};
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!path)
|
||||||
|
path = "/etc/login.defs";
|
||||||
|
|
||||||
|
r = fopen_unlocked(path, "re", &f);
|
||||||
|
if (r == -ENOENT)
|
||||||
|
goto assign;
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to open %s: %m", path);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *line = NULL;
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
r = read_line(f, LINE_MAX, &line);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to read %s: %m", path);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ((t = first_word(line, "SYS_UID_MAX")))
|
||||||
|
(void) parse_alloc_uid(path, "SYS_UID_MAX", t, &defs.system_uid_max);
|
||||||
|
else if ((t = first_word(line, "SYS_GID_MAX")))
|
||||||
|
(void) parse_alloc_uid(path, "SYS_GID_MAX", t, &defs.system_gid_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
assign:
|
||||||
|
*ret_defs = defs;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const UGIDAllocationRange *acquire_ugid_allocation_range(void) {
|
||||||
|
#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
|
||||||
|
static thread_local UGIDAllocationRange defs = {
|
||||||
|
#else
|
||||||
|
static const UGIDAllocationRange defs = {
|
||||||
|
#endif
|
||||||
|
.system_uid_max = SYSTEM_UID_MAX,
|
||||||
|
.system_gid_max = SYSTEM_GID_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES
|
||||||
|
/* This function will ignore failure to read the file, so it should only be called from places where
|
||||||
|
* we don't crucially depend on the answer. In other words, it's appropriate for journald, but
|
||||||
|
* probably not for sysusers. */
|
||||||
|
|
||||||
|
static thread_local bool initialized = false;
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
(void) read_login_defs(&defs, NULL);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return &defs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uid_is_system(uid_t uid) {
|
||||||
|
const UGIDAllocationRange *defs;
|
||||||
|
assert_se(defs = acquire_ugid_allocation_range());
|
||||||
|
|
||||||
|
return uid <= defs->system_uid_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gid_is_system(gid_t gid) {
|
||||||
|
const UGIDAllocationRange *defs;
|
||||||
|
assert_se(defs = acquire_ugid_allocation_range());
|
||||||
|
|
||||||
|
return gid <= defs->system_gid_max;
|
||||||
|
}
|
||||||
|
|
||||||
UserRecord* user_record_new(void) {
|
UserRecord* user_record_new(void) {
|
||||||
UserRecord *h;
|
UserRecord *h;
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,8 @@
|
||||||
/* The default disk size to use when nothing else is specified, relative to free disk space */
|
/* The default disk size to use when nothing else is specified, relative to free disk space */
|
||||||
#define USER_DISK_SIZE_DEFAULT_PERCENT 85
|
#define USER_DISK_SIZE_DEFAULT_PERCENT 85
|
||||||
|
|
||||||
static inline bool uid_is_system(uid_t uid) {
|
bool uid_is_system(uid_t uid);
|
||||||
return uid <= SYSTEM_UID_MAX;
|
bool gid_is_system(gid_t gid);
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool gid_is_system(gid_t gid) {
|
|
||||||
return gid <= SYSTEM_GID_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool uid_is_dynamic(uid_t uid) {
|
static inline bool uid_is_dynamic(uid_t uid) {
|
||||||
return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
|
return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX;
|
||||||
|
@ -41,6 +36,13 @@ static inline bool gid_is_container(gid_t gid) {
|
||||||
return uid_is_container((uid_t) gid);
|
return uid_is_container((uid_t) gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct UGIDAllocationRange {
|
||||||
|
uid_t system_uid_max;
|
||||||
|
gid_t system_gid_max;
|
||||||
|
} UGIDAllocationRange;
|
||||||
|
|
||||||
|
const UGIDAllocationRange *acquire_ugid_allocation_range(void);
|
||||||
|
|
||||||
typedef enum UserDisposition {
|
typedef enum UserDisposition {
|
||||||
USER_INTRINSIC, /* root and nobody */
|
USER_INTRINSIC, /* root and nobody */
|
||||||
USER_SYSTEM, /* statically allocated users for system services */
|
USER_SYSTEM, /* statically allocated users for system services */
|
||||||
|
|
|
@ -339,6 +339,10 @@ tests += [
|
||||||
[],
|
[],
|
||||||
[]],
|
[]],
|
||||||
|
|
||||||
|
[['src/test/test-user-record.c'],
|
||||||
|
[],
|
||||||
|
[]],
|
||||||
|
|
||||||
[['src/test/test-user-util.c'],
|
[['src/test/test-user-util.c'],
|
||||||
[],
|
[],
|
||||||
[]],
|
[]],
|
||||||
|
|
54
src/test/test-user-record.c
Normal file
54
src/test/test-user-record.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "format-util.h"
|
||||||
|
#include "tests.h"
|
||||||
|
#include "user-record.h"
|
||||||
|
|
||||||
|
static void test_acquire_ugid_allocation_range(void) {
|
||||||
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
|
const UGIDAllocationRange *defs;
|
||||||
|
assert_se(defs = acquire_ugid_allocation_range());
|
||||||
|
|
||||||
|
log_info("system_uid_max="UID_FMT, defs->system_uid_max);
|
||||||
|
log_info("system_gid_max="GID_FMT, defs->system_gid_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_uid_is_system(void) {
|
||||||
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
|
uid_t uid = 0;
|
||||||
|
log_info("uid_is_system("UID_FMT") = %s", uid, yes_no(uid_is_system(uid)));
|
||||||
|
|
||||||
|
uid = 999;
|
||||||
|
log_info("uid_is_system("UID_FMT") = %s", uid, yes_no(uid_is_system(uid)));
|
||||||
|
|
||||||
|
uid = getuid();
|
||||||
|
log_info("uid_is_system("UID_FMT") = %s", uid, yes_no(uid_is_system(uid)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_gid_is_system(void) {
|
||||||
|
log_info("/* %s */", __func__);
|
||||||
|
|
||||||
|
gid_t gid = 0;
|
||||||
|
log_info("gid_is_system("GID_FMT") = %s", gid, yes_no(gid_is_system(gid)));
|
||||||
|
|
||||||
|
gid = 999;
|
||||||
|
log_info("gid_is_system("GID_FMT") = %s", gid, yes_no(gid_is_system(gid)));
|
||||||
|
|
||||||
|
gid = getgid();
|
||||||
|
log_info("gid_is_system("GID_FMT") = %s", gid, yes_no(gid_is_system(gid)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
test_setup_logging(LOG_DEBUG);
|
||||||
|
|
||||||
|
test_acquire_ugid_allocation_range();
|
||||||
|
test_uid_is_system();
|
||||||
|
test_gid_is_system();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue