aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2014-04-23 20:22:35 -0400
committerDavid S. Miller <davem@davemloft.net>2014-04-24 13:52:54 -0400
commit973462bbde79bb827824c73b59027a0aed5c9ca6 (patch)
treefdf9ac5d381071d750adb9cb81e406a2b16fd58f /net
parenta64d90fd962c2956da7505f98a302408450365e2 (diff)
rtnetlink: Warn when interface's information won't fit in our packet
Without IFLA_EXT_MASK specified, the information reported for a single interface in response to RTM_GETLINK is expected to fit within a netlink packet of NLMSG_GOODSIZE. If it doesn't, however, things will go badly wrong, When listing all interfaces, netlink_dump() will incorrectly treat -EMSGSIZE on the first message in a packet as the end of the listing and omit information for that interface and all subsequent ones. This can cause getifaddrs(3) to enter an infinite loop. This patch won't fix the problem, but it will WARN_ON() making it easier to track down what's going wrong. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Reviewed-by: Jiri Pirko <jpirko@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/rtnetlink.c17
1 files changed, 12 insertions, 5 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 64ad17d077ed..8db72ac88feb 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1198,6 +1198,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1198 struct hlist_head *head; 1198 struct hlist_head *head;
1199 struct nlattr *tb[IFLA_MAX+1]; 1199 struct nlattr *tb[IFLA_MAX+1];
1200 u32 ext_filter_mask = 0; 1200 u32 ext_filter_mask = 0;
1201 int err;
1201 1202
1202 s_h = cb->args[0]; 1203 s_h = cb->args[0];
1203 s_idx = cb->args[1]; 1204 s_idx = cb->args[1];
@@ -1218,11 +1219,17 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1218 hlist_for_each_entry_rcu(dev, head, index_hlist) { 1219 hlist_for_each_entry_rcu(dev, head, index_hlist) {
1219 if (idx < s_idx) 1220 if (idx < s_idx)
1220 goto cont; 1221 goto cont;
1221 if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, 1222 err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
1222 NETLINK_CB(cb->skb).portid, 1223 NETLINK_CB(cb->skb).portid,
1223 cb->nlh->nlmsg_seq, 0, 1224 cb->nlh->nlmsg_seq, 0,
1224 NLM_F_MULTI, 1225 NLM_F_MULTI,
1225 ext_filter_mask) <= 0) 1226 ext_filter_mask);
1227 /* If we ran out of room on the first message,
1228 * we're in trouble
1229 */
1230 WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
1231
1232 if (err <= 0)
1226 goto out; 1233 goto out;
1227 1234
1228 nl_dump_check_consistent(cb, nlmsg_hdr(skb)); 1235 nl_dump_check_consistent(cb, nlmsg_hdr(skb));