[lxc-devel] usernsselfmap
Serge Hallyn
serge.hallyn at ubuntu.com
Wed Mar 6 22:25:25 UTC 2013
Hey guys,
just to help play with user namespaces some more I pushed a C version
of Eric's script for completely unprivileged use of user namespaces to
https://code.launchpad.net/~serge-hallyn/+junk/nsexec and to the
nsexec package in ppa:serge-hallyn/userns-natty. Appending the code
below as well. The point is: you unshare a new user namespace, and
in there you map uid 0 to your host uid, then start a shell. This
requires zero setup on the host (so the shadow package updates to define
per-user subuids are not needed for these games). From that shell you
can unshare mounts, network, uts namespace, etc, and basically be root
in your fake little domain.
It's fun. I just './usernsselfmap', and I can pretend I'm root.
BTW, Eric, where the heck does one find the latest version of
util-linux? Latest I could find did not yet know about userns.
(Once that lands in ubuntu I can drop my nsexec altogether, as well
as lxc-unshare)
Anyway, enjoy!
#include <stdio.h>
#include <sched.h>
#include <linux/sched.h>
#include <stdlib.h>
#include <errno.h>
int writemaps(pid_t pid)
{
FILE *fout;
char path[1024];
int origuid = getuid();
int origgid = getgid();
int ret;
printf("starting from uid %d gid %d\n", origuid, origgid);
snprintf(path, 1024, "/proc/%d/uid_map", pid);
fout = fopen(path, "w");
ret = fprintf(fout, "0 %d 1\n", origuid);
if (ret < 0) {
perror("writing uidmap\n");
return -1;
}
ret = fclose(fout);
if (ret < 0) {
perror("closing uidmap\n");
return -1;
}
snprintf(path, 1024, "/proc/%d/gid_map", pid);
fout = fopen(path, "w");
ret = fprintf(fout, "0 %d 1\n", origgid);
if (ret < 0) {
perror("writing gidmap\n");
return -1;
}
ret = fclose(fout);
if (ret < 0) {
perror("closing gidmap\n");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
char *args[] = { "/bin/bash", NULL };
int ret, fromchildpipe[2], tochildpipe[2];
pid_t pid;
ret = pipe(fromchildpipe);
if (ret < 0)
exit(1);
ret = pipe(tochildpipe);
if (ret < 0)
exit(1);
pid = fork();
if (pid < 0)
exit(1);
int x = 0;
if (pid > 0) {
int status;
close(fromchildpipe[1]);
close(tochildpipe[0]);
read(fromchildpipe[0], &x, sizeof(x));
if (x == 1)
exit(1);
close(fromchildpipe[0]);
ret = writemaps(pid);
if (ret < 0) {
printf("Error writing maps for %d\n", pid);
x = 1;
}
write(tochildpipe[1], &x, sizeof(x));
close(tochildpipe[1]);
waitpid(pid, &status, __WALL);
exit(x);
}
close(fromchildpipe[0]);
close(tochildpipe[1]);
ret = unshare(CLONE_NEWUSER);
if (ret < 0) {
perror("unshare");
x = 1;
write(fromchildpipe[1], &x, sizeof(x));
exit(1);
}
write(fromchildpipe[1], &x, sizeof(x));
read(tochildpipe[0], &x, sizeof(x));
if (x == 1) {
printf("error in parent writing uid maps\n");
exit(1);
}
close(fromchildpipe[1]);
close(tochildpipe[0]);
ret = setgid(0);
if (ret < 0)
perror("setgid");
ret = setuid(0);
perror("setuid");
printf("execing bash (I am now %d %d)\n", getuid(), getgid());
execv(args[0], args);
}
More information about the lxc-devel
mailing list