Skip to content

Commit 5674aa7

Browse files
committed
uid-range: add new uid_range_load_userns() for loading /proc/self/uid_map
1 parent 2e37ebd commit 5674aa7

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

src/shared/uid-range.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
#include <string.h>
66

77
#include "alloc-util.h"
8+
#include "errno-util.h"
9+
#include "fd-util.h"
10+
#include "format-util.h"
811
#include "macro.h"
12+
#include "path-util.h"
913
#include "sort-util.h"
14+
#include "stat-util.h"
1015
#include "uid-range.h"
1116
#include "user-util.h"
1217

@@ -178,3 +183,47 @@ bool uid_range_contains(const UidRange *p, size_t n, uid_t uid) {
178183

179184
return false;
180185
}
186+
187+
int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
188+
_cleanup_fclose_ FILE *f = NULL;
189+
int r;
190+
191+
/* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
192+
* the specified file (which can be either uid_map or gid_map, in case caller needs to deal with GID
193+
* maps).
194+
*
195+
* To simplify things this will modify the passed array in case of later failure. */
196+
197+
if (!path)
198+
path = "/proc/self/uid_map";
199+
200+
f = fopen(path, "re");
201+
if (!f) {
202+
r = -errno;
203+
204+
if (r == -ENOENT && path_startswith(path, "/proc/") && proc_mounted() > 0)
205+
return -EOPNOTSUPP;
206+
207+
return r;
208+
}
209+
210+
for (;;) {
211+
uid_t uid_base, uid_shift, uid_range;
212+
int k;
213+
214+
errno = 0;
215+
k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
216+
if (k == EOF) {
217+
if (ferror(f))
218+
return errno_or_else(EIO);
219+
220+
return 0;
221+
}
222+
if (k != 3)
223+
return -EBADMSG;
224+
225+
r = uid_range_add(p, n, uid_base, uid_range);
226+
if (r < 0)
227+
return r;
228+
}
229+
}

src/shared/uid-range.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ int uid_range_add_str(UidRange **p, size_t *n, const char *s);
1313

1414
int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);
1515
bool uid_range_contains(const UidRange *p, size_t n, uid_t uid);
16+
17+
int uid_range_load_userns(UidRange **p, size_t *n, const char *path);

src/test/test-uid-range.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
#include <stddef.h>
44

55
#include "alloc-util.h"
6+
#include "errno-util.h"
7+
#include "fd-util.h"
8+
#include "fileio.h"
9+
#include "fs-util.h"
610
#include "tests.h"
11+
#include "tmpfile-util.h"
712
#include "uid-range.h"
813
#include "user-util.h"
914
#include "util.h"
15+
#include "virt.h"
1016

1117
TEST(uid_range) {
1218
_cleanup_free_ UidRange *p = NULL;
@@ -72,4 +78,45 @@ TEST(uid_range) {
7278
assert_se(p[0].nr == 1983);
7379
}
7480

81+
TEST(load_userns) {
82+
_cleanup_(unlink_and_freep) char *fn = NULL;
83+
_cleanup_free_ UidRange *p = NULL;
84+
_cleanup_fclose_ FILE *f = NULL;
85+
size_t n = 0;
86+
int r;
87+
88+
r = uid_range_load_userns(&p, &n, NULL);
89+
if (ERRNO_IS_NOT_SUPPORTED(r))
90+
return;
91+
92+
assert_se(r >= 0);
93+
assert_se(uid_range_contains(p, n, getuid()));
94+
95+
r = running_in_userns();
96+
if (r == 0) {
97+
assert_se(n == 1);
98+
assert_se(p[0].start == 0);
99+
assert_se(p[0].nr == UINT32_MAX);
100+
}
101+
102+
assert_se(fopen_temporary(NULL, &f, &fn) >= 0);
103+
fputs("0 0 20\n"
104+
"100 0 20\n", f);
105+
assert_se(fflush_and_check(f) >= 0);
106+
107+
p = mfree(p);
108+
n = 0;
109+
110+
assert_se(uid_range_load_userns(&p, &n, fn) >= 0);
111+
112+
assert_se(uid_range_contains(p, n, 0));
113+
assert_se(uid_range_contains(p, n, 19));
114+
assert_se(!uid_range_contains(p, n, 20));
115+
116+
assert_se(!uid_range_contains(p, n, 99));
117+
assert_se(uid_range_contains(p, n, 100));
118+
assert_se(uid_range_contains(p, n, 119));
119+
assert_se(!uid_range_contains(p, n, 120));
120+
}
121+
75122
DEFINE_TEST_MAIN(LOG_DEBUG);

0 commit comments

Comments
 (0)