]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxc-user-nic: check db before trying to delete
authorChristian Brauner <christian.brauner@ubuntu.com>
Sun, 27 Aug 2017 07:17:10 +0000 (09:17 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Tue, 29 Aug 2017 20:54:50 +0000 (22:54 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/lxc_user_nic.c

index 7b9aa980214c1a49e4a951e41f4fff1c7dff0226..defa69060373a52757a4bcd04bce5d76a943b932 100644 (file)
@@ -3127,7 +3127,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\" "
@@ -5117,12 +5117,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) {
@@ -5161,20 +5160,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);
index 077f594e7cf25eb5e1f84fbbfe6e3faac4f2001f..813cc49b426e3857d3cdf6fabcd26cd1e4b1d941 100644 (file)
@@ -453,7 +453,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 */
index 7ab20fddc53bbe910a834fdab00b174c5d1ff6f3..0237a9268359edd2c7073c66851e2e2e24fa7b0b 100644 (file)
@@ -572,20 +572,23 @@ 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) {
-               usernic_error("Failed to fstat: %s.\n", strerror(errno));
+       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;
@@ -966,9 +974,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;
@@ -989,6 +1000,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) {
@@ -1030,12 +1050,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 (request == LXC_USERNIC_DELETE) {
+               int ret;
+               struct alloted_s *it;
+               bool found_nicname = false;
 
-               if (strcmp(args.type, "ovs")) {
+               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);
                }
 
@@ -1046,10 +1090,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);