#include <../include/openpty.h>
#endif
-#ifdef HAVE_LINUX_MEMFD_H
-#include <linux/memfd.h>
-#endif
-
#include "af_unix.h"
#include "caps.h" /* for lxc_caps_last_cap() */
#include "cgroup.h"
#include "namespace.h"
#include "network.h"
#include "parse.h"
+#include "ringbuf.h"
#include "storage.h"
#include "storage/aufs.h"
#include "storage/overlay.h"
#if IS_BIONIC
#include <../include/lxcmntent.h>
-#ifndef HAVE_PRLIMIT
-#include <../include/prlimit.h>
-#endif
#else
#include <mntent.h>
#endif
-lxc_log_define(lxc_conf, lxc);
-
-#if HAVE_LIBCAP
-#ifndef CAP_SETFCAP
-#define CAP_SETFCAP 31
-#endif
-
-#ifndef CAP_MAC_OVERRIDE
-#define CAP_MAC_OVERRIDE 32
-#endif
-
-#ifndef CAP_MAC_ADMIN
-#define CAP_MAC_ADMIN 33
-#endif
-#endif
-
-#ifndef PR_CAPBSET_DROP
-#define PR_CAPBSET_DROP 24
-#endif
-
-#ifndef LO_FLAGS_AUTOCLEAR
-#define LO_FLAGS_AUTOCLEAR 4
-#endif
-
-#ifndef CAP_SETUID
-#define CAP_SETUID 7
-#endif
-
-#ifndef CAP_SETGID
-#define CAP_SETGID 6
+#if !defined(HAVE_PRLIMIT) && defined(HAVE_PRLIMIT64)
+#include <../include/prlimit.h>
#endif
-/* needed for cgroup automount checks, regardless of whether we
- * have included linux/capability.h or not */
-#ifndef CAP_SYS_ADMIN
-#define CAP_SYS_ADMIN 21
-#endif
+lxc_log_define(lxc_conf, lxc);
/* Define pivot_root() if missing from the C library */
#ifndef HAVE_PIVOT_ROOT
extern int pivot_root(const char * new_root, const char * put_old);
#endif
-/* Define sethostname() if missing from the C library */
-#ifndef HAVE_SETHOSTNAME
-static int sethostname(const char * name, size_t len)
-{
-#ifdef __NR_sethostname
- return syscall(__NR_sethostname, name, len);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-#endif
-
#ifndef MS_PRIVATE
#define MS_PRIVATE (1<<18)
#endif
#define MS_LAZYTIME (1<<25)
#endif
-/* memfd_create() */
-#ifndef MFD_CLOEXEC
-#define MFD_CLOEXEC 0x0001U
-#endif
-
-#ifndef MFD_ALLOW_SEALING
-#define MFD_ALLOW_SEALING 0x0002U
-#endif
-
-#ifndef HAVE_MEMFD_CREATE
-static int memfd_create(const char *name, unsigned int flags) {
- #ifndef __NR_memfd_create
- #if defined __i386__
- #define __NR_memfd_create 356
- #elif defined __x86_64__
- #define __NR_memfd_create 319
- #elif defined __arm__
- #define __NR_memfd_create 385
- #elif defined __aarch64__
- #define __NR_memfd_create 279
- #elif defined __s390__
- #define __NR_memfd_create 350
- #elif defined __powerpc__
- #define __NR_memfd_create 360
- #elif defined __sparc__
- #define __NR_memfd_create 348
- #elif defined __blackfin__
- #define __NR_memfd_create 390
- #elif defined __ia64__
- #define __NR_memfd_create 1340
- #elif defined _MIPS_SIM
- #if _MIPS_SIM == _MIPS_SIM_ABI32
- #define __NR_memfd_create 4354
- #endif
- #if _MIPS_SIM == _MIPS_SIM_NABI32
- #define __NR_memfd_create 6318
- #endif
- #if _MIPS_SIM == _MIPS_SIM_ABI64
- #define __NR_memfd_create 5314
- #endif
- #endif
- #endif
- #ifdef __NR_memfd_create
- return syscall(__NR_memfd_create, name, flags);
- #else
- errno = ENOSYS;
- return -1;
- #endif
-}
-#else
-extern int memfd_create(const char *name, unsigned int flags);
-#endif
-
char *lxchook_names[NUM_LXC_HOOKS] = {"pre-start", "pre-mount", "mount",
"autodev", "start", "stop",
- "post-stop", "clone", "destroy"};
-
-typedef int (*instantiate_cb)(struct lxc_handler *, struct lxc_netdev *);
+ "post-stop", "clone", "destroy",
+ "start-host"};
struct mount_opt {
char *name;
struct lxc_conf *current_config;
#endif
-/* Declare this here, since we don't want to reshuffle the whole file. */
-static int in_caplist(int cap, struct lxc_list *caps);
-
-static int instantiate_veth(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_phys(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_empty(struct lxc_handler *, struct lxc_netdev *);
-static int instantiate_none(struct lxc_handler *, struct lxc_netdev *);
-
-static instantiate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
- [LXC_NET_VETH] = instantiate_veth,
- [LXC_NET_MACVLAN] = instantiate_macvlan,
- [LXC_NET_VLAN] = instantiate_vlan,
- [LXC_NET_PHYS] = instantiate_phys,
- [LXC_NET_EMPTY] = instantiate_empty,
- [LXC_NET_NONE] = instantiate_none,
-};
-
-static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
-static int shutdown_none(struct lxc_handler *, struct lxc_netdev *);
-
-static instantiate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
- [LXC_NET_VETH] = shutdown_veth,
- [LXC_NET_MACVLAN] = shutdown_macvlan,
- [LXC_NET_VLAN] = shutdown_vlan,
- [LXC_NET_PHYS] = shutdown_phys,
- [LXC_NET_EMPTY] = shutdown_empty,
- [LXC_NET_NONE] = shutdown_none,
-};
-
static struct mount_opt mount_opt[] = {
{ "async", 1, MS_SYNCHRONOUS },
{ "atime", 1, MS_NOATIME },
return run_buffer(buffer);
}
-static int run_script(const char *name, const char *section, const char *script,
- ...)
+int run_script(const char *name, const char *section, const char *script, ...)
{
int ret;
char *buffer, *p;
{"/proc/self/fd/2", "stderr"},
};
-static int setup_dev_symlinks(const struct lxc_rootfs *rootfs)
+static int lxc_setup_dev_symlinks(const struct lxc_rootfs *rootfs)
{
char path[MAXPATHLEN];
int ret,i;
return 0;
}
-/*
- * Build a space-separate list of ptys to pass to systemd.
- */
+/* Build a space-separate list of ptys to pass to systemd. */
static bool append_ptyname(char **pp, char *name)
{
char *p;
return true;
}
-static int lxc_setup_tty(struct lxc_conf *conf)
+static int lxc_setup_ttys(struct lxc_conf *conf)
{
int i, ret;
const struct lxc_tty_info *tty_info = &conf->tty_info;
struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
ret = snprintf(path, sizeof(path), "/dev/tty%d", i + 1);
- if (ret < 0 || (size_t)ret >= sizeof(path)) {
- ERROR("pathname too long for ttys");
+ if (ret < 0 || (size_t)ret >= sizeof(path))
return -1;
- }
if (ttydir) {
/* create dev/lxc/tty%d" */
ret = snprintf(lxcpath, sizeof(lxcpath),
"/dev/%s/tty%d", ttydir, i + 1);
- if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
- ERROR("pathname too long for ttys");
+ if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
return -1;
- }
ret = creat(lxcpath, 0660);
if (ret < 0 && errno != EEXIST) {
- SYSERROR("failed to create \"%s\"", lxcpath);
+ SYSERROR("Failed to create \"%s\"", lxcpath);
return -1;
}
if (ret >= 0)
ret = unlink(path);
if (ret < 0 && errno != ENOENT) {
- SYSERROR("failed to unlink \"%s\"", path);
+ SYSERROR("Failed to unlink \"%s\"", path);
return -1;
}
ret = mount(pty_info->name, lxcpath, "none", MS_BIND, 0);
if (ret < 0) {
- WARN("failed to bind mount \"%s\" onto \"%s\"",
+ WARN("Failed to bind mount \"%s\" onto \"%s\"",
pty_info->name, path);
continue;
}
ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d",
ttydir, i + 1);
- if (ret < 0 || (size_t)ret >= sizeof(lxcpath)) {
- ERROR("tty pathname too long");
+ if (ret < 0 || (size_t)ret >= sizeof(lxcpath))
return -1;
- }
ret = symlink(lxcpath, path);
if (ret < 0) {
- SYSERROR("failed to create symlink \"%s\" -> \"%s\"",
+ SYSERROR("Failed to create symlink \"%s\" -> \"%s\"",
path, lxcpath);
return -1;
}
if (ret < 0) {
ret = creat(path, 0660);
if (ret < 0) {
- SYSERROR("failed to create \"%s\"", path);
+ SYSERROR("Failed to create \"%s\"", path);
/* this isn't fatal, continue */
} else {
close(ret);
ret = mount(pty_info->name, path, "none", MS_BIND, 0);
if (ret < 0) {
- SYSERROR("failed to mount '%s'->'%s'", pty_info->name, path);
+ SYSERROR("Failed to mount '%s'->'%s'", pty_info->name, path);
continue;
}
- DEBUG("bind mounted \"%s\" onto \"%s\"", pty_info->name,
+ DEBUG("Bind mounted \"%s\" onto \"%s\"", pty_info->name,
path);
}
}
}
- INFO("finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+ INFO("Finished setting up %d /dev/tty<N> device(s)", tty_info->nbtty);
+ return 0;
+}
+
+int lxc_allocate_ttys(const char *name, struct lxc_conf *conf)
+{
+ struct lxc_tty_info *tty_info = &conf->tty_info;
+ int i, ret;
+
+ /* no tty in the configuration */
+ if (!conf->tty)
+ return 0;
+
+ tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
+ if (!tty_info->pty_info) {
+ SYSERROR("failed to allocate struct *pty_info");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < conf->tty; i++) {
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+ process_lock();
+ ret = openpty(&pty_info->master, &pty_info->slave,
+ pty_info->name, NULL, NULL);
+ process_unlock();
+ if (ret) {
+ SYSERROR("failed to create pty device number %d", i);
+ tty_info->nbtty = i;
+ lxc_delete_tty(tty_info);
+ return -ENOTTY;
+ }
+
+ DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
+ pty_info->name, pty_info->master, pty_info->slave);
+
+ /* Prevent leaking the file descriptors to the container */
+ ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
+ if (ret < 0)
+ WARN("failed to set FD_CLOEXEC flag on master fd %d of "
+ "pty device \"%s\": %s",
+ pty_info->master, pty_info->name, strerror(errno));
+
+ ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
+ if (ret < 0)
+ WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
+ "pty device \"%s\": %s",
+ pty_info->slave, pty_info->name, strerror(errno));
+
+ pty_info->busy = 0;
+ }
+
+ tty_info->nbtty = conf->tty;
+
+ INFO("finished allocating %d pts devices", conf->tty);
return 0;
}
+void lxc_delete_tty(struct lxc_tty_info *tty_info)
+{
+ int i;
+
+ for (i = 0; i < tty_info->nbtty; i++) {
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+ close(pty_info->master);
+ close(pty_info->slave);
+ }
+
+ free(tty_info->pty_info);
+ tty_info->pty_info = NULL;
+ tty_info->nbtty = 0;
+}
+
+static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
+{
+ int i;
+ struct lxc_conf *conf = handler->conf;
+ struct lxc_tty_info *tty_info = &conf->tty_info;
+ int sock = handler->data_sock[0];
+ int ret = -1;
+
+ if (!conf->tty)
+ return 0;
+
+ for (i = 0; i < conf->tty; i++) {
+ int ttyfds[2];
+ struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
+
+ ttyfds[0] = pty_info->master;
+ ttyfds[1] = pty_info->slave;
+
+ ret = lxc_abstract_unix_send_fds(sock, ttyfds, 2, NULL, 0);
+ if (ret < 0)
+ break;
+
+ TRACE("Send pty \"%s\" with master fd %d and slave fd %d to "
+ "parent", pty_info->name, pty_info->master, pty_info->slave);
+ }
+
+ if (ret < 0)
+ ERROR("Failed to send %d ttys to parent: %s", conf->tty,
+ strerror(errno));
+ else
+ TRACE("Sent %d ttys to parent", conf->tty);
+
+ return ret;
+}
+
+static int lxc_create_ttys(struct lxc_handler *handler)
+{
+ int ret = -1;
+ struct lxc_conf *conf = handler->conf;
+
+ ret = lxc_allocate_ttys(handler->name, conf);
+ if (ret < 0) {
+ ERROR("Failed to allocate ttys");
+ goto on_error;
+ }
+
+ ret = lxc_send_ttys_to_parent(handler);
+ if (ret < 0) {
+ ERROR("Failed to send ttys to parent");
+ goto on_error;
+ }
+
+ if (!conf->is_execute) {
+ ret = lxc_setup_ttys(conf);
+ if (ret < 0) {
+ ERROR("Failed to setup ttys");
+ goto on_error;
+ }
+ }
+
+ if (conf->pty_names) {
+ ret = setenv("container_ttys", conf->pty_names, 1);
+ if (ret < 0)
+ SYSERROR("Failed to set \"container_ttys=%s\"", conf->pty_names);
+ }
+
+ ret = 0;
+
+on_error:
+ lxc_delete_tty(&conf->tty_info);
+
+ return ret;
+}
+
static int setup_rootfs_pivot_root(const char *rootfs)
{
int oldroot = -1, newroot = -1;
return 0;
}
-static int setup_hw_addr(char *hwaddr, const char *ifname)
-{
- struct sockaddr sockaddr;
- struct ifreq ifr;
- int ret, fd, saved_errno;
-
- ret = lxc_convert_mac(hwaddr, &sockaddr);
- if (ret) {
- ERROR("mac address '%s' conversion failed : %s",
- hwaddr, strerror(-ret));
- return -1;
- }
-
- memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_name[IFNAMSIZ-1] = '\0';
- memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
+static int parse_resource(const char *res) {
+ size_t i;
+ int resid = -1;
- fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd < 0) {
- ERROR("socket failure : %s", strerror(errno));
- return -1;
+ for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) {
+ if (strcmp(res, limit_opt[i].name) == 0)
+ return limit_opt[i].value;
}
- ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
- saved_errno = errno;
- close(fd);
- if (ret)
- ERROR("ioctl failure : %s", strerror(saved_errno));
-
- DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifr.ifr_name);
-
- return ret;
+ /* try to see if it's numeric, so the user may specify
+ * resources that the running kernel knows about but
+ * we don't */
+ if (lxc_safe_int(res, &resid) == 0)
+ return resid;
+ return -1;
}
-static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
-{
- struct lxc_list *iterator;
- struct lxc_inetdev *inetdev;
- int err;
-
- lxc_list_for_each(iterator, ip) {
+int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
+ struct lxc_list *it;
+ struct lxc_limit *lim;
+ int resid;
- inetdev = iterator->elem;
+ lxc_list_for_each(it, limits) {
+ lim = it->elem;
- err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
- &inetdev->bcast, inetdev->prefix);
- if (err) {
- ERROR("failed to setup_ipv4_addr ifindex %d : %s",
- ifindex, strerror(-err));
+ resid = parse_resource(lim->resource);
+ if (resid < 0) {
+ ERROR("unknown resource %s", lim->resource);
return -1;
}
- }
-
- return 0;
-}
-
-static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
-{
- struct lxc_list *iterator;
- struct lxc_inet6dev *inet6dev;
- int err;
-
- lxc_list_for_each(iterator, ip) {
-
- inet6dev = iterator->elem;
- err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
- &inet6dev->mcast, &inet6dev->acast,
- inet6dev->prefix);
- if (err) {
- ERROR("failed to setup_ipv6_addr ifindex %d : %s",
- ifindex, strerror(-err));
+#if HAVE_PRLIMIT || HAVE_PRLIMIT64
+ if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
+ ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
return -1;
}
+#else
+ ERROR("Cannot set limit %s as prlimit is missing", lim->resource);
+ return -1;
+#endif
}
-
return 0;
}
-static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
-{
- char ifname[IFNAMSIZ];
- int err;
- const char *net_type_name;
- char *current_ifname = ifname;
-
- /* empty network namespace */
- if (!netdev->ifindex) {
- if (netdev->flags & IFF_UP) {
- err = lxc_netdev_up("lo");
- if (err) {
- ERROR("failed to set the loopback up : %s",
- strerror(-err));
- return -1;
- }
- }
-
- if (netdev->type == LXC_NET_EMPTY)
- return 0;
-
- if (netdev->type == LXC_NET_NONE)
- return 0;
-
- if (netdev->type != LXC_NET_VETH) {
- net_type_name = lxc_net_type_to_str(netdev->type);
- ERROR("%s networks are not supported for containers "
- "not setup up by privileged users",
- net_type_name);
- return -1;
- }
-
- netdev->ifindex = if_nametoindex(netdev->name);
- }
+static char *default_rootfs_mount = LXCROOTFSMOUNT;
- /* get the new ifindex in case of physical netdev */
- if (netdev->type == LXC_NET_PHYS) {
- if (!(netdev->ifindex = if_nametoindex(netdev->link))) {
- ERROR("failed to get ifindex for %s",
- netdev->link);
- return -1;
- }
- }
+struct lxc_conf *lxc_conf_init(void)
+{
+ struct lxc_conf *new;
+ int i;
- /* retrieve the name of the interface */
- if (!if_indextoname(netdev->ifindex, current_ifname)) {
- ERROR("no interface corresponding to index '%d'",
- netdev->ifindex);
- return -1;
+ new = malloc(sizeof(*new));
+ if (!new) {
+ ERROR("lxc_conf_init : %s", strerror(errno));
+ return NULL;
}
+ memset(new, 0, sizeof(*new));
- /* Default: let the system to choose one interface name.
- * When the IFLA_IFNAME attribute is passed something like "<prefix>%d"
- * netlink will replace the format specifier with an appropriate index.
- */
- if (!netdev->name)
- netdev->name = netdev->type == LXC_NET_PHYS ?
- netdev->link : "eth%d";
-
- /* rename the interface name */
- if (strcmp(ifname, netdev->name) != 0) {
- err = lxc_netdev_rename_by_name(ifname, netdev->name);
- if (err) {
- ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
- strerror(-err));
- return -1;
- }
- }
-
- /* Re-read the name of the interface because its name has changed
- * and would be automatically allocated by the system
- */
- if (!if_indextoname(netdev->ifindex, current_ifname)) {
- ERROR("no interface corresponding to index '%d'",
- netdev->ifindex);
- return -1;
- }
-
- /* set a mac address */
- if (netdev->hwaddr) {
- if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
- ERROR("failed to setup hw address for '%s'",
- current_ifname);
- return -1;
- }
- }
-
- /* setup ipv4 addresses on the interface */
- if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
- ERROR("failed to setup ip addresses for '%s'",
- ifname);
- return -1;
- }
-
- /* setup ipv6 addresses on the interface */
- if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
- ERROR("failed to setup ipv6 addresses for '%s'",
- ifname);
- return -1;
- }
-
- /* set the network device up */
- if (netdev->flags & IFF_UP) {
- int err;
-
- err = lxc_netdev_up(current_ifname);
- if (err) {
- ERROR("failed to set '%s' up : %s", current_ifname,
- strerror(-err));
- return -1;
- }
-
- /* the network is up, make the loopback up too */
- err = lxc_netdev_up("lo");
- if (err) {
- ERROR("failed to set the loopback up : %s",
- strerror(-err));
- return -1;
- }
- }
-
- /* We can only set up the default routes after bringing
- * up the interface, sine bringing up the interface adds
- * the link-local routes and we can't add a default
- * route if the gateway is not reachable. */
-
- /* setup ipv4 gateway on the interface */
- if (netdev->ipv4_gateway) {
- if (!(netdev->flags & IFF_UP)) {
- ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname);
- return -1;
- }
-
- if (lxc_list_empty(&netdev->ipv4)) {
- ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname);
- return -1;
- }
-
- err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- err = lxc_ipv4_dest_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- ERROR("failed to add ipv4 dest for '%s': %s",
- ifname, strerror(-err));
- }
-
- err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
- if (err) {
- ERROR("failed to setup ipv4 gateway for '%s': %s",
- ifname, strerror(-err));
- if (netdev->ipv4_gateway_auto) {
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
- ERROR("tried to set autodetected ipv4 gateway '%s'", buf);
- }
- return -1;
- }
- }
- }
-
- /* setup ipv6 gateway on the interface */
- if (netdev->ipv6_gateway) {
- if (!(netdev->flags & IFF_UP)) {
- ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname);
- return -1;
- }
-
- if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
- ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname);
- return -1;
- }
-
- err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- err = lxc_ipv6_dest_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- ERROR("failed to add ipv6 dest for '%s': %s",
- ifname, strerror(-err));
- }
-
- err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
- if (err) {
- ERROR("failed to setup ipv6 gateway for '%s': %s",
- ifname, strerror(-err));
- if (netdev->ipv6_gateway_auto) {
- char buf[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
- ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
- }
- return -1;
- }
- }
- }
-
- DEBUG("'%s' has been setup", current_ifname);
-
- return 0;
-}
-
-static int lxc_setup_networks_in_child_namespaces(const struct lxc_conf *conf,
- struct lxc_list *network)
-{
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
-
- lxc_log_configured_netdevs(conf);
-
- lxc_list_for_each(iterator, network) {
- netdev = iterator->elem;
-
- /* REMOVE in LXC 3.0 */
- if (netdev->idx < 0) {
- ERROR("WARNING: using \"lxc.network.*\" keys to define "
- "networks is DEPRECATED, please switch to using "
- "\"lxc.net.[i].* keys\"");
- }
-
- if (lxc_setup_netdev_in_child_namespaces(netdev)) {
- ERROR("failed to setup netdev");
- return -1;
- }
- }
-
- if (!lxc_list_empty(network))
- INFO("network has been setup");
-
- return 0;
-}
-
-static int parse_resource(const char *res) {
- size_t i;
- int resid = -1;
-
- for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) {
- if (strcmp(res, limit_opt[i].name) == 0)
- return limit_opt[i].value;
- }
-
- /* try to see if it's numeric, so the user may specify
- * resources that the running kernel knows about but
- * we don't */
- if (lxc_safe_int(res, &resid) == 0)
- return resid;
- return -1;
-}
-
-int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
- struct lxc_list *it;
- struct lxc_limit *lim;
- int resid;
-
- lxc_list_for_each(it, limits) {
- lim = it->elem;
-
- resid = parse_resource(lim->resource);
- if (resid < 0) {
- ERROR("unknown resource %s", lim->resource);
- return -1;
- }
-
- if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
- ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
- return -1;
- }
- }
- return 0;
-}
-
-/* try to move physical nics to the init netns */
-void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
-{
- int i, oldfd;
- char ifname[IFNAMSIZ];
-
- if (netnsfd < 0 || conf->num_savednics == 0)
- return;
-
- INFO("Running to reset %d nic names.", conf->num_savednics);
-
- oldfd = lxc_preserve_ns(getpid(), "net");
- if (oldfd < 0) {
- SYSERROR("Failed to open monitor netns fd.");
- return;
- }
-
- if (setns(netnsfd, 0) != 0) {
- SYSERROR("Failed to enter container netns to reset nics");
- close(oldfd);
- return;
- }
- for (i=0; i<conf->num_savednics; i++) {
- struct saved_nic *s = &conf->saved_nics[i];
- /* retrieve the name of the interface */
- if (!if_indextoname(s->ifindex, ifname)) {
- WARN("no interface corresponding to index '%d'", s->ifindex);
- continue;
- }
- if (lxc_netdev_move_by_name(ifname, 1, s->orig_name))
- WARN("Error moving nic name:%s back to host netns", ifname);
- free(s->orig_name);
- }
- conf->num_savednics = 0;
-
- if (setns(oldfd, 0) != 0)
- SYSERROR("Failed to re-enter monitor's netns");
- close(oldfd);
-}
-
-static char *default_rootfs_mount = LXCROOTFSMOUNT;
-
-struct lxc_conf *lxc_conf_init(void)
-{
- struct lxc_conf *new;
- int i;
-
- new = malloc(sizeof(*new));
- if (!new) {
- ERROR("lxc_conf_init : %s", strerror(errno));
- return NULL;
- }
- memset(new, 0, sizeof(*new));
-
- new->loglevel = LXC_LOG_LEVEL_NOTSET;
- new->personality = -1;
- new->autodev = 1;
- new->console.log_path = NULL;
- new->console.log_fd = -1;
- new->console.path = NULL;
- new->console.peer = -1;
- new->console.peerpty.busy = -1;
- new->console.peerpty.master = -1;
- new->console.peerpty.slave = -1;
- new->console.master = -1;
- new->console.slave = -1;
- new->console.name[0] = '\0';
- new->maincmd_fd = -1;
- new->nbd_idx = -1;
- new->rootfs.mount = strdup(default_rootfs_mount);
- if (!new->rootfs.mount) {
- ERROR("lxc_conf_init : %s", strerror(errno));
- free(new);
- return NULL;
- }
- new->logfd = -1;
- lxc_list_init(&new->cgroup);
- lxc_list_init(&new->network);
- lxc_list_init(&new->mount_list);
- lxc_list_init(&new->caps);
- lxc_list_init(&new->keepcaps);
- lxc_list_init(&new->id_map);
- lxc_list_init(&new->includes);
- lxc_list_init(&new->aliens);
- lxc_list_init(&new->environment);
- lxc_list_init(&new->limits);
- for (i=0; i<NUM_LXC_HOOKS; i++)
- lxc_list_init(&new->hooks[i]);
- lxc_list_init(&new->groups);
- new->lsm_aa_profile = NULL;
- new->lsm_se_context = NULL;
- new->tmp_umount_proc = 0;
-
- for (i = 0; i < LXC_NS_MAX; i++)
- new->inherit_ns_fd[i] = -1;
-
- /* if running in a new user namespace, init and COMMAND
- * default to running as UID/GID 0 when using lxc-execute */
- new->init_uid = 0;
- new->init_gid = 0;
- memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
-
- return new;
-}
-
-static int instantiate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char *veth1, *veth2;
- char veth1buf[IFNAMSIZ], veth2buf[IFNAMSIZ];
- int bridge_index, err;
- unsigned int mtu = 0;
-
- if (netdev->priv.veth_attr.pair) {
- veth1 = netdev->priv.veth_attr.pair;
- if (handler->conf->reboot)
- lxc_netdev_delete_by_name(veth1);
- } else {
- err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
- if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */
- ERROR("veth1 name too long");
- return -1;
- }
- veth1 = lxc_mkifname(veth1buf);
- if (!veth1) {
- ERROR("failed to allocate a temporary name");
- return -1;
- }
- /* store away for deconf */
- memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
- }
-
- snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
- veth2 = lxc_mkifname(veth2buf);
- if (!veth2) {
- ERROR("failed to allocate a temporary name");
- goto out_delete;
- }
-
- err = lxc_veth_create(veth1, veth2);
- if (err) {
- ERROR("failed to create veth pair \"%s\" and \"%s\": %s", veth1,
- veth2, strerror(-err));
- goto out_delete;
- }
-
- /* changing the high byte of the mac address to 0xfe, the bridge interface
- * will always keep the host's mac address and not take the mac address
- * of a container */
- err = setup_private_host_hw_addr(veth1);
- if (err) {
- ERROR("failed to change mac address of host interface \"%s\": %s",
- veth1, strerror(-err));
- goto out_delete;
- }
-
- netdev->ifindex = if_nametoindex(veth2);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the index for \"%s\"", veth2);
- goto out_delete;
- }
-
- if (netdev->mtu) {
- if (lxc_safe_uint(netdev->mtu, &mtu) < 0)
- WARN("failed to parse mtu from");
- else
- INFO("retrieved mtu %d", mtu);
- } else if (netdev->link) {
- bridge_index = if_nametoindex(netdev->link);
- if (bridge_index) {
- mtu = netdev_get_mtu(bridge_index);
- INFO("retrieved mtu %d from %s", mtu, netdev->link);
- } else {
- mtu = netdev_get_mtu(netdev->ifindex);
- INFO("retrieved mtu %d from %s", mtu, veth2);
- }
- }
-
- if (mtu) {
- err = lxc_netdev_set_mtu(veth1, mtu);
- if (!err)
- err = lxc_netdev_set_mtu(veth2, mtu);
- if (err) {
- ERROR("failed to set mtu \"%d\" for veth pair \"%s\" "
- "and \"%s\": %s",
- mtu, veth1, veth2, strerror(-err));
- goto out_delete;
- }
- }
-
- if (netdev->link) {
- err = lxc_bridge_attach(netdev->link, veth1);
- if (err) {
- ERROR("failed to attach \"%s\" to bridge \"%s\": %s",
- veth1, netdev->link, strerror(-err));
- goto out_delete;
- }
- INFO("attached \"%s\" to bridge \"%s\"", veth1, netdev->link);
- }
-
- err = lxc_netdev_up(veth1);
- if (err) {
- ERROR("failed to set \"%s\" up: %s", veth1, strerror(-err));
- goto out_delete;
- }
-
- if (netdev->upscript) {
- err = run_script(handler->name, "net", netdev->upscript, "up",
- "veth", veth1, (char*) NULL);
- if (err)
- goto out_delete;
- }
-
- DEBUG("instantiated veth \"%s/%s\", index is \"%d\"", veth1, veth2,
- netdev->ifindex);
-
- return 0;
-
-out_delete:
- if (netdev->ifindex != 0)
- lxc_netdev_delete_by_name(veth1);
- if (!netdev->priv.veth_attr.pair)
- free(veth1);
- free(veth2);
- return -1;
-}
-
-static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char *veth1;
- int err;
-
- if (netdev->priv.veth_attr.pair)
- veth1 = netdev->priv.veth_attr.pair;
- else
- veth1 = netdev->priv.veth_attr.veth1;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "veth", veth1, (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int instantiate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char peerbuf[IFNAMSIZ], *peer;
- int err;
-
- if (!netdev->link) {
- ERROR("no link specified for macvlan netdev");
- return -1;
- }
-
- err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
- if (err >= sizeof(peerbuf))
- return -1;
-
- peer = lxc_mkifname(peerbuf);
- if (!peer) {
- ERROR("failed to make a temporary name");
- return -1;
- }
-
- err = lxc_macvlan_create(netdev->link, peer,
- netdev->priv.macvlan_attr.mode);
- if (err) {
- ERROR("failed to create macvlan interface '%s' on '%s' : %s",
- peer, netdev->link, strerror(-err));
- goto out;
- }
-
- netdev->ifindex = if_nametoindex(peer);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the index for %s", peer);
- goto out;
- }
-
- if (netdev->upscript) {
- err = run_script(handler->name, "net", netdev->upscript, "up",
- "macvlan", netdev->link, (char*) NULL);
- if (err)
- goto out;
- }
-
- DEBUG("instantiated macvlan '%s', index is '%d' and mode '%d'",
- peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
-
- return 0;
-out:
- lxc_netdev_delete_by_name(peer);
- free(peer);
- return -1;
-}
-
-static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- int err;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "macvlan", netdev->link,
- (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-/* XXX: merge with instantiate_macvlan */
-static int instantiate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- char peer[IFNAMSIZ];
- int err;
- static uint16_t vlan_cntr = 0;
- unsigned int mtu = 0;
-
- if (!netdev->link) {
- ERROR("no link specified for vlan netdev");
- return -1;
- }
-
- err = snprintf(peer, sizeof(peer), "vlan%d-%d", netdev->priv.vlan_attr.vid, vlan_cntr++);
- if (err >= sizeof(peer)) {
- ERROR("peer name too long");
- return -1;
- }
-
- err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
- if (err) {
- ERROR("failed to create vlan interface '%s' on '%s' : %s",
- peer, netdev->link, strerror(-err));
- return -1;
- }
-
- netdev->ifindex = if_nametoindex(peer);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the ifindex for %s", peer);
- lxc_netdev_delete_by_name(peer);
- return -1;
- }
-
- DEBUG("instantiated vlan '%s', ifindex is '%d'", " vlan1000",
- netdev->ifindex);
- if (netdev->mtu) {
- if (lxc_safe_uint(netdev->mtu, &mtu) < 0) {
- ERROR("Failed to retrieve mtu from: '%d'/'%s'.",
- netdev->ifindex, netdev->name);
- return -1;
- }
- err = lxc_netdev_set_mtu(peer, mtu);
- if (err) {
- ERROR("failed to set mtu '%s' for %s : %s",
- netdev->mtu, peer, strerror(-err));
- lxc_netdev_delete_by_name(peer);
- return -1;
- }
- }
-
- return 0;
-}
-
-static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- return 0;
-}
-
-static int instantiate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- if (!netdev->link) {
- ERROR("no link specified for the physical interface");
- return -1;
- }
-
- netdev->ifindex = if_nametoindex(netdev->link);
- if (!netdev->ifindex) {
- ERROR("failed to retrieve the index for %s", netdev->link);
- return -1;
- }
-
- if (netdev->upscript) {
- int err;
- err = run_script(handler->name, "net", netdev->upscript,
- "up", "phys", netdev->link, (char*) NULL);
- if (err)
- return -1;
- }
-
- return 0;
-}
-
-static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- int err;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "phys", netdev->link, (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int instantiate_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- netdev->ifindex = 0;
- return 0;
-}
-
-static int instantiate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- netdev->ifindex = 0;
- if (netdev->upscript) {
- int err;
- err = run_script(handler->name, "net", netdev->upscript,
- "up", "empty", (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- int err;
-
- if (netdev->downscript) {
- err = run_script(handler->name, "net", netdev->downscript,
- "down", "empty", (char*) NULL);
- if (err)
- return -1;
- }
- return 0;
-}
-
-static int shutdown_none(struct lxc_handler *handler, struct lxc_netdev *netdev)
-{
- return 0;
-}
-
-int lxc_requests_empty_network(struct lxc_handler *handler)
-{
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
- bool found_none = false, found_nic = false;
-
- if (lxc_list_empty(network))
- return 0;
-
- lxc_list_for_each(iterator, network) {
-
- netdev = iterator->elem;
-
- if (netdev->type == LXC_NET_NONE)
- found_none = true;
- else
- found_nic = true;
- }
- if (found_none && !found_nic)
- return 1;
- return 0;
-}
-
-int lxc_setup_networks_in_parent_namespaces(struct lxc_handler *handler)
-{
- bool am_root;
- struct lxc_netdev *netdev;
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
-
- /* We need to be root. */
- am_root = (getuid() == 0);
- if (!am_root)
- return 0;
-
- lxc_list_for_each(iterator, network) {
- netdev = iterator->elem;
-
- if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
- ERROR("invalid network configuration type '%d'",
- netdev->type);
- return -1;
- }
-
- if (netdev_conf[netdev->type](handler, netdev)) {
- ERROR("failed to create netdev");
- return -1;
- }
-
- }
-
- return 0;
-}
-
-bool lxc_delete_network(struct lxc_handler *handler)
-{
- int ret;
- struct lxc_list *iterator;
- struct lxc_list *network = &handler->conf->network;
- bool deleted_all = true;
-
- lxc_list_for_each(iterator, network) {
- char *hostveth = NULL;
- struct lxc_netdev *netdev = iterator->elem;
-
- /* We can only delete devices whose ifindex we have. If we don't
- * have the index it means that we didn't create it.
- */
- if (!netdev->ifindex)
- continue;
-
- if (netdev->type == LXC_NET_PHYS) {
- ret = lxc_netdev_rename_by_index(netdev->ifindex, netdev->link);
- if (ret < 0)
- WARN("Failed to rename interface with index %d "
- "to its initial name \"%s\"",
- netdev->ifindex, netdev->link);
- else
- TRACE("Renamed interface with index %d to its "
- "initial name \"%s\"",
- netdev->ifindex, netdev->link);
- continue;
- }
-
- ret = netdev_deconf[netdev->type](handler, netdev);
- if (ret < 0)
- WARN("Failed to deconfigure network device");
-
- /* Recent kernels remove the virtual interfaces when the network
- * namespace is destroyed but in case we did not move the
- * interface to the network namespace, we have to destroy it.
- */
- if (!am_unpriv()) {
- ret = lxc_netdev_delete_by_index(netdev->ifindex);
- if (-ret == ENODEV) {
- INFO("Interface \"%s\" with index %d already "
- "deleted or existing in different network "
- "namespace",
- netdev->name ? netdev->name : "(null)",
- netdev->ifindex);
- } else if (ret < 0) {
- deleted_all = false;
- WARN("Failed to remove interface \"%s\" with "
- "index %d: %s",
- netdev->name ? netdev->name : "(null)",
- netdev->ifindex, strerror(-ret));
- continue;
- }
- INFO("Removed interface \"%s\" with index %d",
- netdev->name ? netdev->name : "(null)",
- netdev->ifindex);
- }
-
- if (netdev->type != LXC_NET_VETH)
- continue;
-
- if (am_unpriv()) {
- if (is_ovs_bridge(netdev->link)) {
- ret = lxc_unpriv_delete_nic(handler->lxcpath,
- handler->name,
- netdev, getpid());
- if (ret < 0)
- WARN("Failed to remove port \"%s\" "
- "from openvswitch bridge \"%s\"",
- netdev->priv.veth_attr.pair,
- netdev->link);
- }
-
- continue;
- }
-
- /* Explicitly delete host veth device to prevent lingering
- * devices. We had issues in LXD around this.
- */
- if (netdev->priv.veth_attr.pair)
- hostveth = netdev->priv.veth_attr.pair;
- else
- hostveth = netdev->priv.veth_attr.veth1;
- if (*hostveth == '\0')
- continue;
-
- ret = lxc_netdev_delete_by_name(hostveth);
- if (ret < 0) {
- deleted_all = false;
- WARN("Failed to remove interface \"%s\" from \"%s\": %s",
- hostveth, netdev->link, strerror(-ret));
- continue;
- }
- INFO("Removed interface \"%s\" from \"%s\"", hostveth, netdev->link);
-
- if (!is_ovs_bridge(netdev->link)) {
- netdev->priv.veth_attr.veth1[0] = '\0';
- continue;
- }
-
- /* Delete the openvswitch port. */
- ret = lxc_ovs_delete_port(netdev->link, hostveth);
- if (ret < 0)
- WARN("Failed to remove port \"%s\" from openvswitch "
- "bridge \"%s\"", hostveth, netdev->link);
- else
- INFO("Removed port \"%s\" from openvswitch bridge \"%s\"",
- hostveth, netdev->link);
-
- netdev->priv.veth_attr.veth1[0] = '\0';
- }
-
- return deleted_all;
-}
-
-#define LXC_USERNIC_PATH LIBEXECDIR "/lxc/lxc-user-nic"
-static int unpriv_assign_nic(const char *lxcpath, char *lxcname,
- struct lxc_netdev *netdev, pid_t pid)
-{
- int ret;
- pid_t child;
- int bytes, pipefd[2];
- char *token, *saveptr = NULL;
- char netdev_link[IFNAMSIZ + 1];
- char buffer[MAXPATHLEN] = {0};
-
- if (netdev->type != LXC_NET_VETH) {
- ERROR("nic type %d not support for unprivileged use",
- netdev->type);
- return -1;
- }
-
- if (pipe(pipefd) < 0) {
- SYSERROR("pipe failed");
- return -1;
- }
-
- child = fork();
- if (child < 0) {
- SYSERROR("fork");
- close(pipefd[0]);
- close(pipefd[1]);
- return -1;
- }
-
- if (child == 0) { /* child */
- /* Call lxc-user-nic pid type bridge. */
- int ret;
- char pidstr[LXC_NUMSTRLEN64];
-
- close(pipefd[0]); /* Close the read-end of the pipe. */
-
- /* Redirect stdout to write-end of the pipe. */
- ret = dup2(pipefd[1], STDOUT_FILENO);
- if (ret >= 0)
- ret = dup2(pipefd[1], STDERR_FILENO);
- close(pipefd[1]); /* Close the write-end of the pipe. */
- if (ret < 0) {
- SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
- exit(EXIT_FAILURE);
- }
-
- if (netdev->link)
- strncpy(netdev_link, netdev->link, IFNAMSIZ);
- else
- strncpy(netdev_link, "none", IFNAMSIZ);
-
- ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
- if (ret < 0 || ret >= LXC_NUMSTRLEN64)
- exit(EXIT_FAILURE);
- pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
-
- INFO("Execing lxc-user-nic create %s %s %s veth %s %s", lxcpath,
- lxcname, pidstr, netdev_link,
- netdev->name ? netdev->name : "(null)");
- if (netdev->name)
- execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
- lxcpath, lxcname, pidstr, "veth", netdev_link,
- netdev->name, (char *)NULL);
- else
- execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "create",
- lxcpath, lxcname, pidstr, "veth", netdev_link,
- (char *)NULL);
- SYSERROR("Failed to exec lxc-user-nic.");
- exit(EXIT_FAILURE);
- }
-
- /* close the write-end of the pipe */
- close(pipefd[1]);
-
- bytes = read(pipefd[0], &buffer, MAXPATHLEN);
- if (bytes < 0) {
- SYSERROR("Failed to read from pipe file descriptor.");
- close(pipefd[0]);
- return -1;
- }
- buffer[bytes - 1] = '\0';
-
- if (wait_for_pid(child) != 0) {
- ERROR("lxc-user-nic failed to configure requested network: %s",
- buffer[0] != '\0' ? buffer : "(null)");
- close(pipefd[0]);
- return -1;
- }
- TRACE("Received output \"%s\" from lxc-user-nic", buffer);
-
- /* close the read-end of the pipe */
- close(pipefd[0]);
-
- /* fill netdev->name field */
- token = strtok_r(buffer, ":", &saveptr);
- if (!token)
- return -1;
-
- netdev->name = malloc(IFNAMSIZ + 1);
- if (!netdev->name) {
- SYSERROR("Failed to allocate memory.");
- return -1;
- }
- memset(netdev->name, 0, IFNAMSIZ + 1);
- strncpy(netdev->name, token, IFNAMSIZ);
-
- /* fill netdev->veth_attr.pair field */
- token = strtok_r(NULL, ":", &saveptr);
- if (!token)
- return -1;
-
- netdev->priv.veth_attr.pair = strdup(token);
- if (!netdev->priv.veth_attr.pair) {
- ERROR("Failed to allocate memory.");
- return -1;
- }
-
- /* fill netdev->veth_attr.pair field */
- token = strtok_r(NULL, ":", &saveptr);
- if (!token)
- return -1;
-
- ret = lxc_safe_int(token, &netdev->ifindex);
- if (ret < 0) {
- ERROR("Failed to parse ifindex for network device \"%s\"", netdev->name);
- return -1;
+ new->loglevel = LXC_LOG_LEVEL_NOTSET;
+ new->personality = -1;
+ new->autodev = 1;
+ new->console.buffer_log_file = NULL;
+ new->console.buffer_log_file_fd = -1;
+ new->console.buffer_size = 0;
+ new->console.log_path = NULL;
+ new->console.log_fd = -1;
+ new->console.path = NULL;
+ new->console.peer = -1;
+ new->console.peerpty.busy = -1;
+ new->console.peerpty.master = -1;
+ new->console.peerpty.slave = -1;
+ new->console.master = -1;
+ new->console.slave = -1;
+ new->console.name[0] = '\0';
+ memset(&new->console.ringbuf, 0, sizeof(struct lxc_ringbuf));
+ new->maincmd_fd = -1;
+ new->nbd_idx = -1;
+ new->rootfs.mount = strdup(default_rootfs_mount);
+ if (!new->rootfs.mount) {
+ ERROR("lxc_conf_init : %s", strerror(errno));
+ free(new);
+ return NULL;
}
+ new->logfd = -1;
+ lxc_list_init(&new->cgroup);
+ lxc_list_init(&new->network);
+ lxc_list_init(&new->mount_list);
+ lxc_list_init(&new->caps);
+ lxc_list_init(&new->keepcaps);
+ lxc_list_init(&new->id_map);
+ lxc_list_init(&new->includes);
+ lxc_list_init(&new->aliens);
+ lxc_list_init(&new->environment);
+ lxc_list_init(&new->limits);
+ for (i = 0; i < NUM_LXC_HOOKS; i++)
+ lxc_list_init(&new->hooks[i]);
+ lxc_list_init(&new->groups);
+ new->lsm_aa_profile = NULL;
+ new->lsm_se_context = NULL;
+ new->tmp_umount_proc = 0;
- return 0;
-}
-
-int lxc_assign_network(const char *lxcpath, char *lxcname,
- struct lxc_list *network, pid_t pid)
-{
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
- char ifname[IFNAMSIZ];
- int am_root = (getuid() == 0);
- int err;
-
- lxc_list_for_each(iterator, network) {
-
- netdev = iterator->elem;
-
- if (netdev->type == LXC_NET_VETH && !am_root) {
- if (netdev->mtu)
- INFO("mtu ignored due to insufficient privilege");
- if (unpriv_assign_nic(lxcpath, lxcname, netdev, pid))
- return -1;
- /* lxc-user-nic has moved the nic to the new ns.
- * unpriv_assign_nic() fills in netdev->name.
- * netdev->ifindex will be filed in at
- * lxc_setup_netdev_in_child_namespaces.
- */
- continue;
- }
-
- /* empty network namespace, nothing to move */
- if (!netdev->ifindex)
- continue;
-
- /* retrieve the name of the interface */
- if (!if_indextoname(netdev->ifindex, ifname)) {
- ERROR("no interface corresponding to index '%d'", netdev->ifindex);
- return -1;
- }
-
- err = lxc_netdev_move_by_name(ifname, pid, NULL);
- if (err) {
- ERROR("failed to move '%s' to the container : %s",
- netdev->link, strerror(-err));
- return -1;
- }
-
- DEBUG("move '%s'/'%s' to '%d': .", ifname, netdev->name, pid);
- }
+ /* if running in a new user namespace, init and COMMAND
+ * default to running as UID/GID 0 when using lxc-execute */
+ new->init_uid = 0;
+ new->init_gid = 0;
+ memset(&new->cgroup_meta, 0, sizeof(struct lxc_cgroup));
+ memset(&new->inherit_ns, 0, sizeof(char *) * LXC_NS_MAX);
- return 0;
+ return new;
}
static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
pos += sprintf(mapbuf, "new%cidmap %d", u_or_g, pid);
lxc_list_for_each(iterator, idmap) {
- /* The kernel only takes <= 4k for writes to
- * /proc/<nr>/[ug]id_map
- */
map = iterator->elem;
if (map->idtype != type)
continue;
use_shadow ? " " : "", map->nsid,
map->hostid, map->range,
use_shadow ? "" : "\n");
- if (fill <= 0 || fill >= left)
- SYSERROR("Too many {g,u}id mappings defined.");
+ if (fill <= 0 || fill >= left) {
+ /* The kernel only takes <= 4k for writes to
+ * /proc/<pid>/{g,u}id_map
+ */
+ SYSERROR("Too many %cid mappings defined", u_or_g);
+ return -1;
+ }
pos += fill;
}
lxc_map_ids_exec_wrapper,
(void *)mapbuf);
if (ret < 0) {
- ERROR("new%cidmap failed to write mapping: %s",
- u_or_g, cmd_output);
+ ERROR("new%cidmap failed to write mapping \"%s\": %s",
+ u_or_g, cmd_output, mapbuf);
return -1;
}
+ TRACE("new%cidmap wrote mapping \"%s\"", u_or_g, mapbuf);
} else {
ret = write_id_mapping(type, pid, mapbuf, pos - mapbuf);
- if (ret < 0)
+ if (ret < 0) {
+ ERROR("Failed to write mapping: %s", mapbuf);
return -1;
+ }
+ TRACE("Wrote mapping \"%s\"", mapbuf);
}
memset(mapbuf, 0, sizeof(mapbuf));
if (id >= map->hostid && id < map->hostid + map->range)
return (id - map->hostid) + map->nsid;
}
- return -1;
-}
-
-int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
-{
- struct lxc_list *it;
- struct id_map *map;
- unsigned int freeid = 0;
-again:
- lxc_list_for_each(it, &conf->id_map) {
- map = it->elem;
- if (map->idtype != idtype)
- continue;
- if (freeid >= map->nsid && freeid < map->nsid + map->range) {
- freeid = map->nsid + map->range;
- goto again;
- }
- }
- return freeid;
-}
-
-int lxc_find_gateway_addresses(struct lxc_handler *handler)
-{
- struct lxc_list *network = &handler->conf->network;
- struct lxc_list *iterator;
- struct lxc_netdev *netdev;
- int link_index;
-
- lxc_list_for_each(iterator, network) {
- netdev = iterator->elem;
-
- if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
- continue;
-
- if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
- ERROR("gateway = auto only supported for "
- "veth and macvlan");
- return -1;
- }
-
- if (!netdev->link) {
- ERROR("gateway = auto needs a link interface");
- return -1;
- }
-
- link_index = if_nametoindex(netdev->link);
- if (!link_index)
- return -EINVAL;
-
- if (netdev->ipv4_gateway_auto) {
- if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
- ERROR("failed to automatically find ipv4 gateway "
- "address from link interface '%s'", netdev->link);
- return -1;
- }
- }
-
- if (netdev->ipv6_gateway_auto) {
- if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
- ERROR("failed to automatically find ipv6 gateway "
- "address from link interface '%s'", netdev->link);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-int lxc_create_tty(const char *name, struct lxc_conf *conf)
-{
- struct lxc_tty_info *tty_info = &conf->tty_info;
- int i, ret;
-
- /* no tty in the configuration */
- if (!conf->tty)
- return 0;
-
- tty_info->pty_info = malloc(sizeof(*tty_info->pty_info) * conf->tty);
- if (!tty_info->pty_info) {
- SYSERROR("failed to allocate struct *pty_info");
- return -ENOMEM;
- }
-
- for (i = 0; i < conf->tty; i++) {
- struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
- process_lock();
- ret = openpty(&pty_info->master, &pty_info->slave,
- pty_info->name, NULL, NULL);
- process_unlock();
- if (ret) {
- SYSERROR("failed to create pty device number %d", i);
- tty_info->nbtty = i;
- lxc_delete_tty(tty_info);
- return -ENOTTY;
- }
-
- DEBUG("allocated pty \"%s\" with master fd %d and slave fd %d",
- pty_info->name, pty_info->master, pty_info->slave);
-
- /* Prevent leaking the file descriptors to the container */
- ret = fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
- if (ret < 0)
- WARN("failed to set FD_CLOEXEC flag on master fd %d of "
- "pty device \"%s\": %s",
- pty_info->master, pty_info->name, strerror(errno));
-
- ret = fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
- if (ret < 0)
- WARN("failed to set FD_CLOEXEC flag on slave fd %d of "
- "pty device \"%s\": %s",
- pty_info->slave, pty_info->name, strerror(errno));
-
- pty_info->busy = 0;
- }
-
- tty_info->nbtty = conf->tty;
-
- INFO("finished allocating %d pts devices", conf->tty);
- return 0;
-}
-
-void lxc_delete_tty(struct lxc_tty_info *tty_info)
-{
- int i;
-
- for (i = 0; i < tty_info->nbtty; i++) {
- struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
-
- close(pty_info->master);
- close(pty_info->slave);
- }
-
- free(tty_info->pty_info);
- tty_info->pty_info = NULL;
- tty_info->nbtty = 0;
+ return -1;
}
+int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype)
+{
+ struct lxc_list *it;
+ struct id_map *map;
+ unsigned int freeid = 0;
+again:
+ lxc_list_for_each(it, &conf->id_map) {
+ map = it->elem;
+ if (map->idtype != idtype)
+ continue;
+ if (freeid >= map->nsid && freeid < map->nsid + map->range) {
+ freeid = map->nsid + map->range;
+ goto again;
+ }
+ }
+ return freeid;
+}
int chown_mapped_root_exec_wrapper(void *args)
{
return true;
}
-static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
-{
- int i;
- int *ttyfds;
- struct lxc_pty_info *pty_info;
- struct lxc_conf *conf = handler->conf;
- const struct lxc_tty_info *tty_info = &conf->tty_info;
- int sock = handler->ttysock[0];
- int ret = -1;
- size_t num_ttyfds = (2 * conf->tty);
-
- ttyfds = malloc(num_ttyfds * sizeof(int));
- if (!ttyfds)
- return -1;
-
- for (i = 0; i < num_ttyfds; i++) {
- pty_info = &tty_info->pty_info[i / 2];
- ttyfds[i++] = pty_info->slave;
- ttyfds[i] = pty_info->master;
- TRACE("send pty \"%s\" with master fd %d and slave fd %d to "
- "parent",
- pty_info->name, pty_info->master, pty_info->slave);
- }
-
- ret = lxc_abstract_unix_send_fds(sock, ttyfds, num_ttyfds, NULL, 0);
- if (ret < 0)
- ERROR("failed to send %d ttys to parent: %s", conf->tty,
- strerror(errno));
- else
- TRACE("sent %d ttys to parent", conf->tty);
-
- close(handler->ttysock[0]);
- close(handler->ttysock[1]);
-
- for (i = 0; i < num_ttyfds; i++)
- close(ttyfds[i]);
-
- free(ttyfds);
-
- return ret;
-}
-
int lxc_setup(struct lxc_handler *handler)
{
+ int ret;
const char *name = handler->name;
struct lxc_conf *lxc_conf = handler->conf;
const char *lxcpath = handler->lxcpath;
return -1;
}
- if (lxc_conf->inherit_ns_fd[LXC_NS_UTS] == -1) {
+ if (handler->nsfd[LXC_NS_UTS] == -1) {
if (setup_utsname(lxc_conf->utsname)) {
ERROR("failed to setup the utsname for '%s'", name);
return -1;
}
}
- if (lxc_setup_networks_in_child_namespaces(lxc_conf,
- &lxc_conf->network)) {
+ if (lxc_setup_network_in_child_namespaces(lxc_conf, &lxc_conf->network)) {
ERROR("failed to setup the network for '%s'", name);
return -1;
}
+ if (lxc_network_send_name_and_ifindex_to_parent(handler) < 0) {
+ ERROR("Failed to network device names and ifindices to parent");
+ return -1;
+ }
+
if (lxc_conf->autodev > 0) {
if (mount_autodev(name, &lxc_conf->rootfs, lxcpath)) {
ERROR("failed to mount /dev in the container");
}
}
- if (!lxc_conf->is_execute && lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
- ERROR("failed to setup the console for '%s'", name);
+ ret = lxc_setup_console(&lxc_conf->rootfs, &lxc_conf->console,
+ lxc_conf->ttydir);
+ if (ret < 0) {
+ ERROR("Failed to setup console");
return -1;
}
- if (!lxc_conf->is_execute && setup_dev_symlinks(&lxc_conf->rootfs)) {
- ERROR("failed to setup /dev symlinks for '%s'", name);
+ ret = lxc_setup_dev_symlinks(&lxc_conf->rootfs);
+ if (ret < 0) {
+ ERROR("Failed to setup /dev symlinks");
return -1;
}
return -1;
}
- if (lxc_create_tty(name, lxc_conf)) {
- ERROR("failed to create the ttys");
- return -1;
- }
-
- if (lxc_send_ttys_to_parent(handler) < 0) {
- ERROR("failure sending console info to parent");
- return -1;
- }
-
- if (!lxc_conf->is_execute && lxc_setup_tty(lxc_conf)) {
- ERROR("failed to setup the ttys for '%s'", name);
+ ret = lxc_create_ttys(handler);
+ if (ret < 0)
return -1;
- }
-
- if (lxc_conf->pty_names && setenv("container_ttys", lxc_conf->pty_names, 1))
- SYSERROR("failed to set environment variable for container ptys");
-
if (setup_personality(lxc_conf->personality)) {
ERROR("failed to setup personality");
if (strcmp(hook, "pre-start") == 0)
which = LXCHOOK_PRESTART;
+ else if (strcmp(hook, "start-host") == 0)
+ which = LXCHOOK_START_HOST;
else if (strcmp(hook, "pre-mount") == 0)
which = LXCHOOK_PREMOUNT;
else if (strcmp(hook, "mount") == 0)
return 0;
}
-
int lxc_clear_mount_entries(struct lxc_conf *c)
{
struct lxc_list *it,*next;
return 0;
}
-static void lxc_clear_saved_nics(struct lxc_conf *conf)
-{
- int i;
-
- if (!conf->saved_nics)
- return;
- for (i=0; i < conf->num_savednics; i++)
- free(conf->saved_nics[i].orig_name);
- free(conf->saved_nics);
-}
-
static inline void lxc_clear_aliens(struct lxc_conf *conf)
{
struct lxc_list *it,*next;
return;
if (current_config == conf)
current_config = NULL;
+ free(conf->console.buffer_log_file);
free(conf->console.log_path);
free(conf->console.path);
+ if (conf->console.buffer_size > 0 && conf->console.ringbuf.addr)
+ lxc_ringbuf_release(&conf->console.ringbuf);
free(conf->rootfs.mount);
free(conf->rootfs.bdev_type);
free(conf->rootfs.options);
free(conf->ttydir);
free(conf->fstab);
free(conf->rcfile);
+ free(conf->execute_cmd);
free(conf->init_cmd);
+ free(conf->init_cwd);
free(conf->unexpanded_config);
free(conf->pty_names);
free(conf->syslog);
lxc_clear_cgroups(conf, "lxc.cgroup");
lxc_clear_hooks(conf, "lxc.hook");
lxc_clear_mount_entries(conf);
- lxc_clear_saved_nics(conf);
lxc_clear_idmaps(conf);
lxc_clear_groups(conf);
lxc_clear_includes(conf);
struct lxc_list *it;
struct id_map *map;
char c = '1';
- int ret = -1;
+ int ret = -1, status = -1;
struct lxc_list *idmap = NULL, *tmplist = NULL;
struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
*host_uid_map = NULL, *host_gid_map = NULL;
close(p[0]);
p[0] = -1;
+ euid = geteuid();
+ egid = getegid();
+
/* Find container root. */
lxc_list_for_each(it, &conf->id_map) {
map = it->elem;
container_root_uid->hostid = map->hostid;
container_root_uid->nsid = 0;
container_root_uid->range = map->range;
+
+ /* Check if container root mapping contains a mapping
+ * for user's uid.
+ */
+ if (euid >= map->hostid && euid < map->hostid + map->range)
+ host_uid_map = container_root_uid;
} else if (map->idtype == ID_TYPE_GID && container_root_gid == NULL) {
container_root_gid = malloc(sizeof(*container_root_gid));
if (!container_root_gid)
container_root_gid->hostid = map->hostid;
container_root_gid->nsid = 0;
container_root_gid->range = map->range;
+
+ /* Check if container root mapping contains a mapping
+ * for user's gid.
+ */
+ if (egid >= map->hostid && egid < map->hostid + map->range)
+ host_gid_map = container_root_gid;
}
/* Found container root. */
goto on_error;
}
- host_uid_map = container_root_uid;
- host_gid_map = container_root_gid;
-
/* Check whether the {g,u}id of the user has a mapping. */
- euid = geteuid();
- egid = getegid();
- if (euid != container_root_uid->hostid)
+ if (!host_uid_map)
host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
- if (egid != container_root_gid->hostid)
+ if (!host_gid_map)
host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
if (!host_uid_map) {
ret = lxc_map_ids(idmap, pid);
if (ret < 0) {
ERROR("error setting up {g,u}id mappings for child process "
- "\"%d\"",
- pid);
+ "\"%d\"", pid);
goto on_error;
}
goto on_error;
}
+on_error:
/* Wait for child to finish. */
- ret = wait_for_pid(pid);
+ if (pid > 0)
+ status = wait_for_pid(pid);
-on_error:
if (idmap)
lxc_free_idmap(idmap);
if (container_root_uid)
close(p[0]);
close(p[1]);
+ if (status < 0)
+ ret = -1;
+
+ return ret;
+}
+
+int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
+ const char *fn_name)
+{
+ pid_t pid;
+ uid_t euid, egid;
+ struct userns_fn_data d;
+ int p[2];
+ struct id_map *map;
+ struct lxc_list *cur;
+ char c = '1';
+ int ret = -1;
+ struct lxc_list *idmap = NULL, *tmplist = NULL;
+ struct id_map *container_root_uid = NULL, *container_root_gid = NULL,
+ *host_uid_map = NULL, *host_gid_map = NULL;
+
+ ret = pipe(p);
+ if (ret < 0) {
+ SYSERROR("opening pipe");
+ return -1;
+ }
+ d.fn = fn;
+ d.fn_name = fn_name;
+ d.arg = data;
+ d.p[0] = p[0];
+ d.p[1] = p[1];
+
+ /* Clone child in new user namespace. */
+ pid = lxc_clone(run_userns_fn, &d, CLONE_NEWUSER);
+ if (pid < 0) {
+ ERROR("failed to clone child process in new user namespace");
+ goto on_error;
+ }
+
+ close(p[0]);
+ p[0] = -1;
+
+ euid = geteuid();
+ egid = getegid();
+
+ /* Allocate new {g,u}id map list. */
+ idmap = malloc(sizeof(*idmap));
+ if (!idmap)
+ goto on_error;
+ lxc_list_init(idmap);
+
+ /* Find container root. */
+ lxc_list_for_each(cur, &conf->id_map) {
+ struct id_map *tmpmap;
+
+ tmplist = malloc(sizeof(*tmplist));
+ if (!tmplist)
+ goto on_error;
+
+ tmpmap = malloc(sizeof(*tmpmap));
+ if (!tmpmap) {
+ free(tmplist);
+ goto on_error;
+ }
+
+ memset(tmpmap, 0, sizeof(*tmpmap));
+ memcpy(tmpmap, cur->elem, sizeof(*tmpmap));
+ tmplist->elem = tmpmap;
+
+ lxc_list_add_tail(idmap, tmplist);
+
+ map = cur->elem;
+
+ if (map->idtype == ID_TYPE_UID)
+ if (euid >= map->hostid && euid < map->hostid + map->range)
+ host_uid_map = map;
+
+ if (map->idtype == ID_TYPE_GID)
+ if (egid >= map->hostid && egid < map->hostid + map->range)
+ host_gid_map = map;
+
+ if (map->nsid != 0)
+ continue;
+
+ if (map->idtype == ID_TYPE_UID)
+ if (container_root_uid == NULL)
+ container_root_uid = map;
+
+ if (map->idtype == ID_TYPE_GID)
+ if (container_root_gid == NULL)
+ container_root_gid = map;
+ }
+
+ if (!container_root_uid || !container_root_gid) {
+ ERROR("No mapping for container root found");
+ goto on_error;
+ }
+
+ /* Check whether the {g,u}id of the user has a mapping. */
+ if (!host_uid_map)
+ host_uid_map = idmap_add(conf, euid, ID_TYPE_UID);
+ else
+ host_uid_map = container_root_uid;
+
+ if (!host_gid_map)
+ host_gid_map = idmap_add(conf, egid, ID_TYPE_GID);
+ else
+ host_gid_map = container_root_gid;
+
+ if (!host_uid_map) {
+ DEBUG("Failed to find mapping for uid %d", euid);
+ goto on_error;
+ }
+
+ if (!host_gid_map) {
+ DEBUG("Failed to find mapping for gid %d", egid);
+ goto on_error;
+ }
+
+ if (host_uid_map && (host_uid_map != container_root_uid)) {
+ /* Add container root to the map. */
+ tmplist = malloc(sizeof(*tmplist));
+ if (!tmplist)
+ goto on_error;
+ lxc_list_add_elem(tmplist, host_uid_map);
+ lxc_list_add_tail(idmap, tmplist);
+ }
+ /* idmap will now keep track of that memory. */
+ host_uid_map = NULL;
+
+ if (host_gid_map && (host_gid_map != container_root_gid)) {
+ tmplist = malloc(sizeof(*tmplist));
+ if (!tmplist)
+ goto on_error;
+ lxc_list_add_elem(tmplist, host_gid_map);
+ lxc_list_add_tail(idmap, tmplist);
+ }
+ /* idmap will now keep track of that memory. */
+ host_gid_map = NULL;
+
+ if (lxc_log_get_level() == LXC_LOG_LEVEL_TRACE ||
+ conf->loglevel == LXC_LOG_LEVEL_TRACE) {
+ lxc_list_for_each(cur, idmap) {
+ map = cur->elem;
+ TRACE("establishing %cid mapping for \"%d\" in new "
+ "user namespace: nsuid %lu - hostid %lu - range "
+ "%lu",
+ (map->idtype == ID_TYPE_UID) ? 'u' : 'g', pid,
+ map->nsid, map->hostid, map->range);
+ }
+ }
+
+ /* Set up {g,u}id mapping for user namespace of child process. */
+ ret = lxc_map_ids(idmap, pid);
+ if (ret < 0) {
+ ERROR("error setting up {g,u}id mappings for child process "
+ "\"%d\"", pid);
+ goto on_error;
+ }
+
+ /* Tell child to proceed. */
+ if (write(p[1], &c, 1) != 1) {
+ SYSERROR("failed telling child process \"%d\" to proceed", pid);
+ goto on_error;
+ }
+
+on_error:
+ /* Wait for child to finish. */
+ if (pid > 0)
+ ret = wait_for_pid(pid);
+
+ if (idmap)
+ lxc_free_idmap(idmap);
+ if (host_uid_map && (host_uid_map != container_root_uid))
+ free(host_uid_map);
+ if (host_gid_map && (host_gid_map != container_root_gid))
+ free(host_gid_map);
+
+ if (p[0] != -1)
+ close(p[0]);
+ close(p[1]);
+
return ret;
}
ERROR("To pass uid mappings to lxc-create, you could create");
ERROR("~/.config/lxc/default.conf:");
ERROR("lxc.include = %s", LXC_DEFAULT_CONFIG);
- ERROR("lxc.id_map = u 0 %u %u", uid, urange);
- ERROR("lxc.id_map = g 0 %u %u", gid, grange);
+ ERROR("lxc.idmap = u 0 %u %u", uid, urange);
+ ERROR("lxc.idmap = g 0 %u %u", gid, grange);
free(gname);
free(uname);
return result;
}
-
-int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname,
- struct lxc_netdev *netdev, pid_t pid)
-{
- pid_t child;
- int bytes, pipefd[2];
- char buffer[MAXPATHLEN] = {0};
-
- if (netdev->type != LXC_NET_VETH) {
- ERROR("nic type %d not support for unprivileged use",
- netdev->type);
- return -1;
- }
-
- if (pipe(pipefd) < 0) {
- SYSERROR("pipe failed");
- return -1;
- }
-
- child = fork();
- if (child < 0) {
- SYSERROR("fork");
- close(pipefd[0]);
- close(pipefd[1]);
- return -1;
- }
-
- if (child == 0) { /* child */
- /* Call lxc-user-nic pid type bridge. */
- int ret;
- char pidstr[LXC_NUMSTRLEN64];
-
- close(pipefd[0]); /* Close the read-end of the pipe. */
-
- /* Redirect stdout to write-end of the pipe. */
- ret = dup2(pipefd[1], STDOUT_FILENO);
- if (ret >= 0)
- ret = dup2(pipefd[1], STDERR_FILENO);
- close(pipefd[1]); /* Close the write-end of the pipe. */
- if (ret < 0) {
- SYSERROR("Failed to dup2() to redirect stdout to pipe file descriptor.");
- exit(EXIT_FAILURE);
- }
-
- if (!netdev->link)
- SYSERROR("Network link for network device \"%s\" is "
- "missing", netdev->priv.veth_attr.pair);
-
- ret = snprintf(pidstr, LXC_NUMSTRLEN64, "%d", pid);
- if (ret < 0 || ret >= LXC_NUMSTRLEN64)
- exit(EXIT_FAILURE);
- pidstr[LXC_NUMSTRLEN64 - 1] = '\0';
-
- INFO("Execing lxc-user-nic delete %s %s %s veth %s %s", lxcpath,
- lxcname, pidstr, netdev->link, netdev->priv.veth_attr.pair);
- execlp(LXC_USERNIC_PATH, LXC_USERNIC_PATH, "delete", lxcpath,
- lxcname, pidstr, "veth", netdev->link,
- netdev->priv.veth_attr.pair, (char *)NULL);
- SYSERROR("Failed to exec lxc-user-nic.");
- exit(EXIT_FAILURE);
- }
-
- /* close the write-end of the pipe */
- close(pipefd[1]);
-
- bytes = read(pipefd[0], &buffer, MAXPATHLEN);
- if (bytes < 0) {
- SYSERROR("Failed to read from pipe file descriptor.");
- close(pipefd[0]);
- return -1;
- }
- buffer[bytes - 1] = '\0';
-
- if (wait_for_pid(child) != 0) {
- ERROR("lxc-user-nic failed to delete requested network: %s",
- buffer[0] != '\0' ? buffer : "(null)");
- close(pipefd[0]);
- return -1;
- }
- TRACE("Received output \"%s\" from lxc-user-nic", buffer);
-
- /* close the read-end of the pipe */
- close(pipefd[0]);
-
- return 0;
-}