ipnetns: use-after-free problem in get_netnsid_from_name func

Follow the following steps:
 # ip netns add net1
 # export MALLOC_MMAP_THRESHOLD_=0
 # ip netns list
then Segmentation fault (core dumped) will occur.

In get_netnsid_from_name func, answer is freed before
rta_getattr_u32(tb[NETNSA_NSID]), where tb[] refers to answer`s
content. If we set MALLOC_MMAP_THRESHOLD_=0, mmap will be adoped to
malloc memory, which will be freed immediately after calling free
func.  So reading tb[NETNSA_NSID] will access the released memory
after free(answer).

Here, we will call get_netnsid_from_name(tb[NETNSA_NSID]) before free(answer).

Fixes: 86bf43c7c2 ("lib/libnetlink: update rtnl_talk to support malloc buff at run time")
Reported-by: Huiying Kou <kouhuiying@huawei.com>
Signed-off-by: Zhiqiang Liu <liuzhiqiang26@huawei.com>
Acked-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
Zhiqiang Liu 2019-05-05 09:59:51 +08:00 committed by Stephen Hemminger
parent e73306048f
commit 9bf2c538a0

View File

@ -107,7 +107,7 @@ int get_netnsid_from_name(const char *name)
struct nlmsghdr *answer; struct nlmsghdr *answer;
struct rtattr *tb[NETNSA_MAX + 1]; struct rtattr *tb[NETNSA_MAX + 1];
struct rtgenmsg *rthdr; struct rtgenmsg *rthdr;
int len, fd; int len, fd, ret = -1;
netns_nsid_socket_init(); netns_nsid_socket_init();
@ -124,23 +124,22 @@ int get_netnsid_from_name(const char *name)
/* Validate message and parse attributes */ /* Validate message and parse attributes */
if (answer->nlmsg_type == NLMSG_ERROR) if (answer->nlmsg_type == NLMSG_ERROR)
goto err_out; goto out;
rthdr = NLMSG_DATA(answer); rthdr = NLMSG_DATA(answer);
len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr)); len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
if (len < 0) if (len < 0)
goto err_out; goto out;
parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len); parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
if (tb[NETNSA_NSID]) { if (tb[NETNSA_NSID]) {
free(answer); ret = rta_getattr_u32(tb[NETNSA_NSID]);
return rta_getattr_u32(tb[NETNSA_NSID]);
} }
err_out: out:
free(answer); free(answer);
return -1; return ret;
} }
struct nsid_cache { struct nsid_cache {