]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
iplink: fix fd leak when playing with netns
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Wed, 18 Sep 2024 16:49:41 +0000 (18:49 +0200)
committerStephen Hemminger <stephen@networkplumber.org>
Sat, 28 Sep 2024 16:24:56 +0000 (09:24 -0700)
The command 'ip link set foo netns mynetns' opens a file descriptor to fill
the netlink attribute IFLA_NET_NS_FD. This file descriptor is never closed.
When batch mode is used, the number of file descriptor may grow greatly and
reach the maximum file descriptor number that can be opened.

This fd can be closed only after the netlink answer. Moreover, a second
fd could be opened because some (struct link_util)->parse_opt() handlers
call iplink_parse().

Let's add a helper to manage these fds:
 - open_fds_add() stores a fd, up to 5 (arbitrary choice, it seems enough);
 - open_fds_close() closes all stored fds.

Fixes: 0dc34c7713bb ("iproute2: Add processless network namespace support")
Reported-by: Alexandre Ferrieux <alexandre.ferrieux@orange.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
include/utils.h
ip/iplink.c
lib/utils.c

index a2a98b9bf17d9ed42a6ca4ed7a9c6c601e9c942b..f044b3401320b665e39851395c153a89140df008 100644 (file)
@@ -395,4 +395,7 @@ const char *proto_n2a(unsigned short id, char *buf, int len,
 
 FILE *generic_proc_open(const char *env, const char *name);
 
+int open_fds_add(int fd);
+void open_fds_close(void);
+
 #endif /* __UTILS_H__ */
index 3bc75d243719cb0924f955fa693b364f53de94a6..0dd83ff448461c97ac3a15edd24ef6619f51b272 100644 (file)
@@ -622,9 +622,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
                        if (netns != -1)
                                duparg("netns", *argv);
                        netns = netns_get_fd(*argv);
-                       if (netns >= 0)
+                       if (netns >= 0) {
+                               open_fds_add(netns);
                                addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
                                          &netns, 4);
+                       }
                        else if (get_integer(&netns, *argv, 0) == 0)
                                addattr_l(&req->n, sizeof(*req),
                                          IFLA_NET_NS_PID, &netns, 4);
@@ -1088,6 +1090,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
        else
                ret = rtnl_talk(&rth, &req.n, NULL);
 
+       open_fds_close();
+
        if (ret)
                return -2;
 
index deb7654a0b013cae66d53741cf85d89c7c2cca0f..98c06ab6a652eb24632987ea0ec04c9ab6f8220f 100644 (file)
@@ -40,6 +40,9 @@ int timestamp_short;
 int pretty;
 const char *_SL_ = "\n";
 
+static int open_fds[5];
+static int open_fds_cnt;
+
 static int af_byte_len(int af);
 static void print_time(char *buf, int len, __u32 time);
 static void print_time64(char *buf, int len, __s64 time);
@@ -2017,3 +2020,23 @@ FILE *generic_proc_open(const char *env, const char *name)
 
        return fopen(p, "r");
 }
+
+int open_fds_add(int fd)
+{
+       if (open_fds_cnt >= ARRAY_SIZE(open_fds))
+               return -1;
+
+       open_fds[open_fds_cnt++] = fd;
+       return 0;
+}
+
+
+void open_fds_close(void)
+{
+       int i;
+
+       for (i = 0; i < open_fds_cnt; i++)
+               close(open_fds[i]);
+
+       open_fds_cnt = 0;
+}