Merge pull request #2469 from 2xsec/bugfix

tools: lxc-unshare: use lxc list for interface names
This commit is contained in:
Christian Brauner 2018-07-14 17:50:47 +02:00 committed by GitHub
commit 63f9c9e607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -41,6 +41,7 @@
#include "arguments.h" #include "arguments.h"
#include "caps.h" #include "caps.h"
#include "list.h"
#include "log.h" #include "log.h"
#include "namespace.h" #include "namespace.h"
#include "utils.h" #include "utils.h"
@ -57,12 +58,6 @@ struct start_arg {
const char *want_hostname; const char *want_hostname;
}; };
struct my_iflist
{
char *mi_ifname;
struct my_iflist *mi_next;
};
static int my_parser(struct lxc_arguments *args, int c, char *arg); static int my_parser(struct lxc_arguments *args, int c, char *arg);
static inline int sethostname_including_android(const char *name, size_t len); static inline int sethostname_including_android(const char *name, size_t len);
static int get_namespace_flags(char *namespaces); static int get_namespace_flags(char *namespaces);
@ -70,8 +65,9 @@ static bool lookup_user(const char *optarg, uid_t *uid);
static int mount_fs(const char *source, const char *target, const char *type); static int mount_fs(const char *source, const char *target, const char *type);
static void lxc_setup_fs(void); static void lxc_setup_fs(void);
static int do_start(void *arg); static int do_start(void *arg);
static void free_ifname_list(void);
static struct my_iflist *tmpif, *my_iflist; static struct lxc_list ifnames;
static const struct option my_longopts[] = { static const struct option my_longopts[] = {
{"namespaces", required_argument, 0, 's'}, {"namespaces", required_argument, 0, 's'},
@ -112,6 +108,8 @@ Options :\n\
static int my_parser(struct lxc_arguments *args, int c, char *arg) static int my_parser(struct lxc_arguments *args, int c, char *arg)
{ {
struct lxc_list *tmplist;
switch (c) { switch (c) {
case 's': case 's':
args->flags = get_namespace_flags(arg); args->flags = get_namespace_flags(arg);
@ -128,15 +126,15 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
args->want_hostname = arg; args->want_hostname = arg;
break; break;
case 'i': case 'i':
tmpif = malloc(sizeof(*tmpif)); tmplist = malloc(sizeof(*tmplist));
if (!tmpif) { if (!tmplist) {
SYSERROR("Failed to malloc()"); SYSERROR("Failed to alloc lxc list");
free_ifname_list();
return -1; return -1;
} }
tmpif->mi_ifname = arg; lxc_list_add_elem(tmplist, arg);
tmpif->mi_next = my_iflist; lxc_list_add_tail(&ifnames, tmplist);
my_iflist = tmpif;
break; break;
case 'd': case 'd':
args->daemonize = 1; args->daemonize = 1;
@ -302,6 +300,16 @@ static int do_start(void *arg)
return 1; return 1;
} }
static void free_ifname_list(void)
{
struct lxc_list *iterator, *next;
lxc_list_for_each_safe (iterator, &ifnames, next) {
lxc_list_del(iterator);
free(iterator);
}
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int ret; int ret;
@ -309,6 +317,8 @@ int main(int argc, char *argv[])
struct lxc_log log; struct lxc_log log;
struct start_arg start_arg; struct start_arg start_arg;
lxc_list_init(&ifnames);
if (lxc_caps_init()) if (lxc_caps_init())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -324,32 +334,39 @@ int main(int argc, char *argv[])
log.quiet = my_args.quiet; log.quiet = my_args.quiet;
log.lxcpath = my_args.lxcpath[0]; log.lxcpath = my_args.lxcpath[0];
if (lxc_log_init(&log)) if (lxc_log_init(&log)) {
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
} }
if (!*my_args.argv) { if (!*my_args.argv) {
ERROR("A command to execute in the new namespace is required"); ERROR("A command to execute in the new namespace is required");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (my_args.flags == 0) { if (my_args.flags == 0) {
ERROR("A namespace to execute command is required"); ERROR("A namespace to execute command is required");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!(my_args.flags & CLONE_NEWNET) && my_iflist) { if (!(my_args.flags & CLONE_NEWNET) && lxc_list_len(&ifnames) > 0) {
ERROR("-i <interfacename> needs -s NETWORK option"); ERROR("-i <interfacename> needs -s NETWORK option");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!(my_args.flags & CLONE_NEWUTS) && my_args.want_hostname) { if (!(my_args.flags & CLONE_NEWUTS) && my_args.want_hostname) {
ERROR("-H <hostname> needs -s UTSNAME option"); ERROR("-H <hostname> needs -s UTSNAME option");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!(my_args.flags & CLONE_NEWNS) && my_args.want_default_mounts) { if (!(my_args.flags & CLONE_NEWNS) && my_args.want_default_mounts) {
ERROR("-M needs -s MOUNT option"); ERROR("-M needs -s MOUNT option");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -357,6 +374,7 @@ int main(int argc, char *argv[])
start_arg.wait_fd = eventfd(0, EFD_CLOEXEC); start_arg.wait_fd = eventfd(0, EFD_CLOEXEC);
if (start_arg.wait_fd < 0) { if (start_arg.wait_fd < 0) {
SYSERROR("Failed to create eventfd"); SYSERROR("Failed to create eventfd");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@ -368,11 +386,11 @@ int main(int argc, char *argv[])
start_arg.flags = my_args.flags; start_arg.flags = my_args.flags;
start_arg.want_hostname = my_args.want_hostname; start_arg.want_hostname = my_args.want_hostname;
start_arg.want_default_mounts = my_args.want_default_mounts; start_arg.want_default_mounts = my_args.want_default_mounts;
start_arg.wait_fd = -1;
pid = lxc_clone(do_start, &start_arg, my_args.flags); pid = lxc_clone(do_start, &start_arg, my_args.flags);
if (pid < 0) { if (pid < 0) {
ERROR("Failed to clone"); ERROR("Failed to clone");
free_ifname_list();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -387,6 +405,7 @@ int main(int argc, char *argv[])
ret = snprintf(umap, 100, "%d %d 1\n" , my_args.uid, getuid()); ret = snprintf(umap, 100, "%d %d 1\n" , my_args.uid, getuid());
if (ret < 0 || ret >= 100) { if (ret < 0 || ret >= 100) {
ERROR("snprintf is failed"); ERROR("snprintf is failed");
free_ifname_list();
close(start_arg.wait_fd); close(start_arg.wait_fd);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -394,6 +413,7 @@ int main(int argc, char *argv[])
ret = write_id_mapping(ID_TYPE_UID, pid, umap, strlen(umap)); ret = write_id_mapping(ID_TYPE_UID, pid, umap, strlen(umap));
if (ret < 0) { if (ret < 0) {
ERROR("Failed to map uid"); ERROR("Failed to map uid");
free_ifname_list();
close(start_arg.wait_fd); close(start_arg.wait_fd);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -401,19 +421,26 @@ int main(int argc, char *argv[])
ret = write(start_arg.wait_fd, &wait_val, sizeof(wait_val)); ret = write(start_arg.wait_fd, &wait_val, sizeof(wait_val));
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to write eventfd"); SYSERROR("Failed to write eventfd");
free_ifname_list();
close(start_arg.wait_fd); close(start_arg.wait_fd);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
if (my_iflist) { if (lxc_list_len(&ifnames) > 0) {
for (tmpif = my_iflist; tmpif; tmpif = tmpif->mi_next) { struct lxc_list *iterator;
pid_t pid; char* ifname;
pid_t pid;
lxc_list_for_each(iterator, &ifnames) {
ifname = iterator->elem;
if (!ifname)
continue;
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
SYSERROR("Failed to move network device \"%s\" to network namespace", SYSERROR("Failed to move network device \"%s\" to network namespace",
tmpif->mi_ifname); ifname);
continue; continue;
} }
@ -424,14 +451,16 @@ int main(int argc, char *argv[])
if (ret < 0 || ret >= 256) if (ret < 0 || ret >= 256)
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
execlp("ip", "ip", "link", "set", "dev", tmpif->mi_ifname, "netns", buf, (char *)NULL); execlp("ip", "ip", "link", "set", "dev", ifname, "netns", buf, (char *)NULL);
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
if (wait_for_pid(pid) != 0) if (wait_for_pid(pid) != 0)
SYSERROR("Could not move interface \"%s\" into container %d", SYSERROR("Could not move interface \"%s\" into container %d",
tmpif->mi_ifname, pid); ifname, pid);
} }
free_ifname_list();
} }
if (my_args.daemonize) if (my_args.daemonize)