uid-range: tie up number and array of uid range entries

This renames UidRange -> UidRangeEntry, and reintroduces UidRange which
contains the array of UidRangeEntry and its size.
No fucntional changes, just refactoring.
This commit is contained in:
Yu Watanabe
2022-09-16 20:56:58 +09:00
parent 6cc6cd9289
commit 8dcc66cefc
7 changed files with 202 additions and 185 deletions
+69 -46
View File
@@ -15,14 +15,22 @@
#include "uid-range.h"
#include "user-util.h"
static bool uid_range_intersect(const UidRange *a, const UidRange *b) {
UidRange *uid_range_free(UidRange *range) {
if (!range)
return NULL;
free(range->entries);
return mfree(range);
}
static bool uid_range_entry_intersect(const UidRangeEntry *a, const UidRangeEntry *b) {
assert(a);
assert(b);
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);
@@ -35,23 +43,22 @@ static int uid_range_compare(const UidRange *a, const UidRange *b) {
return CMP(a->nr, b->nr);
}
static void uid_range_coalesce(UidRange **p, size_t *n) {
assert(p);
assert(n);
static void uid_range_coalesce(UidRange *range) {
assert(range);
if (*n <= 1)
if (range->n_entries <= 0)
return;
typesafe_qsort(*p, *n, uid_range_compare);
typesafe_qsort(range->entries, range->n_entries, uid_range_entry_compare);
for (size_t i = 0; i < *n; i++) {
UidRange *x = (*p) + i;
for (size_t i = 0; i < range->n_entries; i++) {
UidRangeEntry *x = range->entries + i;
for (size_t j = i + 1; j < *n; j++) {
UidRange *y = (*p)+j;
for (size_t j = i + 1; j < range->n_entries; j++) {
UidRangeEntry *y = range->entries + j;
uid_t begin, end;
if (!uid_range_intersect(x, y))
if (!uid_range_entry_intersect(x, y))
break;
begin = MIN(x->start, y->start);
@@ -60,18 +67,20 @@ static void uid_range_coalesce(UidRange **p, size_t *n) {
x->start = begin;
x->nr = end - begin;
if (*n > j+1)
memmove(y, y+1, sizeof(UidRange) * (*n - j -1));
if (range->n_entries > j + 1)
memmove(y, y + 1, sizeof(UidRangeEntry) * (range->n_entries - j - 1));
(*n)--;
range->n_entries--;
j--;
}
}
}
int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce) {
assert(p);
assert(n);
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;
@@ -79,39 +88,51 @@ int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool
if (start > UINT32_MAX - nr) /* overflow check */
return -ERANGE;
if (!GREEDY_REALLOC(*p, *n + 1))
if (*range)
p = *range;
else {
range_new = new0(UidRange, 1);
if (!range_new)
return -ENOMEM;
p = range_new;
}
if (!GREEDY_REALLOC(p->entries, p->n_entries + 1))
return -ENOMEM;
(*p)[(*n)++] = (UidRange) {
p->entries[p->n_entries++] = (UidRangeEntry) {
.start = start,
.nr = nr,
};
if (coalesce)
uid_range_coalesce(p, n);
uid_range_coalesce(p);
return *n;
TAKE_PTR(range_new);
*range = p;
return 0;
}
int uid_range_add_str(UidRange **p, size_t *n, const char *s) {
int uid_range_add_str(UidRange **range, const char *s) {
uid_t start, end;
int r;
assert(p);
assert(n);
assert(range);
assert(s);
r = parse_uid_range(s, &start, &end);
if (r < 0)
return r;
return uid_range_add(p, n, start, end - start + 1);
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)
@@ -119,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;
@@ -141,26 +162,27 @@ 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) {
_cleanup_free_ UidRange *q = NULL;
int uid_range_load_userns(UidRange **ret, const char *path) {
_cleanup_(uid_range_freep) UidRange *range = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t m = 0;
int r;
/* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
@@ -169,8 +191,7 @@ 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(p);
assert(n);
assert(ret);
if (!path)
path = "/proc/self/uid_map";
@@ -185,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;
@@ -200,15 +225,13 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
if (k != 3)
return -EBADMSG;
r = uid_range_add_internal(&q, &m, uid_base, uid_range, /* coalesce = */ false);
r = uid_range_add_internal(&range, uid_base, uid_range, /* coalesce = */ false);
if (r < 0)
return r;
}
uid_range_coalesce(&q, &m);
*p = TAKE_PTR(q);
*n = m;
uid_range_coalesce(range);
*ret = TAKE_PTR(range);
return 0;
}
+20 -10
View File
@@ -4,21 +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_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce);
static inline int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
return uid_range_add_internal(p, n, start, nr, true);
UidRange *uid_range_free(UidRange *range);
DEFINE_TRIVIAL_CLEANUP_FUNC(UidRange*, uid_range_free);
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 **p, size_t *n, const char *s);
int uid_range_add_str(UidRange **range, const char *s);
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_next_lower(const UidRange *range, uid_t *uid);
static inline bool uid_range_contains(const UidRange *p, size_t n, uid_t uid) {
return uid_range_covers(p, n, uid, 1);
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);