-
Notifications
You must be signed in to change notification settings - Fork 77
uid/gidmapping #145
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
base: main
Are you sure you want to change the base?
uid/gidmapping #145
Changes from all commits
70ae8dd
b58a42d
bb7be24
1a87872
f3704d4
0ed1827
4325803
eb9c436
8bcf1e1
8bb213f
ba6a906
d6c6269
0c87461
6defb9b
3495a17
0493613
b98f7af
088001e
411ca92
9165206
bf0dfae
3ad69ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| #!/bin/sh | ||
|
|
||
| wget https://github.com/ezrizhu/gidmapper/releases/download/0.0.3/gidmapper -O /usr/bin/gidmapper | ||
| chmod +x /usr/bin/gidmapper | ||
| setcap 'CAP_SETGID=ep' /usr/bin/gidmapper | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| #!/bin/sh | ||
|
|
||
| TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree)}" | ||
| TRY="$TRY_TOP/try" | ||
|
|
||
| cleanup() { | ||
| cd / | ||
|
|
||
| if [ -d "$try_workspace" ] | ||
| then | ||
| rm -rf "$try_workspace" >/dev/null 2>&1 | ||
| fi | ||
|
|
||
| if [ -f "$expected" ] | ||
| then | ||
| rm "$expected" | ||
| fi | ||
|
|
||
| if [ -f "$target" ] | ||
| then | ||
| rm "$target" | ||
| fi | ||
| } | ||
|
|
||
| trap 'cleanup' EXIT | ||
|
|
||
| try_workspace="$(mktemp -d)" | ||
| cd "$try_workspace" || return 9 | ||
| touch test | ||
|
|
||
| # Set up expected output | ||
| expected="$(mktemp)" | ||
| ls -l >"$expected" | ||
|
|
||
| # Set up target output | ||
| target="$(mktemp)" | ||
|
|
||
| sudo "$TRY" ls -l | tee "$target" || return 1 | ||
| diff -q "$expected" "$target" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #!/bin/sh | ||
|
|
||
| TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree)}" | ||
| TRY="$TRY_TOP/try" | ||
|
|
||
| control=$(id -Gn) | ||
| testing=$("$TRY" -D "$(mktemp -d)" id -Gn 2>/dev/null) | ||
|
|
||
| if [ "$control" = "$testing" ] | ||
| then | ||
| exit 0 | ||
| else | ||
| exit 1 | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #!/bin/sh | ||
|
|
||
| TRY_TOP="${TRY_TOP:-$(git rev-parse --show-toplevel --show-superproject-working-tree)}" | ||
| TRY="$TRY_TOP/try" | ||
|
|
||
| control=$(id -un) | ||
| testing=$(sudo "$TRY" -D "$(mktemp -d)" -u "$USER" id -un) | ||
|
|
||
| if [ "$control" = "$testing" ] | ||
| then | ||
| exit 0 | ||
| else | ||
| exit 1 | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -172,6 +172,12 @@ autodetect_union_helper() { | |
| fi | ||
| } | ||
|
|
||
| # notify the mapper that we're up | ||
| echo "a" > "$SOCKET" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's use different sentinels when sending to and receiving from the mapper---we should check that the sentinels are what we expect, too. |
||
|
|
||
| # wait for mapper to finish | ||
| cat "$SOCKET" > /dev/null | ||
|
|
||
| # Detect if union_helper is set, if not, we try to autodetect them | ||
| if [ -z "$UNION_HELPER" ] | ||
| then | ||
|
|
@@ -257,30 +263,46 @@ EOF | |
| cat >"$chroot_executable" <<EOF | ||
| #!/bin/sh | ||
|
|
||
| unset START_DIR SANDBOX_DIR UNION_HELPER DIRS_AND_MOUNTS TRY_EXIT_STATUS | ||
| unset START_DIR SANDBOX_DIR UNION_HELPER DIRS_AND_MOUNTS TRY_EXIT_STATUS SOCKET | ||
| unset script_to_execute chroot_executable try_mount_log | ||
|
|
||
| mount -t proc proc /proc && | ||
| cd "$START_DIR" && | ||
| . "$script_to_execute" | ||
| if [ "$EUSER" ] | ||
| then | ||
| su - $EUSER -c "cd "$START_DIR" && sh $script_to_execute" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we confident that all of the other variables we care about are marked as export? This should probably be
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a test to ensure that: (a) normal (non- |
||
| else | ||
| cd "$START_DIR" && | ||
| . "$script_to_execute" | ||
| fi | ||
| EOF | ||
|
|
||
| echo "$@" >"$script_to_execute" | ||
|
|
||
| # `$script_to_execute` need not be +x to be sourced | ||
| chmod +x "$mount_and_execute" "$chroot_executable" | ||
|
|
||
| if [ "$EUSER" ] | ||
| then | ||
| chown "$EUSER" "$script_to_execute" | ||
| fi | ||
|
|
||
| # enable job control so interactive commands will play nicely with try asking for user input later(for committing). #5 | ||
| [ -t 0 ] && set -m | ||
|
|
||
| SOCKET="$(mktemp -u)" | ||
| mkfifo "$SOCKET" | ||
| export SOCKET | ||
|
|
||
| # Running mapper in a subshell to suppress job control [1] + Done message | ||
| (mapper&) | ||
|
|
||
| # --mount: mounting and unmounting filesystems will not affect the rest of the system outside the unshare | ||
| # --map-root-user: map to the superuser UID and GID in the newly created user namespace. | ||
| # --user: the process will have a distinct set of UIDs, GIDs and capabilities. | ||
| # --pid: create a new process namespace (needed fr procfs to work right) | ||
| # --fork: necessary if we do --pid | ||
| # "Creation of a persistent PID namespace will fail if the --fork option is not also specified." | ||
| # shellcheck disable=SC2086 # we want field splitting! | ||
| unshare --mount --map-root-user --user --pid --fork $EXTRA_NS "$mount_and_execute" | ||
| unshare --mount --user --pid --fork $EXTRA_NS "$mount_and_execute" | ||
| TRY_EXIT_STATUS=$? | ||
|
|
||
| # remove symlink | ||
|
|
@@ -533,6 +555,30 @@ error() { | |
| exit "$exit_status" | ||
| } | ||
|
|
||
| ################################################################################ | ||
| # Change uid/gid mapping | ||
| ################################################################################ | ||
|
|
||
| mapper() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a more informative name, like |
||
| cat "$SOCKET" > /dev/null | ||
| # Get the pid of the unshare process with current pid as parent | ||
| pid=$(pgrep -P $$ -f unshare) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a new external dependency?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, we're adding libcap2-bin and procps/procps-ng. readme will be updated appropriately.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's write the process id on the socket, save ourselves the trouble. |
||
|
|
||
| # Map root user to current user, and all groups | ||
| # Usage: gidmapper targetpid outeruid inneruid uidcount outergid innergid uidcount | ||
| if [ "$(id -u)" = 0 ] | ||
| then | ||
| # If we're running as root, we can map all the users | ||
| gidmapper "$pid" 0 0 65535 0 0 65535 | ||
| else | ||
| # If not running as root, we can only mount the caller user | ||
| gidmapper "$pid" 0 "$(id -u)" 1 0 0 65535 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. investigate |
||
| fi | ||
|
|
||
| # Notify the unshare process that we have finished | ||
| echo "a" > "$SOCKET" | ||
| } | ||
|
|
||
| ################################################################################ | ||
| # Argument parsing | ||
| ################################################################################ | ||
|
|
@@ -544,6 +590,7 @@ Usage: $TRY_COMMAND [-nvhyx] [-i PATTERN] [-D DIR] [-U PATH] [-L dir1:dir2:...] | |
| -n don't commit or prompt for commit (overrides -y) | ||
| -y assume yes to all prompts (overrides -n) | ||
| -x prevent network access (by unsharing the network namespace) | ||
| -u username user to run the command with (requires root) | ||
| -i PATTERN ignore paths that match PATTERN on summary and commit | ||
| -D DIR work in DIR (implies -n) | ||
| -U PATH path to unionfs helper (e.g., mergerfs, unionfs-fuse) | ||
|
|
@@ -571,13 +618,19 @@ NO_COMMIT="interactive" | |
| # Includes all patterns given using the `-i` flag; will be used with `grep -f` | ||
| IGNORE_FILE="$(mktemp)" | ||
|
|
||
| while getopts ":yvnhxi:D:U:L:" opt | ||
| while getopts ":yvnhxu:i:D:U:L:" opt | ||
|
|
||
| do | ||
| case "$opt" in | ||
| (y) NO_COMMIT="commit";; | ||
| (n) NO_COMMIT="show";; | ||
| (i) echo "$OPTARG" >>"$IGNORE_FILE";; | ||
| (u) if [ "$(id -u)" -ne "0" ] | ||
| then | ||
| error "need root for -u" 2 | ||
| fi | ||
| EUSER="$OPTARG" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to unconditionally clear |
||
| export EUSER;; | ||
| (D) if ! [ -d "$OPTARG" ] | ||
| then | ||
| error "could not find sandbox directory '$OPTARG'" 2 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #include <pthread.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <unistd.h> | ||
|
|
||
| void* map_uids(void* args) { | ||
| char *targetpid = argv[1]; | ||
| char *outeruid = argv[2]; | ||
| char *inneruid = argv[3]; | ||
| char *uidcount = argv[4]; | ||
| char *outergid = argv[5]; | ||
| char *innergid = argv[6]; | ||
| char *gidcount = argv[7]; | ||
|
|
||
| // Build path strings | ||
| char uid_path[100]; | ||
| sprintf(uid_path, "/proc/%s/uid_map", targetpid); | ||
|
|
||
| char gid_path[100]; | ||
| sprintf(gid_path, "/proc/%s/gid_map", targetpid); | ||
|
|
||
| // Build mapping strings | ||
| char uid_map[100]; | ||
| sprintf(uid_map, "%s %s %s", outeruid, inneruid, uidcount); | ||
|
|
||
| char gid_map[100]; | ||
| sprintf(gid_map, "%s %s %s", outergid, innergid, gidcount); | ||
|
|
||
| // Write mappings | ||
| FILE *uid_file = fopen(uid_path, "w"); | ||
| fprintf(uid_file, "%s", uid_map); | ||
| fclose(uid_file); | ||
|
|
||
| FILE *gid_file = fopen(gid_path, "w"); | ||
| fprintf(gid_file, "%s", gid_map); | ||
| fclose(gid_file); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| int main(int argc, char* argv[]) { | ||
|
|
||
| char *usage = "Usage: gidmapper targetpid outeruid inneruid uidcount outergid innergid gidcount"; | ||
|
|
||
| if(argc < 8) { | ||
| fprintf(stderr, "%s\n", usage); | ||
| exit(1); | ||
| } | ||
|
|
||
| pthread_t mapper_thread; | ||
| pthread_create(&mapper_thread, NULL, map_uids, NULL); | ||
|
|
||
| pthread_join(mapper_thread, NULL); | ||
|
|
||
| return 0; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.