]> git.proxmox.com Git - mirror_lxc.git/blobdiff - src/lxc/network.c
network: remove stack allocations
[mirror_lxc.git] / src / lxc / network.c
index 56ca12b3b276bdc20c36d9b1659284689df58620..249d9d471f1e432ac37c7099b62d3cbbfc49b204 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+#include <arpa/inet.h>
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 #include <linux/sockios.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/inotify.h>
 #include <sys/ioctl.h>
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
 
+#include "../include/netns_ifaddrs.h"
 #include "af_unix.h"
 #include "conf.h"
 #include "config.h"
+#include "file_utils.h"
 #include "log.h"
 #include "macro.h"
+#include "memory_utils.h"
 #include "network.h"
 #include "nl.h"
+#include "raw_syscalls.h"
+#include "syscall_wrappers.h"
 #include "utils.h"
 
-#if HAVE_IFADDRS_H
-#include <ifaddrs.h>
-#else
-#include <../include/ifaddrs.h>
-#endif
-
 #ifndef HAVE_STRLCPY
 #include "include/strlcpy.h"
 #endif
@@ -549,15 +550,15 @@ out:
 #define PHYSNAME "/sys/class/net/%s/phy80211/name"
 static char *is_wlan(const char *ifname)
 {
+       __do_free char *path;
        int i, ret;
        long physlen;
        size_t len;
-       char *path;
        FILE *f;
        char *physname = NULL;
 
        len = strlen(ifname) + strlen(PHYSNAME) - 1;
-       path = alloca(len + 1);
+       path = must_realloc(NULL, len + 1);
        ret = snprintf(path, len, PHYSNAME, ifname);
        if (ret < 0 || (size_t)ret >= len)
                goto bad;
@@ -961,6 +962,9 @@ int netdev_get_mtu(int ifindex)
        if (err < 0)
                goto out;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
        do {
                /* Restore the answer buffer length, it might have been
                 * overwritten by a previous receive.
@@ -1023,6 +1027,8 @@ int netdev_get_mtu(int ifindex)
                }
        } while (readmore);
 
+#pragma GCC diagnostic pop
+
        /* If we end up here, we didn't find any result, so signal an error. */
        err = -1;
 
@@ -1353,15 +1359,15 @@ static int proc_sys_net_write(const char *path, const char *value)
 static int neigh_proxy_set(const char *ifname, int family, int flag)
 {
        int ret;
-       char path[MAXPATHLEN];
+       char path[PATH_MAX];
 
        if (family != AF_INET && family != AF_INET6)
                return -EINVAL;
 
-       ret = snprintf(path, MAXPATHLEN, "/proc/sys/net/%s/conf/%s/%s",
+       ret = snprintf(path, PATH_MAX, "/proc/sys/net/%s/conf/%s/%s",
                       family == AF_INET ? "ipv4" : "ipv6", ifname,
                       family == AF_INET ? "proxy_arp" : "proxy_ndp");
-       if (ret < 0 || (size_t)ret >= MAXPATHLEN)
+       if (ret < 0 || (size_t)ret >= PATH_MAX)
                return -E2BIG;
 
        return proc_sys_net_write(path, flag ? "1" : "0");
@@ -1500,6 +1506,9 @@ int lxc_ipv4_addr_add(int ifindex, struct in_addr *addr, struct in_addr *bcast,
  * the given RTM_NEWADDR message. Allocates memory for the address and stores
  * that pointer in *res (so res should be an in_addr** or in6_addr**).
  */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
 static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res)
 {
        int addrlen;
@@ -1545,6 +1554,8 @@ static int ifa_get_local_ip(int family, struct nlmsghdr *msg, void **res)
        return 0;
 }
 
+#pragma GCC diagnostic pop
+
 static int ip_addr_get(int family, int ifindex, void **res)
 {
        int answer_len, err;
@@ -1587,6 +1598,9 @@ static int ip_addr_get(int family, int ifindex, void **res)
        if (err < 0)
                goto out;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+
        do {
                /* Restore the answer buffer length, it might have been
                 * overwritten by a previous receive.
@@ -1646,6 +1660,8 @@ static int ip_addr_get(int family, int ifindex, void **res)
                }
        } while (readmore);
 
+#pragma GCC diagnostic pop
+
        /* If we end up here, we didn't find any result, so signal an
         * error.
         */
@@ -1832,7 +1848,7 @@ static int lxc_ovs_delete_port_exec(void *data)
 int lxc_ovs_delete_port(const char *bridge, const char *nic)
 {
        int ret;
-       char cmd_output[MAXPATHLEN];
+       char cmd_output[PATH_MAX];
        struct ovs_veth_args args;
 
        args.bridge = bridge;
@@ -1860,7 +1876,7 @@ static int lxc_ovs_attach_bridge_exec(void *data)
 static int lxc_ovs_attach_bridge(const char *bridge, const char *nic)
 {
        int ret;
-       char cmd_output[MAXPATHLEN];
+       char cmd_output[PATH_MAX];
        struct ovs_veth_args args;
 
        args.bridge = bridge;
@@ -1934,7 +1950,7 @@ static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 char *lxc_mkifname(char *template)
 {
        int ret;
-       struct ifaddrs *ifa, *ifaddr;
+       struct netns_ifaddrs *ifa, *ifaddr;
        char name[IFNAMSIZ];
        bool exists = false;
        size_t i = 0;
@@ -1951,7 +1967,7 @@ char *lxc_mkifname(char *template)
                return NULL;
 
        /* Get all the network interfaces. */
-       ret = getifaddrs(&ifaddr);
+       ret = netns_getifaddrs(&ifaddr, -1, &(bool){false});
        if (ret < 0) {
                SYSERROR("Failed to get network interfaces");
                return NULL;
@@ -1967,9 +1983,9 @@ char *lxc_mkifname(char *template)
                for (i = 0; i < strlen(name); i++) {
                        if (name[i] == 'X') {
 #ifdef HAVE_RAND_R
-                               name[i] = padchar[rand_r(&seed) % (strlen(padchar) - 1)];
+                               name[i] = padchar[rand_r(&seed) % strlen(padchar)];
 #else
-                               name[i] = padchar[rand() % (strlen(padchar) - 1)];
+                               name[i] = padchar[rand() % strlen(padchar)];
 #endif
                        }
                }
@@ -1985,7 +2001,7 @@ char *lxc_mkifname(char *template)
                        break;
        }
 
-       freeifaddrs(ifaddr);
+       netns_freeifaddrs(ifaddr);
        (void)strlcpy(template, name, strlen(template) + 1);
 
        return template;
@@ -2078,7 +2094,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
        int bytes, pipefd[2];
        char *token, *saveptr = NULL;
        char netdev_link[IFNAMSIZ];
-       char buffer[MAXPATHLEN] = {0};
+       char buffer[PATH_MAX] = {0};
        size_t retlen;
 
        if (netdev->type != LXC_NET_VETH) {
@@ -2101,8 +2117,6 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
        }
 
        if (child == 0) {
-               int ret;
-               size_t retlen;
                char pidstr[INTTYPE_TO_STRLEN(pid_t)];
 
                close(pipefd[0]);
@@ -2148,7 +2162,7 @@ static int lxc_create_network_unpriv_exec(const char *lxcpath, const char *lxcna
        /* close the write-end of the pipe */
        close(pipefd[1]);
 
-       bytes = lxc_read_nointr(pipefd[0], &buffer, MAXPATHLEN);
+       bytes = lxc_read_nointr(pipefd[0], &buffer, PATH_MAX);
        if (bytes < 0) {
                SYSERROR("Failed to read from pipe file descriptor");
                close(pipefd[0]);
@@ -2242,7 +2256,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
        int bytes, ret;
        pid_t child;
        int pipefd[2];
-       char buffer[MAXPATHLEN] = {0};
+       char buffer[PATH_MAX] = {0};
 
        if (netdev->type != LXC_NET_VETH) {
                ERROR("Network type %d not support for unprivileged use", netdev->type);
@@ -2265,7 +2279,6 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
 
        if (child == 0) {
                char *hostveth;
-               int ret;
 
                close(pipefd[0]);
 
@@ -2304,7 +2317,7 @@ static int lxc_delete_network_unpriv_exec(const char *lxcpath, const char *lxcna
 
        close(pipefd[1]);
 
-       bytes = lxc_read_nointr(pipefd[0], &buffer, MAXPATHLEN);
+       bytes = lxc_read_nointr(pipefd[0], &buffer, PATH_MAX);
        if (bytes < 0) {
                SYSERROR("Failed to read from pipe file descriptor.");
                close(pipefd[0]);
@@ -2406,7 +2419,7 @@ bool lxc_delete_network_unpriv(struct lxc_handler *handler)
                     netdev->link);
 
 clear_ifindices:
-               /* We need to clear any ifindeces we recorded so liblxc won't
+               /* We need to clear any ifindices we recorded so liblxc won't
                 * have cached stale data which would cause it to fail on reboot
                 * we're we don't re-read the on-disk config file.
                 */
@@ -2617,7 +2630,7 @@ bool lxc_delete_network_priv(struct lxc_handler *handler)
                             hostveth, netdev->link);
 
 clear_ifindices:
-               /* We need to clear any ifindeces we recorded so liblxc won't
+               /* We need to clear any ifindices we recorded so liblxc won't
                 * have cached stale data which would cause it to fail on reboot
                 * we're we don't re-read the on-disk config file.
                 */
@@ -2910,8 +2923,6 @@ static int lxc_setup_netdev_in_child_namespaces(struct lxc_netdev *netdev)
 
        /* set the network device up */
        if (netdev->flags & IFF_UP) {
-               int err;
-
                err = lxc_netdev_up(current_ifname);
                if (err) {
                        errno = -err;
@@ -3056,7 +3067,7 @@ int lxc_network_send_veth_names_to_child(struct lxc_handler *handler)
                if (netdev->type != LXC_NET_VETH)
                        continue;
 
-               ret = send(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
+               ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
                if (ret < 0)
                        return -1;
                TRACE("Sent network device name \"%s\" to child", netdev->name);
@@ -3081,7 +3092,7 @@ int lxc_network_recv_veth_names_from_parent(struct lxc_handler *handler)
                if (netdev->type != LXC_NET_VETH)
                        continue;
 
-               ret = recv(data_sock, netdev->name, IFNAMSIZ, 0);
+               ret = lxc_recv_nointr(data_sock, netdev->name, IFNAMSIZ, 0);
                if (ret < 0)
                        return -1;
                TRACE("Received network device name \"%s\" from parent", netdev->name);
@@ -3104,19 +3115,19 @@ int lxc_network_send_name_and_ifindex_to_parent(struct lxc_handler *handler)
                struct lxc_netdev *netdev = iterator->elem;
 
                /* Send network device name in the child's namespace to parent. */
-               ret = send(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
+               ret = lxc_send_nointr(data_sock, netdev->name, IFNAMSIZ, MSG_NOSIGNAL);
                if (ret < 0)
                        return -1;
 
                /* Send network device ifindex in the child's namespace to
                 * parent.
                 */
-               ret = send(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), MSG_NOSIGNAL);
+               ret = lxc_send_nointr(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), MSG_NOSIGNAL);
                if (ret < 0)
                        return -1;
        }
 
-       TRACE("Sent network device names and ifindeces to parent");
+       TRACE("Sent network device names and ifindices to parent");
        return 0;
 }
 
@@ -3136,14 +3147,14 @@ int lxc_network_recv_name_and_ifindex_from_child(struct lxc_handler *handler)
                /* Receive network device name in the child's namespace to
                 * parent.
                 */
-               ret = recv(data_sock, netdev->name, IFNAMSIZ, 0);
+               ret = lxc_recv_nointr(data_sock, netdev->name, IFNAMSIZ, 0);
                if (ret < 0)
                        return -1;
 
                /* Receive network device ifindex in the child's namespace to
                 * parent.
                 */
-               ret = recv(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
+               ret = lxc_recv_nointr(data_sock, &netdev->ifindex, sizeof(netdev->ifindex), 0);
                if (ret < 0)
                        return -1;
        }
@@ -3165,68 +3176,141 @@ void lxc_delete_network(struct lxc_handler *handler)
                DEBUG("Deleted network devices");
 }
 
-int addattr(struct nlmsghdr *n, size_t maxlen, int type, const void *data, size_t alen)
+int lxc_netns_set_nsid(int fd)
 {
-       int len = RTA_LENGTH(alen);
-       struct rtattr *rta;
+       int ret;
+       char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
+                NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
+                NLMSG_ALIGN(1024)];
+       struct nl_handler nlh;
+       struct nlmsghdr *hdr;
+       struct rtgenmsg *msg;
+       int saved_errno;
+       const __s32 ns_id = -1;
+       const __u32 netns_fd = fd;
 
-       if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
+       ret = netlink_open(&nlh, NETLINK_ROUTE);
+       if (ret < 0)
                return -1;
 
-       rta = NLMSG_TAIL(n);
-       rta->rta_type = type;
-       rta->rta_len = len;
-       if (alen)
-               memcpy(RTA_DATA(rta), data, alen);
-       n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
+       memset(buf, 0, sizeof(buf));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+       hdr = (struct nlmsghdr *)buf;
+       msg = (struct rtgenmsg *)NLMSG_DATA(hdr);
+#pragma GCC diagnostic pop
+
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
+       hdr->nlmsg_type = RTM_NEWNSID;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       hdr->nlmsg_pid = 0;
+       hdr->nlmsg_seq = RTM_NEWNSID;
+       msg->rtgen_family = AF_UNSPEC;
+
+       ret = addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
+       if (ret < 0)
+               goto on_error;
+
+       ret = addattr(hdr, 1024, __LXC_NETNSA_NSID, &ns_id, sizeof(ns_id));
+       if (ret < 0)
+               goto on_error;
+
+       ret = __netlink_transaction(&nlh, hdr, hdr);
+
+on_error:
+       saved_errno = errno;
+       netlink_close(&nlh);
+       errno = saved_errno;
+
+       return ret;
+}
+
+static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+
+       memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
+
+       while (RTA_OK(rta, len)) {
+               unsigned short type = rta->rta_type;
+
+               if ((type <= max) && (!tb[type]))
+                       tb[type] = rta;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+               rta = RTA_NEXT(rta, len);
+#pragma GCC diagnostic pop
+       }
 
        return 0;
 }
 
-/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */
-enum {
-       __LXC_NETNSA_NONE,
-#define __LXC_NETNSA_NSID_NOT_ASSIGNED -1
-       __LXC_NETNSA_NSID,
-       __LXC_NETNSA_PID,
-       __LXC_NETNSA_FD,
-       __LXC_NETNSA_MAX,
-};
+static inline __s32 rta_getattr_s32(const struct rtattr *rta)
+{
+       return *(__s32 *)RTA_DATA(rta);
+}
 
-int lxc_netns_set_nsid(int fd)
+#ifndef NETNS_RTA
+#define NETNS_RTA(r) \
+       ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))))
+#endif
+
+int lxc_netns_get_nsid(int fd)
 {
-       ssize_t ret;
+       int ret;
+       ssize_t len;
        char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
                 NLMSG_ALIGN(sizeof(struct rtgenmsg)) +
                 NLMSG_ALIGN(1024)];
+       struct rtattr *tb[__LXC_NETNSA_MAX + 1];
        struct nl_handler nlh;
        struct nlmsghdr *hdr;
        struct rtgenmsg *msg;
-       __s32 ns_id = -1;
+       int saved_errno;
        __u32 netns_fd = fd;
 
        ret = netlink_open(&nlh, NETLINK_ROUTE);
        if (ret < 0)
-               return ret;
+               return -1;
 
        memset(buf, 0, sizeof(buf));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
        hdr = (struct nlmsghdr *)buf;
        msg = (struct rtgenmsg *)NLMSG_DATA(hdr);
+#pragma GCC diagnostic pop
 
        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*msg));
-       hdr->nlmsg_type = RTM_NEWNSID;
+       hdr->nlmsg_type = RTM_GETNSID;
        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        hdr->nlmsg_pid = 0;
-       hdr->nlmsg_seq = RTM_NEWNSID;
+       hdr->nlmsg_seq = RTM_GETNSID;
        msg->rtgen_family = AF_UNSPEC;
 
-       addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
-       addattr(hdr, 1024, __LXC_NETNSA_NSID, &ns_id, sizeof(ns_id));
+       ret = addattr(hdr, 1024, __LXC_NETNSA_FD, &netns_fd, sizeof(netns_fd));
+       if (ret == 0)
+               ret = __netlink_transaction(&nlh, hdr, hdr);
 
-       ret = __netlink_transaction(&nlh, hdr, hdr);
+       saved_errno = errno;
        netlink_close(&nlh);
+       errno = saved_errno;
        if (ret < 0)
                return -1;
 
-       return 0;
+       errno = EINVAL;
+       msg = NLMSG_DATA(hdr);
+       len = hdr->nlmsg_len - NLMSG_SPACE(sizeof(*msg));
+       if (len < 0)
+               return -1;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+       parse_rtattr(tb, __LXC_NETNSA_MAX, NETNS_RTA(msg), len);
+       if (tb[__LXC_NETNSA_NSID])
+               return rta_getattr_s32(tb[__LXC_NETNSA_NSID]);
+#pragma GCC diagnostic pop
+
+       return -1;
 }