Last active
December 28, 2015 22:19
-
-
Save ztmr/7571054 to your computer and use it in GitHub Desktop.
Spawn a new Linux process by inheriting all the kernel namespaces of the existing process specified by PID
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Module : ns_exec | |
| * Created : 20-NOV-2013 20:50 | |
| * Author : Tomas Morstein (www.IDEA.cz) | |
| * Description : Spawn a new process by inheriting all the kernel | |
| * namespaces of the existing process specified by PID | |
| * Prereqs : Linux >=3.8 built with kernel namespace support; | |
| * Older kernels does not implement all the namespaces | |
| * and even the 3.8 shipped by Ubuntu does not come | |
| * with CONFIG_USER_NS enabled: | |
| * $ grep -He 'CONFIG_[A-Z]*_NS=y' /boot/config* | |
| */ | |
| #define _GNU_SOURCE | |
| #include <fcntl.h> | |
| #include <sched.h> | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <stdarg.h> | |
| #include <stdbool.h> | |
| #define MAX_PATH 256 | |
| #define MAX_ERROR 256 | |
| #define ERR_LABEL "\%NSEXEC-E-" | |
| void trap_error (bool die, const char * msg, ...) { | |
| va_list args; | |
| char errmsg [MAX_ERROR]; | |
| va_start (args, msg); | |
| vsnprintf (errmsg, MAX_ERROR, msg, args); | |
| va_end (args); | |
| perror (errmsg); | |
| if (die) exit (EXIT_FAILURE); | |
| } | |
| void join_ns (char * pid, char * ns) { | |
| int fd; | |
| char path [MAX_PATH]; | |
| snprintf (path, MAX_PATH, "/proc/%s/ns/%s", pid, ns); | |
| /* Open the namespace */ | |
| if ((fd = open (path, O_RDONLY)) < 0) { | |
| trap_error (false, ERR_LABEL "OPEN, %s", path); | |
| return; | |
| } | |
| /* Join it after all */ | |
| if (setns (fd, 0) < 0) | |
| trap_error (false, ERR_LABEL "SETNS, %s", path); | |
| } | |
| void exec_ns (char * parent_pid, char * cmd, char * args []) { | |
| /* Join all the namespaces */ | |
| /* NOTE: since the 'mnt' namespace may not allow us | |
| * to see the original host's '/proc' filesystem, | |
| * we have to join it at last. | |
| */ | |
| join_ns (parent_pid, "ipc"); | |
| join_ns (parent_pid, "net"); | |
| join_ns (parent_pid, "pid"); | |
| join_ns (parent_pid, "uts"); | |
| join_ns (parent_pid, "user"); | |
| join_ns (parent_pid, "mnt"); | |
| /* Execute a command within all the joined namespaces; | |
| * execvp returns only if the error occurs... | |
| */ | |
| execvp (cmd, args); | |
| trap_error (true, ERR_LABEL "EXECVP, %s", cmd); | |
| } | |
| int main (int argc, char * argv []) { | |
| if (argc < 3) { | |
| fprintf (stderr, "%s <pid> <cmd> [args...]\n", argv [0]); | |
| exit (EXIT_FAILURE); | |
| } | |
| exec_ns (argv [1], argv [2], &argv [2]); | |
| /* Just a formality, exec_ns should not return/exit */ | |
| return (EXIT_SUCCESS); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment