Commit 50e98013 by Daniel Lezcano Committed by Daniel Lezcano

replace fork_ns by lxc_clone

Make use of the lxc_clone function and do no longer use the fork_ns function. The lxc-unshare utility has been changed to always do a fork. Signed-off-by: 's avatarDaniel Lezcano <dlezcano@fr.ibm.com>
parent 5bb3ba8a
...@@ -40,7 +40,6 @@ void usage(char *cmd) ...@@ -40,7 +40,6 @@ void usage(char *cmd)
{ {
fprintf(stderr, "%s <options> [command]\n", basename(cmd)); fprintf(stderr, "%s <options> [command]\n", basename(cmd));
fprintf(stderr, "Options are:\n"); fprintf(stderr, "Options are:\n");
fprintf(stderr, "\t -f : fork and unshare (automatic when unsharing the pids)\n");
fprintf(stderr, "\t -s flags: Ored list of flags to unshare:\n" \ fprintf(stderr, "\t -s flags: Ored list of flags to unshare:\n" \
"\t MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n"); "\t MOUNT, PID, UTSNAME, IPC, USER, NETWORK\n");
fprintf(stderr, "\t -u <id> : new id to be set if -s USER is specified\n"); fprintf(stderr, "\t -u <id> : new id to be set if -s USER is specified\n");
...@@ -101,7 +100,7 @@ static int lxc_namespace_2_cloneflag(char *namespace) ...@@ -101,7 +100,7 @@ static int lxc_namespace_2_cloneflag(char *namespace)
return -1; return -1;
} }
static int lxc_fill_namespace_flags(char *flaglist, long *flags) static int lxc_fill_namespace_flags(char *flaglist, int *flags)
{ {
char *token, *saveptr = NULL; char *token, *saveptr = NULL;
int aflag; int aflag;
...@@ -125,17 +124,48 @@ static int lxc_fill_namespace_flags(char *flaglist, long *flags) ...@@ -125,17 +124,48 @@ static int lxc_fill_namespace_flags(char *flaglist, long *flags)
return 0; return 0;
} }
struct start_arg {
char ***args;
int *flags;
uid_t *uid;
};
static int do_start(void *arg)
{
struct start_arg *start_arg = arg;
char **args = *start_arg->args;
int flags = *start_arg->flags;
uid_t uid = *start_arg->uid;
if (flags & CLONE_NEWUSER && setuid(uid)) {
ERROR("failed to set uid %d: %s", uid, strerror(errno));
exit(1);
}
execvp(args[0], args);
ERROR("failed to exec: '%s': %s", args[0], strerror(errno));
return 1;
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int opt, status = 1, hastofork = 0; int opt, status;
int ret; int ret;
char *namespaces = NULL; char *namespaces = NULL;
char **args; char **args;
long flags = 0; int flags = 0;
uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */ uid_t uid = -1; /* valid only if (flags & CLONE_NEWUSER) */
pid_t pid; pid_t pid;
while ((opt = getopt(argc, argv, "fs:u:")) != -1) { struct start_arg start_arg = {
.args = &args,
.uid = &uid,
.flags = &flags,
};
while ((opt = getopt(argc, argv, "s:u:")) != -1) {
switch (opt) { switch (opt) {
case 's': case 's':
namespaces = optarg; namespaces = optarg;
...@@ -144,74 +174,31 @@ int main(int argc, char *argv[]) ...@@ -144,74 +174,31 @@ int main(int argc, char *argv[])
uid = lookup_user(optarg); uid = lookup_user(optarg);
if (uid == -1) if (uid == -1)
return 1; return 1;
case 'f':
hastofork = 1;
break;
} }
} }
args = &argv[optind]; args = &argv[optind];
ret = lxc_fill_namespace_flags(namespaces, &flags); ret = lxc_fill_namespace_flags(namespaces, &flags);
if (ret) if (ret)
usage(argv[0]); usage(argv[0]);
if (!(flags & CLONE_NEWUSER) && uid != -1) { if (!(flags & CLONE_NEWUSER) && uid != -1) {
ERROR("-u <uid> need -s USER option"); ERROR("-u <uid> needs -s USER option");
return 1;
}
if ((flags & CLONE_NEWPID) || hastofork) {
if (!argv[optind] || !strlen(argv[optind]))
usage(argv[0]);
pid = fork_ns(flags);
if (pid < 0) {
ERROR("failed to fork into a new namespace: %s",
strerror(errno));
return 1;
}
if (!pid) {
if (flags & CLONE_NEWUSER && setuid(uid)) {
ERROR("failed to set uid %d: %s",
uid, strerror(errno));
exit(1);
}
execvp(args[0], args);
ERROR("failed to exec: '%s': %s",
argv[0], strerror(errno));
exit(1);
}
if (waitpid(pid, &status, 0) < 0)
ERROR("failed to wait for '%d'", pid);
return status;
}
if (unshare_ns(flags)) {
ERROR("failed to unshare the current process: %s",
strerror(errno));
return 1; return 1;
} }
if (flags & CLONE_NEWUSER && setuid(uid)) { pid = lxc_clone(do_start, &start_arg, flags);
ERROR("failed to set uid %d: %s", if (pid < 0) {
uid, strerror(errno)); ERROR("failed to clone");
return 1; return -1;
} }
if (argv[optind] && strlen(argv[optind])) { if (waitpid(pid, &status, 0) < 0) {
execvp(args[0], args); ERROR("failed to wait for '%d'", pid);
ERROR("failed to exec: '%s': %s", return -1;
argv[0], strerror(errno));
return 1;
} }
return 0; return status;
} }
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <signal.h> #include <signal.h>
#include <fcntl.h> #include <fcntl.h>
#include <termios.h> #include <termios.h>
#include <namespace.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/mount.h> #include <sys/mount.h>
...@@ -452,12 +453,79 @@ void lxc_abort(const char *name, struct lxc_handler *handler) ...@@ -452,12 +453,79 @@ void lxc_abort(const char *name, struct lxc_handler *handler)
kill(handler->pid, SIGKILL); kill(handler->pid, SIGKILL);
} }
struct start_arg {
const char *name;
char *const *argv;
struct lxc_handler *handler;
int *sv;
};
static int do_start(void *arg)
{
struct start_arg *start_arg = arg;
struct lxc_handler *handler = start_arg->handler;
const char *name = start_arg->name;
char *const *argv = start_arg->argv;
int *sv = start_arg->sv;
int err = -1, sync;
if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
SYSERROR("failed to set sigprocmask");
goto out_child;
}
close(sv[1]);
/* Be sure we don't inherit this after the exec */
fcntl(sv[0], F_SETFD, FD_CLOEXEC);
/* Tell our father he can begin to configure the container */
if (write(sv[0], &sync, sizeof(sync)) < 0) {
SYSERROR("failed to write socket");
goto out_child;
}
/* Wait for the father to finish the configuration */
if (read(sv[0], &sync, sizeof(sync)) < 0) {
SYSERROR("failed to read socket");
goto out_child;
}
/* Setup the container, ip, names, utsname, ... */
if (lxc_setup(name, handler->tty, &handler->tty_info)) {
ERROR("failed to setup the container");
goto out_warn_father;
}
if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
SYSERROR("failed to remove CAP_SYS_BOOT capability");
goto out_child;
}
execvp(argv[0], argv);
SYSERROR("failed to exec %s", argv[0]);
out_warn_father:
/* If the exec fails, tell that to our father */
if (write(sv[0], &err, sizeof(err)) < 0)
SYSERROR("failed to write the socket");
out_child:
return -1;
}
int lxc_spawn(const char *name, struct lxc_handler *handler, char *const argv[]) int lxc_spawn(const char *name, struct lxc_handler *handler, char *const argv[])
{ {
int sv[2]; int sv[2];
int clone_flags; int clone_flags;
int err = -1, sync; int err = -1, sync;
struct start_arg start_arg = {
.name = name,
.argv = argv,
.handler = handler,
.sv = sv,
};
/* Synchro socketpair */ /* Synchro socketpair */
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) { if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv)) {
SYSERROR("failed to create communication socketpair"); SYSERROR("failed to create communication socketpair");
...@@ -469,58 +537,12 @@ int lxc_spawn(const char *name, struct lxc_handler *handler, char *const argv[]) ...@@ -469,58 +537,12 @@ int lxc_spawn(const char *name, struct lxc_handler *handler, char *const argv[])
clone_flags |= CLONE_NEWNET; clone_flags |= CLONE_NEWNET;
/* Create a process in a new set of namespaces */ /* Create a process in a new set of namespaces */
handler->pid = fork_ns(clone_flags); handler->pid = lxc_clone(do_start, &start_arg, clone_flags);
if (handler->pid < 0) { if (handler->pid < 0) {
SYSERROR("failed to fork into a new namespace"); SYSERROR("failed to fork into a new namespace");
goto out_close; goto out_close;
} }
if (!handler->pid) {
if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
SYSERROR("failed to set sigprocmask");
goto out_child;
}
close(sv[1]);
/* Be sure we don't inherit this after the exec */
fcntl(sv[0], F_SETFD, FD_CLOEXEC);
/* Tell our father he can begin to configure the container */
if (write(sv[0], &sync, sizeof(sync)) < 0) {
SYSERROR("failed to write socket");
goto out_child;
}
/* Wait for the father to finish the configuration */
if (read(sv[0], &sync, sizeof(sync)) < 0) {
SYSERROR("failed to read socket");
goto out_child;
}
/* Setup the container, ip, names, utsname, ... */
if (lxc_setup(name, handler->tty, &handler->tty_info)) {
ERROR("failed to setup the container");
goto out_warn_father;
}
if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
SYSERROR("failed to remove CAP_SYS_BOOT capability");
goto out_child;
}
execvp(argv[0], argv);
SYSERROR("failed to exec %s", argv[0]);
out_warn_father:
/* If the exec fails, tell that to our father */
if (write(sv[0], &err, sizeof(err)) < 0)
SYSERROR("failed to write the socket");
out_child:
exit(err);
}
close(sv[0]); close(sv[0]);
/* Wait for the child to be ready */ /* Wait for the child to be ready */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment