aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2018-06-23 13:02:14 +0200
committerToni Uhlig <matzeton@googlemail.com>2018-06-23 13:02:14 +0200
commit5c03f3f3e32a3c4d9b30e8765e1082dd9886020c (patch)
tree6f8f3b886d900924894bb09ba32dfa9be5ccb34b /src
parent2ada2322f6d8dc31c22b563acd7c2fb9d87cb8a3 (diff)
improved filesystem managment (blacklisting, mounting read-only/read-write objects), improved jail/pty handling
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'src')
-rw-r--r--src/capabilities.c4
-rw-r--r--src/filesystem.c201
-rw-r--r--src/filesystem.h8
-rw-r--r--src/jail.c29
-rw-r--r--src/options.c4
-rw-r--r--src/options.h2
-rw-r--r--src/utils.c26
-rw-r--r--src/utils.h2
8 files changed, 151 insertions, 125 deletions
diff --git a/src/capabilities.c b/src/capabilities.c
index 57658cc..d7fcf5b 100644
--- a/src/capabilities.c
+++ b/src/capabilities.c
@@ -221,12 +221,12 @@ void caps_drop_dac_override(int noprofile)
if (getuid() == 0 && !noprofile) {
if (prctl(PR_CAPBSET_DROP, CAP_DAC_OVERRIDE, 0, 0, 0)) {
} else {
- D("%s", "Drop CAP_DAC_OVERRIDE");
+ D2("%s", "Drop CAP_DAC_OVERRIDE");
}
if (prctl(PR_CAPBSET_DROP, CAP_DAC_READ_SEARCH, 0, 0, 0)) {
} else {
- D("%s", "Drop CAP_DAC_READ_SEARCH");
+ D2("%s", "Drop CAP_DAC_READ_SEARCH");
}
}
}
diff --git a/src/filesystem.c b/src/filesystem.c
index 1a55111..3fbb0d6 100644
--- a/src/filesystem.c
+++ b/src/filesystem.c
@@ -2,6 +2,7 @@
#include "config.h"
#else
#define POTD_RODIR "/var/run/potd-rodir"
+#define POTD_ROFILE "/var/run/potd-rofile"
#endif
#include <stdio.h>
@@ -16,6 +17,7 @@
#include "log.h"
#include "utils.h"
+#include "options.h"
typedef struct MountData {
/*
@@ -29,47 +31,54 @@ typedef struct MountData {
char *fstype;
} MountData;
-typedef enum {
+typedef enum fs_oper {
BLACKLIST_FILE,
- BLACKLIST_NOLOG,
MOUNT_READONLY,
MOUNT_TMPFS,
MOUNT_NOEXEC,
MOUNT_RDWR,
OPERATION_MAX
-} OPERATION;
+} fs_oper;
typedef enum {
UNSUCCESSFUL,
SUCCESSFUL
-} LAST_DISABLE_OPERATION;
-LAST_DISABLE_OPERATION last_disable = UNSUCCESSFUL;
+} last_disable_oper;
+last_disable_oper last_disable = UNSUCCESSFUL;
-static void disable_file(OPERATION op, const char *filename);
+static void disable_file(fs_oper op, const char *filename);
+static void disable_file_newroot(fs_oper op, const char *filename,
+ const char *newroot);
static int get_mount_flags(const char *path, unsigned long *flags);
static MountData *
get_last_mount(void);
static void fs_rdonly(const char *dir);
static void fs_rdwr(const char *dir);
static void fs_noexec(const char *dir);
+static void fs_var_lock(void);
+static void fs_var_tmp(void);
-#define MAX_BUF 4096
-static char mbuf[MAX_BUF];
+static char mbuf[BUFSIZ];
static MountData mdata;
-static void disable_file(OPERATION op, const char *filename)
+static void disable_file(fs_oper op, const char *filename)
{
char *fname;
struct stat s;
+ int rv;
assert(filename);
- assert(op <OPERATION_MAX);
+ assert(op < OPERATION_MAX);
last_disable = UNSUCCESSFUL;
// Resolve all symlinks
fname = realpath(filename, NULL);
if (fname == NULL && errno != EACCES) {
+ if (errno == ENOENT)
+ W_STRERR("%s: realpath '%s'", __func__, filename);
+ else
+ E_STRERR("%s: realpath '%s'", __func__, filename);
return;
}
@@ -78,16 +87,18 @@ static void disable_file(OPERATION op, const char *filename)
// realpath and stat funtions will fail on FUSE filesystems
// they don't seem to like a uid of 0
// force mounting
- int rv = mount(POTD_RODIR, filename, "none", MS_BIND, "mode=400,gid=0");
+ rv = mount(getopt_str(OPT_RODIR), filename, NULL,
+ MS_BIND, "mode=400,gid=0");
if (rv == 0) {
last_disable = SUCCESSFUL;
} else {
- rv = mount(POTD_RODIR, filename, "none", MS_BIND, "mode=400,gid=0");
+ rv = mount(getopt_str(OPT_ROFILE), filename, NULL, MS_BIND,
+ "mode=400,gid=0");
if (rv == 0)
last_disable = SUCCESSFUL;
}
if (last_disable == SUCCESSFUL) {
- D("%s: disable '%s' successful", __func__, filename);
+ D("%s: disable '%s' forced", __func__, filename);
} else {
W2("%s: '%s' is an invalid file, skipping...", __func__, filename);
}
@@ -105,7 +116,7 @@ static void disable_file(OPERATION op, const char *filename)
}
// modify the file
- if (op == BLACKLIST_FILE || op == BLACKLIST_NOLOG) {
+ if (op == BLACKLIST_FILE) {
// some distros put all executables under /usr/bin and make /bin a symbolic link
if ((strcmp(fname, "/bin") == 0 || strcmp(fname, "/usr/bin") == 0) &&
is_link(filename) &&
@@ -120,11 +131,17 @@ static void disable_file(OPERATION op, const char *filename)
}
if (S_ISDIR(s.st_mode)) {
- if (mount(POTD_RODIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
+ if (mount(getopt_str(OPT_RODIR), fname, NULL, MS_BIND,
+ "mode=400,gid=0") < 0)
+ {
FATAL("%s: disable dir '%s'", __func__, fname);
+ }
} else {
- if (mount(POTD_RODIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
+ if (mount(getopt_str(OPT_ROFILE), fname, NULL, MS_BIND,
+ "mode=400,gid=0") < 0)
+ {
FATAL("%s: disable file '%s'", __func__, fname);
+ }
}
last_disable = SUCCESSFUL;
}
@@ -133,7 +150,7 @@ static void disable_file(OPERATION op, const char *filename)
fs_rdonly(fname);
// TODO: last_disable = SUCCESSFUL;
} else if (op == MOUNT_RDWR) {
- D("%s: Mounting read-only '%s'", __func__, fname);
+ D("%s: Mounting read-write '%s'", __func__, fname);
fs_rdwr(fname);
// TODO: last_disable = SUCCESSFUL;
} else if (op == MOUNT_NOEXEC) {
@@ -144,8 +161,11 @@ static void disable_file(OPERATION op, const char *filename)
if (S_ISDIR(s.st_mode)) {
D("%s: Mounting tmpfs on '%s'", __func__, fname);
// preserve owner and mode for the directory
- if (mount("tmpfs", fname, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC, 0) < 0)
+ if (mount("tmpfs", fname, "tmpfs", MS_NOSUID|MS_NODEV|
+ MS_STRICTATIME|MS_REC, 0) < 0)
+ {
FATAL("%s: mounting tmpfs '%s'", __func__, fname);
+ }
/* coverity[toctou] */
if (chown(fname, s.st_uid, s.st_gid) == -1)
FATAL("%s: mounting tmpfs chown '%s'", __func__, fname);
@@ -160,6 +180,17 @@ static void disable_file(OPERATION op, const char *filename)
free(fname);
}
+static void disable_file_newroot(fs_oper op, const char *filename,
+ const char *newroot)
+{
+ char path[PATH_MAX];
+
+ snprintf(path, sizeof path, "%s/%s", newroot, filename);
+ disable_file(op, path);
+// if (last_disable == SUCCESSFUL)
+// fs_rdonly(path, 1);
+}
+
static int get_mount_flags(const char *path, unsigned long *flags)
{
struct statvfs buf;
@@ -179,13 +210,17 @@ get_last_mount(void)
FILE *fp = fopen("/proc/self/mountinfo", "r");
char *ptr;
int cnt = 1;
+ size_t len;
if (!fp)
goto errexit;
mbuf[0] = '\0';
- while (fgets(mbuf, MAX_BUF, fp)) {}
+ while (fgets(mbuf, BUFSIZ, fp)) {}
fclose(fp);
+ len = strnlen(mbuf, BUFSIZ);
+ if (mbuf[len - 1] == '\n')
+ mbuf[len - 1] = 0;
D("%s: %s", __func__, mbuf);
// extract filesystem name, directory and filesystem type
@@ -229,7 +264,7 @@ get_last_mount(void)
goto errexit;
}
- D("%s: fsname='%s' dir='%s' fstype=%s\n", __func__, mdata.fsname,
+ D("%s: fsname='%s' dir='%s' fstype=%s", __func__, mdata.fsname,
mdata.dir, mdata.fstype);
return &mdata;
errexit:
@@ -340,87 +375,72 @@ static void fs_noexec(const char *dir)
}
}
-// Disable /mnt, /media, /run/mount and /run/media access
-void fs_mnt(void)
-{
- disable_file(BLACKLIST_FILE, "/mnt");
- disable_file(BLACKLIST_FILE, "/media");
- disable_file(BLACKLIST_FILE, "/run/mount");
- disable_file(BLACKLIST_FILE, "//run/media");
-}
-
// mount /proc and /sys directories
-void fs_proc_sys(void)
+void fs_proc_sys(const char *newroot)
{
- D("%s: Remounting /proc and /proc/sys filesystems", __func__);
- if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
- FATAL("%s: mounting /proc", __func__);
+ char path[PATH_MAX] = {0};
+
+ assert(newroot);
+
+ snprintf(path, sizeof path, "%s/proc", newroot);
+ D("%s: Remounting '%s'", __func__, path);
+ if (mount("proc", path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC,
+ NULL) < 0)
+ {
+ FATAL("%s: mounting %s", __func__, path);
+ }
// remount /proc/sys readonly
- if (mount("/proc/sys", "/proc/sys", NULL, MS_BIND | MS_REC, NULL) < 0 ||
- mount(NULL, "/proc/sys", NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|
+ snprintf(path, sizeof path, "%s/proc/sys", newroot);
+ D("%s: Remounting '%s'", __func__, path);
+ if (mount(path, path, "none", MS_BIND|MS_REC, NULL) < 0 ||
+ mount(NULL, path, "none", MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|
MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0)
{
- FATAL("%s: mounting /proc/sys", __func__);
+ FATAL("%s: mounting %s", __func__, path);
}
/* Mount a version of /sys that describes the network namespace */
- D("%s: Remounting /sys directory", __func__);
- if (umount2("/sys", MNT_DETACH) < 0)
- W("%s: failed to unmount /sys", __func__);
- if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) {
- W("%s: failed to mount /sys", __func__);
- } else {
- W("%s: remount /sys", __func__);
+ snprintf(path, sizeof path, "%s/sys", newroot);
+ D("%s: Remounting '%s'", __func__, path);
+ umount2(path, MNT_DETACH);
+ if (mount("sysfs", path, "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|
+ MS_REC, NULL) < 0)
+ {
+ FATAL("%s: mounting '%s'", __func__, path);
}
+}
- disable_file(BLACKLIST_FILE, "/sys/firmware");
- disable_file(BLACKLIST_FILE, "/sys/hypervisor");
- disable_file(BLACKLIST_FILE, "/sys/power");
- disable_file(BLACKLIST_FILE, "/sys/kernel/debug");
- disable_file(BLACKLIST_FILE, "/sys/kernel/vmcoreinfo");
- disable_file(BLACKLIST_FILE, "/sys/kernel/uevent_helper");
-
- // various /proc/sys files
- disable_file(BLACKLIST_FILE, "/proc/sys/security");
- disable_file(BLACKLIST_FILE, "/proc/sys/efi/vars");
- disable_file(BLACKLIST_FILE, "/proc/sys/fs/binfmt_misc");
- disable_file(BLACKLIST_FILE, "/proc/sys/kernel/core_pattern");
- disable_file(BLACKLIST_FILE, "/proc/sys/kernel/modprobe");
- disable_file(BLACKLIST_FILE, "/proc/sysrq-trigger");
- disable_file(BLACKLIST_FILE, "/proc/sys/kernel/hotplug");
- disable_file(BLACKLIST_FILE, "/proc/sys/vm/panic_on_oom");
-
- // various /proc files
- disable_file(BLACKLIST_FILE, "/proc/irq");
- disable_file(BLACKLIST_FILE, "/proc/bus");
- disable_file(BLACKLIST_FILE, "/proc/config.gz");
- disable_file(BLACKLIST_FILE, "/proc/sched_debug");
- disable_file(BLACKLIST_FILE, "/proc/timer_list");
- disable_file(BLACKLIST_FILE, "/proc/timer_stats");
- disable_file(BLACKLIST_FILE, "/proc/kcore");
- disable_file(BLACKLIST_FILE, "/proc/kallsyms");
- disable_file(BLACKLIST_FILE, "/proc/mem");
- disable_file(BLACKLIST_FILE, "/proc/kmem");
-
- // remove kernel symbol information
- disable_file(BLACKLIST_FILE, "/usr/src/linux");
- disable_file(BLACKLIST_FILE, "/lib/modules");
- disable_file(BLACKLIST_FILE, "/usr/lib/debug");
- disable_file(BLACKLIST_FILE, "/boot");
-
- // disable /selinux
- disable_file(BLACKLIST_FILE, "/selinux");
-
- // disable /dev/port
- disable_file(BLACKLIST_FILE, "/dev/port");
-
- // disable /dev/kmsg and /proc/kmsg
- disable_file(BLACKLIST_FILE, "/dev/kmsg");
- disable_file(BLACKLIST_FILE, "/proc/kmsg");
+void fs_disable_files(const char *newroot)
+{
+ size_t i;
+ const char *blacklist_objects[] = {
+ "/sys/firmware", "/sys/hypervisor", "/sys/power", "/sys/kernel/debug",
+ "/sys/kernel/vmcoreinfo", "/sys/kernel/uevent_helper",
+ /* various /proc/sys files */
+ "/proc/sys/security", "/proc/sys/efi/vars", "/proc/sys/fs/binfmt_misc",
+ "/proc/sys/kernel/core_pattern", "/proc/sys/kernel/modprobe",
+ "/proc/sysrq-trigger", "/proc/sys/kernel/hotplug",
+ "/proc/sys/vm/panic_on_oom",
+ /* various /proc files */
+ "/proc/acpi", "/proc/apm", "/proc/asound", "/proc/fs", "/proc/scsi",
+ "/proc/irq", "/proc/bus", "/proc/config.gz", "/proc/sched_debug",
+ "/proc/timer_list", "/proc/timer_stats", "/proc/kcore", "/proc/keys",
+ "/proc/kallsyms", "/proc/mem", "/proc/kmem",
+ /* remove kernel symbol information */
+ "/usr/src/linux", "/lib/modules", "/usr/lib/debug", "/boot",
+ /* other */
+ "/sys/fs/selinux", "/selinux",
+ "/dev/port", "/dev/kmsg", "/proc/kmsg",
+ "/mnt", "/media", "/run/mount", "/run/media"
+ };
+
+ for (i = 0; i < SIZEOF(blacklist_objects); ++i) {
+ disable_file_newroot(BLACKLIST_FILE, blacklist_objects[i], newroot);
+ }
}
-void fs_var_lock(void)
+static void fs_var_lock(void)
{
char *lnk;
@@ -451,7 +471,7 @@ void fs_var_lock(void)
}
}
-void fs_var_tmp(void)
+static void fs_var_tmp(void)
{
struct stat s;
@@ -483,6 +503,8 @@ void fs_basic_fs(void)
fs_rdonly("/lib32");
fs_rdonly("/libx32");
fs_rdonly("/usr");
+ D("%s: mounting read-only /proc/sys/net ", __func__);
+ fs_rdonly("/proc/sys/net");
// update /var directory in order to support multiple sandboxes running on the same root directory
fs_var_lock();
@@ -492,4 +514,3 @@ void fs_basic_fs(void)
fs_rdwr("/var/cache");
fs_rdwr("/var/utmp");
}
-
diff --git a/src/filesystem.h b/src/filesystem.h
index af3517b..bd801f6 100644
--- a/src/filesystem.h
+++ b/src/filesystem.h
@@ -1,13 +1,9 @@
#ifndef POTD_FILESYSTEM_H
#define POTD_FILESYSTEM_H 1
-void fs_mnt(void);
+void fs_disable_files(const char *newroot);
-void fs_proc_sys(void);
-
-void fs_var_lock(void);
-
-void fs_var_tmp(void);
+void fs_proc_sys(const char *newroot);
void fs_basic_fs(void);
diff --git a/src/jail.c b/src/jail.c
index 157a563..e302123 100644
--- a/src/jail.c
+++ b/src/jail.c
@@ -3,6 +3,7 @@
#include <sched.h>
#include <signal.h>
#include <pty.h>
+#include <utmp.h>
#include <sys/signalfd.h>
#include <sys/wait.h>
#include <sys/prctl.h>
@@ -13,6 +14,7 @@
#include "socket.h"
#include "pseccomp.h"
#include "capabilities.h"
+#include "filesystem.h"
#include "utils.h"
#include "log.h"
#include "options.h"
@@ -252,7 +254,7 @@ static int jail_childfn(prisoner_process *ctx)
const char *path_devpts = "/dev/pts";
const char *path_proc = "/proc";
const char *path_shell = "/bin/sh";
- int i, s, master_fd;
+ int i, s, master_fd, slave_fd;
int unshare_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|
CLONE_NEWNS/*|CLONE_NEWUSER*/;
//unsigned int ug_map[3] = { 0, 10000, 65535 };
@@ -287,12 +289,16 @@ static int jail_childfn(prisoner_process *ctx)
if (unshare(unshare_flags))
FATAL("Unshare prisoner %d", self_pid);
+ D2("Mounting rootfs to '%s'", ctx->newroot);
+ mount_root();
+ fs_proc_sys(ctx->newroot);
+ fs_disable_files(ctx->newroot);
+
D2("Safe change root to: '%s'", ctx->newroot);
if (safe_chroot(ctx->newroot))
FATAL("Safe jail chroot to '%s' failed", ctx->newroot);
- D2("Mounting rootfs to '%s'", ctx->newroot);
- mount_root();
+ fs_basic_fs();
D2("Checking Shell '%s%s'", ctx->newroot, path_shell);
if (access(path_shell, R_OK|X_OK))
@@ -328,18 +334,20 @@ static int jail_childfn(prisoner_process *ctx)
FATAL("Device file creation failed for rootfs '%s%s'",
ctx->newroot, path_dev);
- D2("Forking a new pty process for "
- "parent %d", self_pid);
- child_pid = forkpty(&master_fd, NULL, NULL, NULL);
+ if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL))
+ FATAL("%s", "openpty");
+
+ child_pid = fork();
switch (child_pid) {
case -1:
+ close(master_fd);
+ close(slave_fd);
FATAL("Forking a new process for the slave tty from "
"parent pty with pid %d",
self_pid);
break;
case 0:
- if (mount_proc(path_proc))
- exit(EXIT_FAILURE);
+ fs_proc_sys("");
socket_set_ifaddr(&ctx->client_psock, "lo", "127.0.0.1", "255.0.0.0");
/*
if (update_setgroups_self(0))
@@ -349,6 +357,10 @@ static int jail_childfn(prisoner_process *ctx)
if (update_guid_map(getpid(), ug_map, 1))
exit(EXIT_FAILURE);
*/
+ close(master_fd);
+ if (login_tty(slave_fd))
+ exit(EXIT_FAILURE);
+
if (close_fds_except(0, 1, 2, -1))
exit(EXIT_FAILURE);
@@ -386,6 +398,7 @@ static int jail_childfn(prisoner_process *ctx)
exit(EXIT_FAILURE);
break;
default:
+ close(slave_fd);
if (set_fd_nonblock(master_fd)) {
E_STRERR("Pty master fd nonblock for prisoner pid %d",
child_pid);
diff --git a/src/options.c b/src/options.c
index 0737c39..e390ac8 100644
--- a/src/options.c
+++ b/src/options.c
@@ -80,6 +80,10 @@ static struct opt options[OPT_MAX+1] = {
"Example: 127.0.0.1:33333\n"),
OPT(OT_PATH, .str = POTD_DEFROOT, "rootfs",
"path to root directory/image\n", NULL),
+ OPT(OT_PATH, .str = POTD_RODIR, "rodir",
+ "path to an empty directory for ro-bind-mounts\n", NULL),
+ OPT(OT_PATH, .str = POTD_ROFILE, "rofile",
+ "path to an empty file for ro-bind-mounts\n", NULL),
OPT(OT_PATH, .str = POTD_NETNS_RUN_DIR, "netns-rundir",
"set the network namespace run directory\n", NULL),
OPT(OT_PATH, .str = POTD_SSH_RUN_DIR, "ssh-rundir",
diff --git a/src/options.h b/src/options.h
index 30e5e94..824cd6c 100644
--- a/src/options.h
+++ b/src/options.h
@@ -10,6 +10,8 @@ typedef enum opt_name {
OPT_PROTOCOL,
OPT_JAIL,
OPT_ROOT,
+ OPT_RODIR,
+ OPT_ROFILE,
OPT_NETNS_RUN_DIR,
OPT_SSH_RUN_DIR,
OPT_CHUSER,
diff --git a/src/utils.c b/src/utils.c
index 49d16d7..08229d9 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -462,9 +462,9 @@ void chk_chroot(void)
void mount_root(void)
{
int s;
- s = mount("", "/", "none", MS_SLAVE|MS_REC, NULL);
+ s = mount("none", "/", NULL, MS_SLAVE|MS_REC, NULL);
if (s)
- s = mount("", "/", "none", MS_PRIVATE|MS_REC, NULL);
+ s = mount("none", "/", NULL, MS_PRIVATE|MS_REC, NULL);
if (s)
chk_chroot();
}
@@ -501,21 +501,6 @@ int mount_pts(const char *mount_path)
return 0;
}
-int mount_proc(const char *mount_path)
-{
- int s;
-
- umount(mount_path);
- s = mount("proc", mount_path, "proc",
- MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL);
- if (s) {
- E_STRERR("Mount proc filesystem to %s", mount_path);
- return 1;
- }
-
- return 0;
-}
-
int setup_network_namespace(const char *name)
{
int fd;
@@ -991,6 +976,13 @@ int selftest_minimal_requirements(void)
N("%s", "Selftest success");
exit(EXIT_SUCCESS);
}
+
+ s = open(getopt_str(OPT_ROFILE), O_WRONLY|O_CREAT|O_TRUNC);
+ if (s < 0 && errno != EEXIST)
+ goto error;
+ if (mkdir(getopt_str(OPT_RODIR), S_IRWXU) && errno != EEXIST)
+ goto error;
+
return 0;
error:
if (getopt_used(OPT_RUNTEST)) {
diff --git a/src/utils.h b/src/utils.h
index 2b745dc..87e87d1 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -50,8 +50,6 @@ int mount_dev(const char *mount_path);
int mount_pts(const char *mount_path);
-int mount_proc(const char *mount_path);
-
int setup_network_namespace(const char *name);
int switch_network_namespace(const char *name);