From 8b8e00a24d3eafa57bfd5db3f364c6570f0c8f10 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Sun, 27 Aug 2017 09:17:10 +0200 Subject: [PATCH] lxc-user-nic: check db before trying to delete Signed-off-by: Christian Brauner --- src/lxc/conf.c | 18 +++++------ src/lxc/conf.h | 2 +- src/lxc/lxc_user_nic.c | 73 +++++++++++++++++++++++++++++++++--------- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 73b1089e58..d2a1f7cad6 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -3234,7 +3234,7 @@ bool lxc_delete_network(struct lxc_handler *handler) if (am_unpriv()) { if (is_ovs_bridge(netdev->link)) { ret = lxc_unpriv_delete_nic(handler->lxcpath, - handler->name, "ovs", + handler->name, netdev, getpid()); if (ret < 0) WARN("Failed to remove port \"%s\" " @@ -5143,12 +5143,11 @@ struct lxc_list *sort_cgroup_settings(struct lxc_list* cgroup_settings) return result; } -int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type, +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 netdev_link[IFNAMSIZ + 1]; char buffer[MAX_BUFFER_SIZE] = {0}; if (netdev->type != LXC_NET_VETH) { @@ -5187,20 +5186,19 @@ int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type, exit(EXIT_FAILURE); } - if (netdev->link) - strncpy(netdev_link, netdev->link, IFNAMSIZ); - else - strncpy(netdev_link, "none", IFNAMSIZ); + 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 ovs %s %s", lxcpath, - lxcname, pidstr, netdev_link, netdev->priv.veth_attr.pair); + 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, "ovs", netdev_link, + lxcname, pidstr, "veth", netdev->link, netdev->priv.veth_attr.pair, (char *)NULL); SYSERROR("Failed to exec lxc-user-nic."); exit(EXIT_FAILURE); diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 89e7923481..c54abb3ab7 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -500,7 +500,7 @@ extern FILE *make_anonymous_mount_file(struct lxc_list *mount); extern struct lxc_list *sort_cgroup_settings(struct lxc_list *cgroup_settings); extern unsigned long add_required_remount_flags(const char *s, const char *d, unsigned long flags); -extern int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, char *type, +extern int lxc_unpriv_delete_nic(const char *lxcpath, char *lxcname, struct lxc_netdev *netdev, pid_t pid); #endif /* __LXC_CONF_H */ diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c index 628a9c70be..db36142c18 100644 --- a/src/lxc/lxc_user_nic.c +++ b/src/lxc/lxc_user_nic.c @@ -572,19 +572,22 @@ struct entry_line { bool keep; }; -static bool cull_entries(int fd, char *me, char *t, char *br) +static bool cull_entries(int fd, char *me, char *t, char *br, char *nicname, + bool *found_nicname) { - int i, n = 0; + int i, ret; off_t len; - char *buf, *p, *e, *nic; + char *buf, *e, *nic, *p; struct stat sb; + int n = 0; struct entry_line *entry_lines = NULL; nic = alloca(100); if (!nic) return false; - if (fstat(fd, &sb) < 0) { + ret = fstat(fd, &sb); + if (ret < 0) { usernic_error("Failed to fstat: %s\n", strerror(errno)); return false; } @@ -593,7 +596,7 @@ static bool cull_entries(int fd, char *me, char *t, char *br) if (len == 0) return true; - buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + buf = lxc_strmmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { usernic_error("Failed to establish shared memory mapping: %s\n", strerror(errno)); @@ -622,6 +625,10 @@ static bool cull_entries(int fd, char *me, char *t, char *br) if (nic && !nic_exists(nic)) entry_lines[n - 1].keep = false; + if (nicname) + if (!strcmp(nic, nicname)) + *found_nicname = true; + p += entry_lines[n - 1].len + 1; if (p >= e) break; @@ -639,8 +646,9 @@ static bool cull_entries(int fd, char *me, char *t, char *br) } free(entry_lines); - munmap(buf, sb.st_size); - if (ftruncate(fd, p - buf)) + lxc_strmunmap(buf, sb.st_size); + ret = ftruncate(fd, p - buf); + if (ret < 0) usernic_error("Failed to set new file size: %s\n", strerror(errno)); @@ -676,7 +684,7 @@ static char *get_nic_if_avail(int fd, struct alloted_s *names, int pid, char *buf = NULL; for (n = names; n != NULL; n = n->next) - cull_entries(fd, n->name, intype, br); + cull_entries(fd, n->name, intype, br, NULL, NULL); if (allowed == 0) return NULL; @@ -965,9 +973,12 @@ struct user_nic_args { char *veth_name; }; +#define LXC_USERNIC_CREATE 0 +#define LXC_USERNIC_DELETE 1 + int main(int argc, char *argv[]) { - int fd, ifindex, n, pid, ret; + int fd, ifindex, n, pid, request, ret; char *me, *newname; char *cnic = NULL, *nicname = NULL; struct alloted_s *alloted = NULL; @@ -988,6 +999,15 @@ int main(int argc, char *argv[]) if (argc >= 8) args.veth_name = argv[7]; + if (!strcmp(args.cmd, "create")) { + request = LXC_USERNIC_CREATE; + } else if (!strcmp(args.cmd, "delete")) { + request = LXC_USERNIC_DELETE; + } else { + usage(argv[0], true); + exit(EXIT_FAILURE); + } + /* Set a sane env, because we are setuid-root. */ ret = clearenv(); if (ret) { @@ -1029,12 +1049,36 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if (!strcmp(args.cmd, "delete")) { - close(fd); + n = get_alloted(me, args.type, args.link, &alloted); - if (strcmp(args.type, "ovs")) { + if (request == LXC_USERNIC_DELETE) { + int ret; + struct alloted_s *it; + bool found_nicname = false; + + if (!is_ovs_bridge(args.link)) { usernic_error("%s", "Deletion of non ovs type network " - "devics not implemented\n"); + "devices not implemented\n"); + close(fd); + free_alloted(&alloted); + exit(EXIT_FAILURE); + } + + /* Check whether the network device we are supposed to delete + * exists in the db. If it doesn't we will not delete it as we + * need to assume the network device is not under our control. + * As a side effect we also clear any invalid entries from the + * database. + */ + for (it = alloted; it; it = it->next) + cull_entries(fd, it->name, args.type, args.link, + args.veth_name, &found_nicname); + close(fd); + free_alloted(&alloted); + + if (!found_nicname) { + usernic_error("%s", "Caller is not allowed to delete " + "network device\n"); exit(EXIT_FAILURE); } @@ -1045,10 +1089,9 @@ int main(int argc, char *argv[]) args.veth_name, args.link); exit(EXIT_FAILURE); } + exit(EXIT_SUCCESS); } - - n = get_alloted(me, args.type, args.link, &alloted); if (n > 0) nicname = get_nic_if_avail(fd, alloted, pid, args.type, args.link, n, &cnic);