mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-07 01:58:02 +03:00
Merge pull request #24685 from yuwata/uid-range
uid-range: several cleanups
This commit is contained in:
commit
e9fe11090e
@ -15,43 +15,27 @@
|
||||
#include "uid-range.h"
|
||||
#include "user-util.h"
|
||||
|
||||
static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
|
||||
assert(range);
|
||||
UidRange *uid_range_free(UidRange *range) {
|
||||
if (!range)
|
||||
return NULL;
|
||||
|
||||
return range->start <= start + nr &&
|
||||
range->start + range->nr >= start;
|
||||
free(range->entries);
|
||||
return mfree(range);
|
||||
}
|
||||
|
||||
static void uid_range_coalesce(UidRange **p, size_t *n) {
|
||||
assert(p);
|
||||
assert(n);
|
||||
static bool uid_range_entry_intersect(const UidRangeEntry *a, const UidRangeEntry *b) {
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
for (size_t i = 0; i < *n; i++) {
|
||||
for (size_t j = i + 1; j < *n; j++) {
|
||||
UidRange *x = (*p)+i, *y = (*p)+j;
|
||||
|
||||
if (uid_range_intersect(x, y->start, y->nr)) {
|
||||
uid_t begin, end;
|
||||
|
||||
begin = MIN(x->start, y->start);
|
||||
end = MAX(x->start + x->nr, y->start + y->nr);
|
||||
|
||||
x->start = begin;
|
||||
x->nr = end - begin;
|
||||
|
||||
if (*n > j+1)
|
||||
memmove(y, y+1, sizeof(UidRange) * (*n - j -1));
|
||||
|
||||
(*n)--;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return a->start <= b->start + b->nr && a->start + a->nr >= b->start;
|
||||
}
|
||||
|
||||
static int uid_range_compare(const UidRange *a, const UidRange *b) {
|
||||
static int uid_range_entry_compare(const UidRangeEntry *a, const UidRangeEntry *b) {
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
r = CMP(a->start, b->start);
|
||||
if (r != 0)
|
||||
return r;
|
||||
@ -59,12 +43,44 @@ static int uid_range_compare(const UidRange *a, const UidRange *b) {
|
||||
return CMP(a->nr, b->nr);
|
||||
}
|
||||
|
||||
int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
|
||||
bool found = false;
|
||||
UidRange *x;
|
||||
static void uid_range_coalesce(UidRange *range) {
|
||||
assert(range);
|
||||
|
||||
assert(p);
|
||||
assert(n);
|
||||
if (range->n_entries <= 0)
|
||||
return;
|
||||
|
||||
typesafe_qsort(range->entries, range->n_entries, uid_range_entry_compare);
|
||||
|
||||
for (size_t i = 0; i < range->n_entries; i++) {
|
||||
UidRangeEntry *x = range->entries + i;
|
||||
|
||||
for (size_t j = i + 1; j < range->n_entries; j++) {
|
||||
UidRangeEntry *y = range->entries + j;
|
||||
uid_t begin, end;
|
||||
|
||||
if (!uid_range_entry_intersect(x, y))
|
||||
break;
|
||||
|
||||
begin = MIN(x->start, y->start);
|
||||
end = MAX(x->start + x->nr, y->start + y->nr);
|
||||
|
||||
x->start = begin;
|
||||
x->nr = end - begin;
|
||||
|
||||
if (range->n_entries > j + 1)
|
||||
memmove(y, y + 1, sizeof(UidRangeEntry) * (range->n_entries - j - 1));
|
||||
|
||||
range->n_entries--;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int uid_range_add_internal(UidRange **range, uid_t start, uid_t nr, bool coalesce) {
|
||||
_cleanup_(uid_range_freep) UidRange *range_new = NULL;
|
||||
UidRange *p;
|
||||
|
||||
assert(range);
|
||||
|
||||
if (nr <= 0)
|
||||
return 0;
|
||||
@ -72,84 +88,51 @@ int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
|
||||
if (start > UINT32_MAX - nr) /* overflow check */
|
||||
return -ERANGE;
|
||||
|
||||
for (size_t i = 0; i < *n; i++) {
|
||||
x = (*p) + i;
|
||||
if (uid_range_intersect(x, start, nr)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
uid_t begin, end;
|
||||
|
||||
begin = MIN(x->start, start);
|
||||
end = MAX(x->start + x->nr, start + nr);
|
||||
|
||||
x->start = begin;
|
||||
x->nr = end - begin;
|
||||
} else {
|
||||
UidRange *t;
|
||||
|
||||
t = reallocarray(*p, *n + 1, sizeof(UidRange));
|
||||
if (!t)
|
||||
if (*range)
|
||||
p = *range;
|
||||
else {
|
||||
range_new = new0(UidRange, 1);
|
||||
if (!range_new)
|
||||
return -ENOMEM;
|
||||
|
||||
*p = t;
|
||||
x = t + ((*n) ++);
|
||||
|
||||
x->start = start;
|
||||
x->nr = nr;
|
||||
p = range_new;
|
||||
}
|
||||
|
||||
typesafe_qsort(*p, *n, uid_range_compare);
|
||||
uid_range_coalesce(p, n);
|
||||
if (!GREEDY_REALLOC(p->entries, p->n_entries + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
return *n;
|
||||
p->entries[p->n_entries++] = (UidRangeEntry) {
|
||||
.start = start,
|
||||
.nr = nr,
|
||||
};
|
||||
|
||||
if (coalesce)
|
||||
uid_range_coalesce(p);
|
||||
|
||||
TAKE_PTR(range_new);
|
||||
*range = p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uid_range_add_str(UidRange **p, size_t *n, const char *s) {
|
||||
uid_t start, nr;
|
||||
const char *t;
|
||||
int uid_range_add_str(UidRange **range, const char *s) {
|
||||
uid_t start, end;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
assert(n);
|
||||
assert(range);
|
||||
assert(s);
|
||||
|
||||
t = strchr(s, '-');
|
||||
if (t) {
|
||||
char *b;
|
||||
uid_t end;
|
||||
r = parse_uid_range(s, &start, &end);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
b = strndupa_safe(s, t - s);
|
||||
r = parse_uid(b, &start);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = parse_uid(t+1, &end);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (end < start)
|
||||
return -EINVAL;
|
||||
|
||||
nr = end - start + 1;
|
||||
} else {
|
||||
r = parse_uid(s, &start);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
nr = 1;
|
||||
}
|
||||
|
||||
return uid_range_add(p, n, start, nr);
|
||||
return uid_range_add_internal(range, start, end - start + 1, /* coalesce = */ true);
|
||||
}
|
||||
|
||||
int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
|
||||
int uid_range_next_lower(const UidRange *range, uid_t *uid) {
|
||||
uid_t closest = UID_INVALID, candidate;
|
||||
|
||||
assert(p);
|
||||
assert(range);
|
||||
assert(uid);
|
||||
|
||||
if (*uid == 0)
|
||||
@ -157,11 +140,11 @@ int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
|
||||
|
||||
candidate = *uid - 1;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
for (size_t i = 0; i < range->n_entries; i++) {
|
||||
uid_t begin, end;
|
||||
|
||||
begin = p[i].start;
|
||||
end = p[i].start + p[i].nr - 1;
|
||||
begin = range->entries[i].start;
|
||||
end = range->entries[i].start + range->entries[i].nr - 1;
|
||||
|
||||
if (candidate >= begin && candidate <= end) {
|
||||
*uid = candidate;
|
||||
@ -179,23 +162,26 @@ int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr) {
|
||||
assert(p || n == 0);
|
||||
|
||||
bool uid_range_covers(const UidRange *range, uid_t start, uid_t nr) {
|
||||
if (nr == 0) /* empty range? always covered... */
|
||||
return true;
|
||||
|
||||
if (start > UINT32_MAX - nr) /* range overflows? definitely not covered... */
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
if (start >= p[i].start && start + nr <= p[i].start + p[i].nr)
|
||||
if (!range)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < range->n_entries; i++)
|
||||
if (start >= range->entries[i].start &&
|
||||
start + nr <= range->entries[i].start + range->entries[i].nr)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
|
||||
int uid_range_load_userns(UidRange **ret, const char *path) {
|
||||
_cleanup_(uid_range_freep) UidRange *range = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
@ -205,6 +191,8 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
|
||||
*
|
||||
* To simplify things this will modify the passed array in case of later failure. */
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (!path)
|
||||
path = "/proc/self/uid_map";
|
||||
|
||||
@ -218,6 +206,10 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
|
||||
return r;
|
||||
}
|
||||
|
||||
range = new0(UidRange, 1);
|
||||
if (!range)
|
||||
return -ENOMEM;
|
||||
|
||||
for (;;) {
|
||||
uid_t uid_base, uid_shift, uid_range;
|
||||
int k;
|
||||
@ -228,13 +220,18 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
|
||||
if (ferror(f))
|
||||
return errno_or_else(EIO);
|
||||
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
if (k != 3)
|
||||
return -EBADMSG;
|
||||
|
||||
r = uid_range_add(p, n, uid_base, uid_range);
|
||||
r = uid_range_add_internal(&range, uid_base, uid_range, /* coalesce = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
uid_range_coalesce(range);
|
||||
|
||||
*ret = TAKE_PTR(range);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,18 +4,31 @@
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct UidRange {
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct UidRangeEntry {
|
||||
uid_t start, nr;
|
||||
} UidRangeEntry;
|
||||
|
||||
typedef struct UidRange {
|
||||
UidRangeEntry *entries;
|
||||
size_t n_entries;
|
||||
} UidRange;
|
||||
|
||||
int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr);
|
||||
int uid_range_add_str(UidRange **p, size_t *n, const char *s);
|
||||
UidRange *uid_range_free(UidRange *range);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UidRange*, uid_range_free);
|
||||
|
||||
int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);
|
||||
bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr);
|
||||
int uid_range_add_internal(UidRange **range, uid_t start, uid_t nr, bool coalesce);
|
||||
static inline int uid_range_add(UidRange **range, uid_t start, uid_t nr) {
|
||||
return uid_range_add_internal(range, start, nr, true);
|
||||
}
|
||||
int uid_range_add_str(UidRange **range, const char *s);
|
||||
|
||||
static inline bool uid_range_contains(const UidRange *p, size_t n, uid_t uid) {
|
||||
return uid_range_covers(p, n, uid, 1);
|
||||
int uid_range_next_lower(const UidRange *range, uid_t *uid);
|
||||
|
||||
bool uid_range_covers(const UidRange *range, uid_t start, uid_t nr);
|
||||
static inline bool uid_range_contains(const UidRange *range, uid_t uid) {
|
||||
return uid_range_covers(range, uid, 1);
|
||||
}
|
||||
|
||||
int uid_range_load_userns(UidRange **p, size_t *n, const char *path);
|
||||
int uid_range_load_userns(UidRange **ret, const char *path);
|
||||
|
@ -4457,8 +4457,7 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
|
||||
}
|
||||
|
||||
static int short_uid_range(const char *path) {
|
||||
_cleanup_free_ UidRange *p = NULL;
|
||||
size_t n = 0;
|
||||
_cleanup_(uid_range_freep) UidRange *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
@ -4466,13 +4465,14 @@ static int short_uid_range(const char *path) {
|
||||
/* Taint systemd if we the UID range assigned to this environment doesn't at least cover 0…65534,
|
||||
* i.e. from root to nobody. */
|
||||
|
||||
r = uid_range_load_userns(&p, &n, path);
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return false;
|
||||
if (r < 0)
|
||||
r = uid_range_load_userns(&p, path);
|
||||
if (r < 0) {
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return false;
|
||||
return log_debug_errno(r, "Failed to load %s: %m", path);
|
||||
}
|
||||
|
||||
return !uid_range_covers(p, n, 0, 65535);
|
||||
return !uid_range_covers(p, 0, 65535);
|
||||
}
|
||||
|
||||
char* manager_taint_string(const Manager *m) {
|
||||
|
@ -48,7 +48,6 @@ struct sd_device_monitor {
|
||||
bool bound;
|
||||
|
||||
UidRange *mapped_userns_uid_range;
|
||||
size_t n_uid_range;
|
||||
|
||||
Hashmap *subsystem_filter;
|
||||
Set *tag_filter;
|
||||
@ -174,7 +173,6 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
|
||||
.bound = fd >= 0,
|
||||
.snl.nl.nl_family = AF_NETLINK,
|
||||
.snl.nl.nl_groups = group,
|
||||
.n_uid_range = SIZE_MAX,
|
||||
};
|
||||
|
||||
if (fd >= 0) {
|
||||
@ -376,7 +374,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
|
||||
|
||||
(void) sd_device_monitor_detach_event(m);
|
||||
|
||||
free(m->mapped_userns_uid_range);
|
||||
uid_range_free(m->mapped_userns_uid_range);
|
||||
free(m->description);
|
||||
hashmap_free(m->subsystem_filter);
|
||||
set_free(m->tag_filter);
|
||||
@ -468,15 +466,14 @@ static bool check_sender_uid(sd_device_monitor *m, uid_t uid) {
|
||||
if (uid == getuid() || uid == geteuid())
|
||||
return true;
|
||||
|
||||
if (m->n_uid_range == SIZE_MAX) {
|
||||
m->n_uid_range = 0;
|
||||
r = uid_range_load_userns(&m->mapped_userns_uid_range, &m->n_uid_range, NULL);
|
||||
if (!m->mapped_userns_uid_range) {
|
||||
r = uid_range_load_userns(&m->mapped_userns_uid_range, NULL);
|
||||
if (r < 0)
|
||||
log_monitor_errno(m, r, "Failed to load UID ranges mapped to the current user namespace, ignoring: %m");
|
||||
}
|
||||
|
||||
/* Trust messages come from outside of the current user namespace. */
|
||||
if (m->n_uid_range != SIZE_MAX && !uid_range_contains(m->mapped_userns_uid_range, m->n_uid_range, uid))
|
||||
if (!uid_range_contains(m->mapped_userns_uid_range, uid))
|
||||
return true;
|
||||
|
||||
/* Otherwise, refuse messages. */
|
||||
|
@ -107,7 +107,6 @@ static Set *database_users = NULL, *database_groups = NULL;
|
||||
|
||||
static uid_t search_uid = UID_INVALID;
|
||||
static UidRange *uid_range = NULL;
|
||||
static size_t n_uid_range = 0;
|
||||
|
||||
static UGIDAllocationRange login_defs = {};
|
||||
static bool login_defs_need_warning = false;
|
||||
@ -123,7 +122,7 @@ STATIC_DESTRUCTOR_REGISTER(database_users, set_free_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(database_by_gid, hashmap_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(database_by_groupname, hashmap_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(uid_range, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(uid_range, uid_range_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
|
||||
@ -1113,7 +1112,7 @@ static int add_user(Item *i) {
|
||||
|
||||
if (read_id_from_file(i, &c, NULL) > 0) {
|
||||
|
||||
if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
|
||||
if (c <= 0 || !uid_range_contains(uid_range, c))
|
||||
log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
|
||||
else {
|
||||
r = uid_is_ok(c, i->name, true);
|
||||
@ -1144,7 +1143,7 @@ static int add_user(Item *i) {
|
||||
maybe_emit_login_defs_warning();
|
||||
|
||||
for (;;) {
|
||||
r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
|
||||
r = uid_range_next_lower(uid_range, &search_uid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "No free user ID available for %s.", i->name);
|
||||
|
||||
@ -1297,7 +1296,7 @@ static int add_group(Item *i) {
|
||||
|
||||
if (read_id_from_file(i, NULL, &c) > 0) {
|
||||
|
||||
if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
|
||||
if (c <= 0 || !uid_range_contains(uid_range, c))
|
||||
log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
|
||||
else {
|
||||
r = gid_is_ok(c, true);
|
||||
@ -1318,7 +1317,7 @@ static int add_group(Item *i) {
|
||||
|
||||
for (;;) {
|
||||
/* We look for new GIDs in the UID pool! */
|
||||
r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
|
||||
r = uid_range_next_lower(uid_range, &search_uid);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "No free group ID available for %s.", i->name);
|
||||
|
||||
@ -1668,7 +1667,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
action[0],
|
||||
description ? "GECOS" : home ? "home directory" : "login shell");
|
||||
|
||||
r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
|
||||
r = uid_range_add_str(&uid_range, resolved_id);
|
||||
if (r < 0)
|
||||
return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid UID range %s.", resolved_id);
|
||||
@ -2169,7 +2168,7 @@ static int run(int argc, char *argv[]) {
|
||||
uid_t begin = login_defs.system_alloc_uid_min,
|
||||
end = MIN3((uid_t) SYSTEM_UID_MAX, login_defs.system_uid_max, login_defs.system_gid_max);
|
||||
if (begin < end) {
|
||||
r = uid_range_add(&uid_range, &n_uid_range, begin, end - begin + 1);
|
||||
r = uid_range_add(&uid_range, begin, end - begin + 1);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
@ -15,105 +15,104 @@
|
||||
#include "virt.h"
|
||||
|
||||
TEST(uid_range) {
|
||||
_cleanup_free_ UidRange *p = NULL;
|
||||
size_t n = 0;
|
||||
_cleanup_(uid_range_freep) UidRange *p = NULL;
|
||||
uid_t search;
|
||||
|
||||
assert_se(uid_range_covers(p, n, 0, 0));
|
||||
assert_se(!uid_range_covers(p, n, 0, 1));
|
||||
assert_se(!uid_range_covers(p, n, 100, UINT32_MAX));
|
||||
assert_se(uid_range_covers(p, 0, 0));
|
||||
assert_se(!uid_range_covers(p, 0, 1));
|
||||
assert_se(!uid_range_covers(p, 100, UINT32_MAX));
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "500-999") >= 0);
|
||||
assert_se(n == 1);
|
||||
assert_se(p[0].start == 500);
|
||||
assert_se(p[0].nr == 500);
|
||||
assert_se(uid_range_add_str(&p, "500-999") >= 0);
|
||||
assert_se(p);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 500);
|
||||
assert_se(p->entries[0].nr == 500);
|
||||
|
||||
assert_se(!uid_range_contains(p, n, 499));
|
||||
assert_se(uid_range_contains(p, n, 500));
|
||||
assert_se(uid_range_contains(p, n, 999));
|
||||
assert_se(!uid_range_contains(p, n, 1000));
|
||||
assert_se(!uid_range_contains(p, 499));
|
||||
assert_se(uid_range_contains(p, 500));
|
||||
assert_se(uid_range_contains(p, 999));
|
||||
assert_se(!uid_range_contains(p, 1000));
|
||||
|
||||
assert_se(!uid_range_covers(p, n, 100, 150));
|
||||
assert_se(!uid_range_covers(p, n, 400, 200));
|
||||
assert_se(!uid_range_covers(p, n, 499, 1));
|
||||
assert_se(uid_range_covers(p, n, 500, 1));
|
||||
assert_se(uid_range_covers(p, n, 501, 10));
|
||||
assert_se(uid_range_covers(p, n, 999, 1));
|
||||
assert_se(!uid_range_covers(p, n, 999, 2));
|
||||
assert_se(!uid_range_covers(p, n, 1000, 1));
|
||||
assert_se(!uid_range_covers(p, n, 1000, 100));
|
||||
assert_se(!uid_range_covers(p, n, 1001, 100));
|
||||
assert_se(!uid_range_covers(p, 100, 150));
|
||||
assert_se(!uid_range_covers(p, 400, 200));
|
||||
assert_se(!uid_range_covers(p, 499, 1));
|
||||
assert_se(uid_range_covers(p, 500, 1));
|
||||
assert_se(uid_range_covers(p, 501, 10));
|
||||
assert_se(uid_range_covers(p, 999, 1));
|
||||
assert_se(!uid_range_covers(p, 999, 2));
|
||||
assert_se(!uid_range_covers(p, 1000, 1));
|
||||
assert_se(!uid_range_covers(p, 1000, 100));
|
||||
assert_se(!uid_range_covers(p, 1001, 100));
|
||||
|
||||
search = UID_INVALID;
|
||||
assert_se(uid_range_next_lower(p, n, &search));
|
||||
assert_se(uid_range_next_lower(p, &search));
|
||||
assert_se(search == 999);
|
||||
assert_se(uid_range_next_lower(p, n, &search));
|
||||
assert_se(uid_range_next_lower(p, &search));
|
||||
assert_se(search == 998);
|
||||
search = 501;
|
||||
assert_se(uid_range_next_lower(p, n, &search));
|
||||
assert_se(uid_range_next_lower(p, &search));
|
||||
assert_se(search == 500);
|
||||
assert_se(uid_range_next_lower(p, n, &search) == -EBUSY);
|
||||
assert_se(uid_range_next_lower(p, &search) == -EBUSY);
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "1000") >= 0);
|
||||
assert_se(n == 1);
|
||||
assert_se(p[0].start == 500);
|
||||
assert_se(p[0].nr == 501);
|
||||
assert_se(uid_range_add_str(&p, "1000") >= 0);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 500);
|
||||
assert_se(p->entries[0].nr == 501);
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "30-40") >= 0);
|
||||
assert_se(n == 2);
|
||||
assert_se(p[0].start == 30);
|
||||
assert_se(p[0].nr == 11);
|
||||
assert_se(p[1].start == 500);
|
||||
assert_se(p[1].nr == 501);
|
||||
assert_se(uid_range_add_str(&p, "30-40") >= 0);
|
||||
assert_se(p->n_entries == 2);
|
||||
assert_se(p->entries[0].start == 30);
|
||||
assert_se(p->entries[0].nr == 11);
|
||||
assert_se(p->entries[1].start == 500);
|
||||
assert_se(p->entries[1].nr == 501);
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "60-70") >= 0);
|
||||
assert_se(n == 3);
|
||||
assert_se(p[0].start == 30);
|
||||
assert_se(p[0].nr == 11);
|
||||
assert_se(p[1].start == 60);
|
||||
assert_se(p[1].nr == 11);
|
||||
assert_se(p[2].start == 500);
|
||||
assert_se(p[2].nr == 501);
|
||||
assert_se(uid_range_add_str(&p, "60-70") >= 0);
|
||||
assert_se(p->n_entries == 3);
|
||||
assert_se(p->entries[0].start == 30);
|
||||
assert_se(p->entries[0].nr == 11);
|
||||
assert_se(p->entries[1].start == 60);
|
||||
assert_se(p->entries[1].nr == 11);
|
||||
assert_se(p->entries[2].start == 500);
|
||||
assert_se(p->entries[2].nr == 501);
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "20-2000") >= 0);
|
||||
assert_se(n == 1);
|
||||
assert_se(p[0].start == 20);
|
||||
assert_se(p[0].nr == 1981);
|
||||
assert_se(uid_range_add_str(&p, "20-2000") >= 0);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 20);
|
||||
assert_se(p->entries[0].nr == 1981);
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "2002") >= 0);
|
||||
assert_se(n == 2);
|
||||
assert_se(p[0].start == 20);
|
||||
assert_se(p[0].nr == 1981);
|
||||
assert_se(p[1].start == 2002);
|
||||
assert_se(p[1].nr == 1);
|
||||
assert_se(uid_range_add_str(&p, "2002") >= 0);
|
||||
assert_se(p->n_entries == 2);
|
||||
assert_se(p->entries[0].start == 20);
|
||||
assert_se(p->entries[0].nr == 1981);
|
||||
assert_se(p->entries[1].start == 2002);
|
||||
assert_se(p->entries[1].nr == 1);
|
||||
|
||||
assert_se(uid_range_add_str(&p, &n, "2001") >= 0);
|
||||
assert_se(n == 1);
|
||||
assert_se(p[0].start == 20);
|
||||
assert_se(p[0].nr == 1983);
|
||||
assert_se(uid_range_add_str(&p, "2001") >= 0);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 20);
|
||||
assert_se(p->entries[0].nr == 1983);
|
||||
}
|
||||
|
||||
TEST(load_userns) {
|
||||
_cleanup_(uid_range_freep) UidRange *p = NULL;
|
||||
_cleanup_(unlink_and_freep) char *fn = NULL;
|
||||
_cleanup_free_ UidRange *p = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
size_t n = 0;
|
||||
int r;
|
||||
|
||||
r = uid_range_load_userns(&p, &n, NULL);
|
||||
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||
r = uid_range_load_userns(&p, NULL);
|
||||
if (r < 0 && ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return;
|
||||
|
||||
assert_se(r >= 0);
|
||||
assert_se(uid_range_contains(p, n, getuid()));
|
||||
assert_se(uid_range_contains(p, getuid()));
|
||||
|
||||
r = running_in_userns();
|
||||
if (r == 0) {
|
||||
assert_se(n == 1);
|
||||
assert_se(p[0].start == 0);
|
||||
assert_se(p[0].nr == UINT32_MAX);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 0);
|
||||
assert_se(p->entries[0].nr == UINT32_MAX);
|
||||
|
||||
assert_se(uid_range_covers(p, n, 0, UINT32_MAX));
|
||||
assert_se(uid_range_covers(p, 0, UINT32_MAX));
|
||||
}
|
||||
|
||||
assert_se(fopen_temporary(NULL, &f, &fn) >= 0);
|
||||
@ -121,19 +120,57 @@ TEST(load_userns) {
|
||||
"100 0 20\n", f);
|
||||
assert_se(fflush_and_check(f) >= 0);
|
||||
|
||||
p = mfree(p);
|
||||
n = 0;
|
||||
p = uid_range_free(p);
|
||||
|
||||
assert_se(uid_range_load_userns(&p, &n, fn) >= 0);
|
||||
assert_se(uid_range_load_userns(&p, fn) >= 0);
|
||||
|
||||
assert_se(uid_range_contains(p, n, 0));
|
||||
assert_se(uid_range_contains(p, n, 19));
|
||||
assert_se(!uid_range_contains(p, n, 20));
|
||||
assert_se(uid_range_contains(p, 0));
|
||||
assert_se(uid_range_contains(p, 19));
|
||||
assert_se(!uid_range_contains(p, 20));
|
||||
|
||||
assert_se(!uid_range_contains(p, n, 99));
|
||||
assert_se(uid_range_contains(p, n, 100));
|
||||
assert_se(uid_range_contains(p, n, 119));
|
||||
assert_se(!uid_range_contains(p, n, 120));
|
||||
assert_se(!uid_range_contains(p, 99));
|
||||
assert_se(uid_range_contains(p, 100));
|
||||
assert_se(uid_range_contains(p, 119));
|
||||
assert_se(!uid_range_contains(p, 120));
|
||||
}
|
||||
|
||||
TEST(uid_range_coalesce) {
|
||||
_cleanup_(uid_range_freep) UidRange *p = NULL;
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
assert_se(uid_range_add_internal(&p, i * 10, 10, /* coalesce = */ false) >= 0);
|
||||
assert_se(uid_range_add_internal(&p, i * 10 + 5, 10, /* coalesce = */ false) >= 0);
|
||||
}
|
||||
|
||||
assert_se(uid_range_add_internal(&p, 100, 1, /* coalesce = */ true) >= 0);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 0);
|
||||
assert_se(p->entries[0].nr == 105);
|
||||
|
||||
p = uid_range_free(p);
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
assert_se(uid_range_add_internal(&p, (10 - i) * 10, 10, /* coalesce = */ false) >= 0);
|
||||
assert_se(uid_range_add_internal(&p, (10 - i) * 10 + 5, 10, /* coalesce = */ false) >= 0);
|
||||
}
|
||||
|
||||
assert_se(uid_range_add_internal(&p, 100, 1, /* coalesce = */ true) >= 0);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 10);
|
||||
assert_se(p->entries[0].nr == 105);
|
||||
|
||||
p = uid_range_free(p);
|
||||
|
||||
for (size_t i = 0; i < 10; i++) {
|
||||
assert_se(uid_range_add_internal(&p, i * 10, 10, /* coalesce = */ false) >= 0);
|
||||
assert_se(uid_range_add_internal(&p, i * 10 + 5, 10, /* coalesce = */ false) >= 0);
|
||||
assert_se(uid_range_add_internal(&p, (10 - i) * 10, 10, /* coalesce = */ false) >= 0);
|
||||
assert_se(uid_range_add_internal(&p, (10 - i) * 10 + 5, 10, /* coalesce = */ false) >= 0);
|
||||
}
|
||||
assert_se(uid_range_add_internal(&p, 100, 1, /* coalesce = */ true) >= 0);
|
||||
assert_se(p->n_entries == 1);
|
||||
assert_se(p->entries[0].start == 0);
|
||||
assert_se(p->entries[0].nr == 115);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
@ -168,20 +168,15 @@ static const struct {
|
||||
},
|
||||
};
|
||||
|
||||
static int table_add_uid_boundaries(
|
||||
Table *table,
|
||||
const UidRange *p,
|
||||
size_t n) {
|
||||
static int table_add_uid_boundaries(Table *table, const UidRange *p) {
|
||||
int r;
|
||||
|
||||
assert(table);
|
||||
assert(p || n == 0);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
|
||||
_cleanup_free_ char *name = NULL, *comment = NULL;
|
||||
|
||||
if (n > 0 &&
|
||||
!uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1))
|
||||
if (!uid_range_covers(p, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1))
|
||||
continue;
|
||||
|
||||
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
|
||||
@ -277,9 +272,9 @@ static int add_unavailable_uid(Table *table, uid_t start, uid_t end) {
|
||||
return table_log_add_error(r);
|
||||
|
||||
free(name);
|
||||
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
|
||||
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_UP),
|
||||
" end unavailable users ",
|
||||
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
|
||||
special_glyph(SPECIAL_GLYPH_ARROW_UP));
|
||||
if (!name)
|
||||
return log_oom();
|
||||
|
||||
@ -306,31 +301,31 @@ static int add_unavailable_uid(Table *table, uid_t start, uid_t end) {
|
||||
static int table_add_uid_map(
|
||||
Table *table,
|
||||
const UidRange *p,
|
||||
size_t n,
|
||||
int (*add_unavailable)(Table *t, uid_t start, uid_t end)) {
|
||||
|
||||
uid_t focus = 0;
|
||||
int n_added = 0, r;
|
||||
|
||||
assert(table);
|
||||
assert(p || n == 0);
|
||||
assert(add_unavailable);
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (focus < p[i].start) {
|
||||
r = add_unavailable(table, focus, p[i].start-1);
|
||||
for (size_t i = 0; p && i < p->n_entries; i++) {
|
||||
UidRangeEntry *x = p->entries + i;
|
||||
|
||||
if (focus < x->start) {
|
||||
r = add_unavailable(table, focus, x->start-1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n_added += r;
|
||||
}
|
||||
|
||||
if (p[i].start > UINT32_MAX - p[i].nr) { /* overflow check */
|
||||
if (x->start > UINT32_MAX - x->nr) { /* overflow check */
|
||||
focus = UINT32_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
focus = p[i].start + p[i].nr;
|
||||
focus = x->start + x->nr;
|
||||
}
|
||||
|
||||
if (focus < UINT32_MAX-1) {
|
||||
@ -429,19 +424,18 @@ static int display_user(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (table) {
|
||||
_cleanup_free_ UidRange *uid_range = NULL;
|
||||
_cleanup_(uid_range_freep) UidRange *uid_range = NULL;
|
||||
int boundary_lines, uid_map_lines;
|
||||
size_t n_uid_range = 0;
|
||||
|
||||
r = uid_range_load_userns(&uid_range, &n_uid_range, "/proc/self/uid_map");
|
||||
r = uid_range_load_userns(&uid_range, "/proc/self/uid_map");
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to load /proc/self/uid_map, ignoring: %m");
|
||||
|
||||
boundary_lines = table_add_uid_boundaries(table, uid_range, n_uid_range);
|
||||
boundary_lines = table_add_uid_boundaries(table, uid_range);
|
||||
if (boundary_lines < 0)
|
||||
return boundary_lines;
|
||||
|
||||
uid_map_lines = table_add_uid_map(table, uid_range, n_uid_range, add_unavailable_uid);
|
||||
uid_map_lines = table_add_uid_map(table, uid_range, add_unavailable_uid);
|
||||
if (uid_map_lines < 0)
|
||||
return uid_map_lines;
|
||||
|
||||
@ -531,20 +525,15 @@ static int show_group(GroupRecord *gr, Table *table) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int table_add_gid_boundaries(
|
||||
Table *table,
|
||||
const UidRange *p,
|
||||
size_t n) {
|
||||
static int table_add_gid_boundaries(Table *table, const UidRange *p) {
|
||||
int r;
|
||||
|
||||
assert(table);
|
||||
assert(p || n == 0);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
|
||||
_cleanup_free_ char *name = NULL, *comment = NULL;
|
||||
|
||||
if (n > 0 &&
|
||||
!uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last))
|
||||
if (!uid_range_covers(p, uid_range_table[i].first, uid_range_table[i].last))
|
||||
continue;
|
||||
|
||||
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
|
||||
@ -631,9 +620,9 @@ static int add_unavailable_gid(Table *table, uid_t start, uid_t end) {
|
||||
return table_log_add_error(r);
|
||||
|
||||
free(name);
|
||||
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
|
||||
name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_UP),
|
||||
" end unavailable groups ",
|
||||
special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
|
||||
special_glyph(SPECIAL_GLYPH_ARROW_UP));
|
||||
if (!name)
|
||||
return log_oom();
|
||||
|
||||
@ -738,19 +727,18 @@ static int display_group(int argc, char *argv[], void *userdata) {
|
||||
}
|
||||
|
||||
if (table) {
|
||||
_cleanup_free_ UidRange *gid_range = NULL;
|
||||
_cleanup_(uid_range_freep) UidRange *gid_range = NULL;
|
||||
int boundary_lines, gid_map_lines;
|
||||
size_t n_gid_range = 0;
|
||||
|
||||
r = uid_range_load_userns(&gid_range, &n_gid_range, "/proc/self/gid_map");
|
||||
r = uid_range_load_userns(&gid_range, "/proc/self/gid_map");
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to load /proc/self/gid_map, ignoring: %m");
|
||||
|
||||
boundary_lines = table_add_gid_boundaries(table, gid_range, n_gid_range);
|
||||
boundary_lines = table_add_gid_boundaries(table, gid_range);
|
||||
if (boundary_lines < 0)
|
||||
return boundary_lines;
|
||||
|
||||
gid_map_lines = table_add_uid_map(table, gid_range, n_gid_range, add_unavailable_gid);
|
||||
gid_map_lines = table_add_uid_map(table, gid_range, add_unavailable_gid);
|
||||
if (gid_map_lines < 0)
|
||||
return gid_map_lines;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user