diff --git a/meson.build b/meson.build index 8083cf655b..0a065fa3e5 100644 --- a/meson.build +++ b/meson.build @@ -694,35 +694,31 @@ if time_epoch == -1 endif conf.set('TIME_EPOCH', time_epoch) -system_uid_max = get_option('system-uid-max') -if system_uid_max == -1 - system_uid_max = run_command( - awk, - '/^\s*SYS_UID_MAX\s+/ { uid=$2 } END { print uid }', - '/etc/login.defs').stdout().strip() - if system_uid_max == '' - system_uid_max = 999 - else - system_uid_max = system_uid_max.to_int() +foreach tuple : [['system-alloc-uid-min', 'SYS_UID_MIN', 1], # Also see login.defs(5). + ['system-uid-max', 'SYS_UID_MAX', 999], + ['system-alloc-gid-min', 'SYS_GID_MIN', 1], + ['system-gid-max', 'SYS_GID_MAX', 999]] + v = get_option(tuple[0]) + if v == -1 + v = run_command( + awk, + '/^\s*@0@\s+/ { uid=$2 } END { print uid }'.format(tuple[1]), + '/etc/login.defs').stdout().strip() + if v == '' + v = tuple[2] + else + v = v.to_int() + endif endif + conf.set(tuple[0].underscorify().to_upper(), v) + substs.set(tuple[0].underscorify().to_upper(), v) +endforeach +if conf.get('SYSTEM_ALLOC_UID_MIN') >= conf.get('SYSTEM_UID_MAX') + error('Invalid uid allocation range') endif -conf.set('SYSTEM_UID_MAX', system_uid_max) -substs.set('systemuidmax', system_uid_max) - -system_gid_max = get_option('system-gid-max') -if system_gid_max == -1 - system_gid_max = run_command( - awk, - '/^\s*SYS_GID_MAX\s+/ { gid=$2 } END { print gid }', - '/etc/login.defs').stdout().strip() - if system_gid_max == '' - system_gid_max = 999 - else - system_gid_max = system_gid_max.to_int() - endif +if conf.get('SYSTEM_ALLOC_GID_MIN') >= conf.get('SYSTEM_GID_MAX') + error('Invalid gid allocation range') endif -conf.set('SYSTEM_GID_MAX', system_gid_max) -substs.set('systemgidmax', system_gid_max) dynamic_uid_min = get_option('dynamic-uid-min') dynamic_uid_max = get_option('dynamic-uid-max') @@ -3539,12 +3535,12 @@ status = [ get_option('debug-tty')), 'TTY GID: @0@'.format(tty_gid), 'users GID: @0@'.format(substs.get('USERS_GID')), - 'maximum system UID: @0@'.format(system_uid_max), - 'maximum system GID: @0@'.format(system_gid_max), - 'minimum dynamic UID: @0@'.format(dynamic_uid_min), - 'maximum dynamic UID: @0@'.format(dynamic_uid_max), - 'minimum container UID base: @0@'.format(container_uid_base_min), - 'maximum container UID base: @0@'.format(container_uid_base_max), + 'system UIDs: <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_UID_MAX'), + conf.get('SYSTEM_ALLOC_UID_MIN')), + 'system GIDs: <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'), + conf.get('SYSTEM_ALLOC_GID_MIN')), + 'dynamic UIDs: @0@–@1@'.format(dynamic_uid_min, dynamic_uid_max), + 'container UID bases: @0@–@1@'.format(container_uid_base_min, container_uid_base_max), '/dev/kvm access mode: @0@'.format(get_option('dev-kvm-mode')), 'render group access mode: @0@'.format(get_option('group-render-mode')), 'certificate root directory: @0@'.format(get_option('certificate-root')), diff --git a/meson_options.txt b/meson_options.txt index a33b6e27ae..d5ce647ae6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -194,6 +194,10 @@ option('status-unit-format-default', type : 'combo', description : 'use unit name or description in messages by default') option('time-epoch', type : 'integer', value : '-1', description : 'time epoch for time clients') +option('system-alloc-uid-min', type : 'integer', value : '-1', + description : 'minimum system UID used when allocating') +option('system-alloc-gid-min', type : 'integer', value : '-1', + description : 'minimum system GID used when allocating') option('system-uid-max', type : 'integer', value : '-1', description : 'maximum system UID') option('system-gid-max', type : 'integer', value : '-1', diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in index 3af9f99830..c0554649de 100644 --- a/src/core/systemd.pc.in +++ b/src/core/systemd.pc.in @@ -80,9 +80,9 @@ modulesloaddir=${modules_load_dir} catalog_dir=/usr/lib/systemd/catalog catalogdir=${catalog_dir} -system_uid_max=@systemuidmax@ +system_uid_max=@SYSTEM_UID_MAX@ systemuidmax=${system_uid_max} -system_gid_max=@systemgidmax@ +system_gid_max=@SYSTEM_GID_MAX@ systemgidmax=${system_gid_max} dynamic_uid_min=@dynamicuidmin@ diff --git a/src/shared/user-record.c b/src/shared/user-record.c index f60db5da00..3ba78d455f 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -41,7 +41,9 @@ static int parse_alloc_uid(const char *path, const char *name, const char *t, ui static int read_login_defs(UGIDAllocationRange *ret_defs, const char *path) { _cleanup_fclose_ FILE *f = NULL; UGIDAllocationRange defs = { + .system_alloc_uid_min = SYSTEM_ALLOC_UID_MIN, .system_uid_max = SYSTEM_UID_MAX, + .system_alloc_gid_min = SYSTEM_ALLOC_GID_MIN, .system_gid_max = SYSTEM_GID_MAX, }; int r; @@ -65,13 +67,28 @@ static int read_login_defs(UGIDAllocationRange *ret_defs, const char *path) { if (r == 0) break; - if ((t = first_word(line, "SYS_UID_MAX"))) + if ((t = first_word(line, "SYS_UID_MIN"))) + (void) parse_alloc_uid(path, "SYS_UID_MIN", t, &defs.system_alloc_uid_min); + else 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_MIN"))) + (void) parse_alloc_uid(path, "SYS_GID_MIN", t, &defs.system_alloc_gid_min); else if ((t = first_word(line, "SYS_GID_MAX"))) (void) parse_alloc_uid(path, "SYS_GID_MAX", t, &defs.system_gid_max); } assign: + if (defs.system_alloc_uid_min > defs.system_uid_max) { + log_debug("%s: SYS_UID_MIN > SYS_UID_MAX, resetting.", path); + defs.system_alloc_uid_min = MIN(defs.system_uid_max - 1, (uid_t) SYSTEM_ALLOC_UID_MIN); + /* Look at sys_uid_max to make sure sys_uid_min..sys_uid_max remains a valid range. */ + } + if (defs.system_alloc_gid_min > defs.system_gid_max) { + log_debug("%s: SYS_GID_MIN > SYS_GID_MAX, resetting.", path); + defs.system_alloc_gid_min = MIN(defs.system_gid_max - 1, (gid_t) SYSTEM_ALLOC_GID_MIN); + /* Look at sys_gid_max to make sure sys_gid_min..sys_gid_max remains a valid range. */ + } + *ret_defs = defs; return 0; } @@ -83,7 +100,9 @@ const UGIDAllocationRange *acquire_ugid_allocation_range(void) { #else static const UGIDAllocationRange defs = { #endif + .system_alloc_uid_min = SYSTEM_ALLOC_UID_MIN, .system_uid_max = SYSTEM_UID_MAX, + .system_alloc_gid_min = SYSTEM_ALLOC_GID_MIN, .system_gid_max = SYSTEM_GID_MAX, }; diff --git a/src/shared/user-record.h b/src/shared/user-record.h index 52348227a5..1f87eff6d5 100644 --- a/src/shared/user-record.h +++ b/src/shared/user-record.h @@ -37,7 +37,9 @@ static inline bool gid_is_container(gid_t gid) { } typedef struct UGIDAllocationRange { + uid_t system_alloc_uid_min; uid_t system_uid_max; + gid_t system_alloc_gid_min; gid_t system_gid_max; } UGIDAllocationRange; diff --git a/src/test/test-user-record.c b/src/test/test-user-record.c index e54e384b09..fcab61d694 100644 --- a/src/test/test-user-record.c +++ b/src/test/test-user-record.c @@ -13,7 +13,9 @@ static void test_acquire_ugid_allocation_range(void) { const UGIDAllocationRange *defs; assert_se(defs = acquire_ugid_allocation_range()); + log_info("system_alloc_uid_min="UID_FMT, defs->system_alloc_uid_min); log_info("system_uid_max="UID_FMT, defs->system_uid_max); + log_info("system_alloc_gid_min="GID_FMT, defs->system_alloc_gid_min); log_info("system_gid_max="GID_FMT, defs->system_gid_max); }