Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

userns: fix id map generating with holes under specific conditions #88

Merged
merged 2 commits into from
Dec 6, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 25 additions & 17 deletions userns.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,17 @@ void id_map_parse(id_map map, char *opt)

$ cat /etc/subuid
barney:100000:65535
barney:200000:100000

Then, calling the function as such:

id_map_load_subids(map, "/etc/subuid", 1000, "barney");

will populate the contents of `map` with the following data:

inner=0 outer=1000 1
inner=0 outer=1000 1
inner=0 outer=100000 65535
inner=0 outer=200000 100000
*/
void id_map_load_subids(id_map map, const char *subid_path, const struct id *id)
{
Expand All @@ -121,6 +123,7 @@ void id_map_load_subids(id_map map, const char *subid_path, const struct id *id)
size assumptions tend to bite back, and pages are extremely cheap. */
char line[4096];

bool found = false;
while (fgets(line, sizeof (line), subids) != NULL) {
char entryname[ID_STR_MAX + 1];
entryname[ID_STR_MAX] = 0;
Expand All @@ -143,9 +146,18 @@ void id_map_load_subids(id_map map, const char *subid_path, const struct id *id)
}

range = id_map_append(map, range, 0, start, length);
found = true;
}

fclose(subids);

/* We're root. We don't care. Map the host range 1:1 if there are no
allotted subids */
if (!found && id->id == 0) {
/* UINT32_MAX - 1 is explicitly left out because the kernel rejects it
(see user_namespaces(7)). */
id_map_append(map, 0, 0, 0, UINT32_MAX - 2);
}
}

void id_map_generate(id_map allotted, id_map out, const char *subid_path, const struct id *id)
Expand All @@ -165,14 +177,19 @@ void id_map_generate(id_map allotted, id_map out, const char *subid_path, const
continue;
}

/* Ignore the [0-65535) range. */
if (range.outer <= ID_MAX) {
uint32_t shift = ID_MAX + 1 - range.outer;
if (shift > range.length) {
shift = range.length;
/* The current id already has been assigned; ignore it if it comes up
in the allotted map. */
if (range.outer <= id->id && id->id < range.outer + range.length) {
uint32_t len = id->id - range.outer;
if (len != 0) {
/* Add range up to (but excluding) id->id */
j = id_map_append(tmp, j, cur_id, range.outer, len);
cur_id += len;
}
range.outer += shift;
range.length -= shift;

/* Change the range to start one past id->id */
range.outer = id->id + 1;
range.length -= len + 1;
continue;
}

Expand All @@ -181,14 +198,6 @@ void id_map_generate(id_map allotted, id_map out, const char *subid_path, const
range.length = 0;
}

/* We're root. We don't care. Map the host range 1:1. */
if (cur_id == 1 && id->id == 0) {
/* UINT32_MAX - 1 is explicitly left out because the kernel rejects it
(see user_namespaces(7)). */
id_map_append(tmp, 0, 0, 0, UINT32_MAX - 2);
goto end;
}

/* Not enough subuids for a full mapping, but, well, it's not the end of
the world. Things might break, so let's at least tell the user. */

Expand All @@ -204,7 +213,6 @@ void id_map_generate(id_map allotted, id_map out, const char *subid_path, const
name, subid_path, cur_id, ID_MAX);
}

end:
memcpy(out, tmp, sizeof (tmp));
}

Expand Down