netlink: fix interface dump.

The current code missed interface addition when reallocating
 temporary buffer.
Tweak the code to perform the reallocation first and add
 interface afterwards unconditionally.

Reported by:	Marek Zarychta <zarychtam@plan-b.pwste.edu.pl>
MFC after:	3 days
This commit is contained in:
Alexander V. Chernikov 2023-02-16 13:17:58 +00:00
parent f52ca3dfd5
commit 86fd0bdba5
2 changed files with 77 additions and 17 deletions

View File

@ -449,24 +449,23 @@ rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *n
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
wa.count++;
if (match_iface(&attrs, ifp)) {
if (offset < base_count) {
if (!if_try_ref(ifp))
continue;
if (offset >= base_count) {
/* Too many matches, need to reallocate */
struct ifnet **new_array;
int sz = base_count * sizeof(void *);
base_count *= 2;
new_array = malloc(sz * 2, M_TEMP, M_NOWAIT);
if (new_array == NULL) {
error = ENOMEM;
break;
}
memcpy(new_array, match_array, sz);
free(match_array, M_TEMP);
match_array = new_array;
}
if (if_try_ref(ifp))
match_array[offset++] = ifp;
continue;
}
/* Too many matches, need to reallocate */
struct ifnet **new_array;
int sz = base_count * sizeof(void *);
base_count *= 2;
new_array = malloc(sz * 2, M_TEMP, M_NOWAIT);
if (new_array == NULL) {
error = ENOMEM;
break;
}
memcpy(new_array, match_array, sz);
free(match_array, M_TEMP);
match_array = new_array;
}
}
NET_EPOCH_EXIT(et);

View File

@ -242,6 +242,67 @@ def test_delete_iface(self):
assert rx_msg.is_type(NlMsgType.NLMSG_ERROR)
assert rx_msg.error_code == errno.ENODEV
@pytest.mark.require_user("root")
def test_dump_ifaces_many(self):
"""Tests if interface dummp is not missing interfaces"""
ifmap = {}
for ifname in (self.vnet.iface_alias_map["if1"].name, "lo0"):
ifindex = socket.if_nametoindex(ifname)
ifmap[ifindex] = ifname
for i in range(40):
ifname = "lo{}".format(i + 1)
flags = NlmNewFlags.NLM_F_EXCL.value | NlmNewFlags.NLM_F_CREATE.value
msg = NetlinkIflaMessage(self.helper, NlRtMsgType.RTM_NEWLINK.value)
msg.nl_hdr.nlmsg_flags = (
flags | NlmBaseFlags.NLM_F_ACK.value | NlmBaseFlags.NLM_F_REQUEST.value
)
msg.add_nla(NlAttrStr(IflattrType.IFLA_IFNAME, ifname))
msg.add_nla(
NlAttrNested(
IflattrType.IFLA_LINKINFO,
[
NlAttrStrn(IflinkInfo.IFLA_INFO_KIND, "lo"),
],
)
)
rx_msg = self.get_reply(msg)
assert rx_msg.is_type(NlMsgType.NLMSG_ERROR)
nla_list, _ = rx_msg.parse_attrs(bytes(rx_msg.cookie)[4:], rtnl_ifla_attrs)
nla_map = {n.nla_type: n for n in nla_list}
assert nla_map[IflattrType.IFLA_IFNAME.value].text == ifname
ifindex = nla_map[IflattrType.IFLA_NEW_IFINDEX.value].u32
assert ifindex > 0
assert ifindex not in ifmap
ifmap[ifindex] = ifname
# Dump all interfaces and check if the output matches ifmap
kernel_ifmap = {}
msg = NetlinkIflaMessage(self.helper, NlRtMsgType.RTM_GETLINK.value)
msg.nl_hdr.nlmsg_flags = (
NlmBaseFlags.NLM_F_ACK.value | NlmBaseFlags.NLM_F_REQUEST.value
)
self.write_message(msg)
while True:
rx_msg = self.read_message()
if msg.nl_hdr.nlmsg_seq != rx_msg.nl_hdr.nlmsg_seq:
raise ValueError(
"unexpected seq {}".format(rx_msg.nl_hdr.nlmsg_seq)
)
if rx_msg.is_type(NlMsgType.NLMSG_ERROR):
raise ValueError("unexpected message {}".format(rx_msg))
if rx_msg.is_type(NlMsgType.NLMSG_DONE):
break
if not rx_msg.is_type(NlRtMsgType.RTM_NEWLINK):
raise ValueError("unexpected message {}".format(rx_msg))
ifindex = rx_msg.base_hdr.ifi_index
assert ifindex == rx_msg.base_hdr.ifi_index
kernel_ifmap[ifindex] = rx_msg.get_nla(IflattrType.IFLA_IFNAME).text
assert kernel_ifmap == ifmap
#
# *
# * {len=76, type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, seq=1662892737, pid=0},