Skip to content

Instantly share code, notes, and snippets.

@ztmr
Last active December 28, 2015 22:19
Show Gist options
  • Select an option

  • Save ztmr/7571054 to your computer and use it in GitHub Desktop.

Select an option

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
/*
* 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