From 57daf8ff8c6c357a5a083657e5b03d2883cbc4f9 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 18 Sep 2024 18:49:41 +0200 Subject: [PATCH] iplink: fix fd leak when playing with netns 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 Signed-off-by: Nicolas Dichtel Signed-off-by: Stephen Hemminger Reference:https://github.com/iproute2/iproute2/commit/57daf8ff8c6c357a5a083657e5b03d2883cbc4f9 Conflict:Context adaptation --- include/utils.h | 3 +++ ip/iplink.c | 6 +++++- lib/utils.c | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/utils.h b/include/utils.h index f26ed82..4a08372 100644 --- a/include/utils.h +++ b/include/utils.h @@ -390,4 +390,7 @@ int proto_a2n(unsigned short *id, const char *buf, const char *proto_n2a(unsigned short id, char *buf, int len, const struct proto *proto_tb, size_t tb_len); +int open_fds_add(int fd); +void open_fds_close(void); + #endif /* __UTILS_H__ */ diff --git a/ip/iplink.c b/ip/iplink.c index 9a548dd..f7465d1 100644 --- a/ip/iplink.c +++ b/ip/iplink.c @@ -675,9 +675,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); @@ -1141,6 +1143,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; diff --git a/lib/utils.c b/lib/utils.c index 99ba7a2..1f4a498 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -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); @@ -1970,3 +1973,23 @@ int proto_a2n(unsigned short *id, const char *buf, return 0; } + +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; +} -- 2.43.0