pax_global_header00006660000000000000000000000064110173647030014514gustar00rootroot0000000000000052 comment=5023991db2355698e50052a53cb429020f5e3146 switchsh-0~20070801/000077500000000000000000000000001101736470300140715ustar00rootroot00000000000000switchsh-0~20070801/switchsh.c000066400000000000000000000061261101736470300160760ustar00rootroot00000000000000/* * This program creates a new filesystem namespace, bind mounts /bin/bash * over /bin/sh and runs its arguments. * It needs to be installed setuid root and will drop the extra privileges * before running the argument. * * gcc -O2 -s switchsh.c -o switchsh * chown root:root switchsh * chmod u+s switchsh * ./switchsh /bin/sh --version * * Written by Marco d'Itri , released to the public domain. */ #include #include #include #include #include #include #include #include #include /* syscall */ #include #include #include #include /* waitpid */ #include /* mount */ # include /* unshare */ #ifndef USE_CLONE /* old kernel headers may lack the system call number */ # if defined(__NR_unshare) # elif defined(__i386__) # define __NR_unshare 310 # elif defined(__x86_64__) # define __NR_unshare 272 # elif defined(__powerpc__) || defined(__powerpc64__) # define __NR_unshare 282 # else /* update the kernel headers or add the number for the architecture */ # error "unshare unsupported on this architecture!" # endif # ifndef SYS_unshare # define SYS_unshare __NR_unshare # endif # if !(__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 4) static inline int unshare(int flags) { return syscall(SYS_unshare, flags); } # endif #endif /* Prototypes */ void err_quit(const char *, ...) __attribute__ ((noreturn, format(printf, 1, 2))); void err_sys(const char *, ...) __attribute__ ((noreturn, format(printf, 1, 2))); int main(int argc, char *argv[]) { int pid; if (!*++argv) err_quit("Usage: switchsh PROGRAM [ARG]..."); #ifdef USE_CLONE /* think about this as fork(2)... */ pid = syscall(SYS_clone, CLONE_NEWNS | SIGCHLD, 0); #else pid = fork(); #endif if (pid < 0) { /* error */ if (errno == EPERM) err_quit("This program must be setuid root!"); err_sys("fork"); } if (pid > 0) { /* parent */ int status; /* wait for the child */ waitpid(pid, &status, 0); exit(WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status) + 128); } /* child */ #ifndef USE_CLONE if (unshare(CLONE_NEWNS) < 0) { if (errno == ENOSYS) err_quit("unshare requires a kernel >= 2.6.16"); else err_sys("unshare"); } #endif if (mount("/bin/bash", "/bin/sh", NULL, MS_BIND, NULL) < 0) { if (errno == EPERM) err_quit("This program must be setuid root!"); err_sys("mount"); } /* permanently drop privileges */ if (setgid(getgid()) < 0) err_sys("cannot drop GID 0"); if (setuid(getuid()) < 0) err_sys("cannot drop UID 0"); execv(*argv, argv); err_sys("Can't exec %s", argv[0]); } /* Error routines */ void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(errno)); va_end(ap); exit(1); } void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); exit(1); }