Skip to content

Commit 6864761

Browse files
dsaherngregkh
authored andcommitted
net: Improve handling of failures on link and route dumps
[ Upstream commit f6c5775 ] In general, rtnetlink dumps do not anticipate failure to dump a single object (e.g., link or route) on a single pass. As both route and link objects have grown via more attributes, that is no longer a given. netlink dumps can handle a failure if the dump function returns an error; specifically, netlink_dump adds the return code to the response if it is <= 0 so userspace is notified of the failure. The missing piece is the rtnetlink dump functions returning the error. Fix route and link dump functions to return the errors if no object is added to an skb (detected by skb->len != 0). IPv6 route dumps (rt6_dump_route) already return the error; this patch updates IPv4 and link dumps. Other dump functions may need to be ajusted as well. Reported-by: Jan Moskyto Matejka <[email protected]> Signed-off-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0174b07 commit 6864761

File tree

3 files changed

+49
-28
lines changed

3 files changed

+49
-28
lines changed

net/core/rtnetlink.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,24 +1617,26 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
16171617
cb->nlh->nlmsg_seq, 0,
16181618
flags,
16191619
ext_filter_mask);
1620-
/* If we ran out of room on the first message,
1621-
* we're in trouble
1622-
*/
1623-
WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
16241620

1625-
if (err < 0)
1626-
goto out;
1621+
if (err < 0) {
1622+
if (likely(skb->len))
1623+
goto out;
1624+
1625+
goto out_err;
1626+
}
16271627

16281628
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
16291629
cont:
16301630
idx++;
16311631
}
16321632
}
16331633
out:
1634+
err = skb->len;
1635+
out_err:
16341636
cb->args[1] = idx;
16351637
cb->args[0] = h;
16361638

1637-
return skb->len;
1639+
return err;
16381640
}
16391641

16401642
int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len)
@@ -3413,8 +3415,12 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
34133415
err = br_dev->netdev_ops->ndo_bridge_getlink(
34143416
skb, portid, seq, dev,
34153417
filter_mask, NLM_F_MULTI);
3416-
if (err < 0 && err != -EOPNOTSUPP)
3417-
break;
3418+
if (err < 0 && err != -EOPNOTSUPP) {
3419+
if (likely(skb->len))
3420+
break;
3421+
3422+
goto out_err;
3423+
}
34183424
}
34193425
idx++;
34203426
}
@@ -3425,16 +3431,22 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
34253431
seq, dev,
34263432
filter_mask,
34273433
NLM_F_MULTI);
3428-
if (err < 0 && err != -EOPNOTSUPP)
3429-
break;
3434+
if (err < 0 && err != -EOPNOTSUPP) {
3435+
if (likely(skb->len))
3436+
break;
3437+
3438+
goto out_err;
3439+
}
34303440
}
34313441
idx++;
34323442
}
34333443
}
3444+
err = skb->len;
3445+
out_err:
34343446
rcu_read_unlock();
34353447
cb->args[0] = idx;
34363448

3437-
return skb->len;
3449+
return err;
34383450
}
34393451

34403452
static inline size_t bridge_nlmsg_size(void)

net/ipv4/fib_frontend.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
758758
unsigned int e = 0, s_e;
759759
struct fib_table *tb;
760760
struct hlist_head *head;
761-
int dumped = 0;
761+
int dumped = 0, err;
762762

763763
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
764764
((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
@@ -778,20 +778,27 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
778778
if (dumped)
779779
memset(&cb->args[2], 0, sizeof(cb->args) -
780780
2 * sizeof(cb->args[0]));
781-
if (fib_table_dump(tb, skb, cb) < 0)
782-
goto out;
781+
err = fib_table_dump(tb, skb, cb);
782+
if (err < 0) {
783+
if (likely(skb->len))
784+
goto out;
785+
786+
goto out_err;
787+
}
783788
dumped = 1;
784789
next:
785790
e++;
786791
}
787792
}
788793
out:
794+
err = skb->len;
795+
out_err:
789796
rcu_read_unlock();
790797

791798
cb->args[1] = e;
792799
cb->args[0] = h;
793800

794-
return skb->len;
801+
return err;
795802
}
796803

797804
/* Prepare and feed intra-kernel routing request.

net/ipv4/fib_trie.c

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,8 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
19321932

19331933
/* rcu_read_lock is hold by caller */
19341934
hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
1935+
int err;
1936+
19351937
if (i < s_i) {
19361938
i++;
19371939
continue;
@@ -1942,17 +1944,14 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
19421944
continue;
19431945
}
19441946

1945-
if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
1946-
cb->nlh->nlmsg_seq,
1947-
RTM_NEWROUTE,
1948-
tb->tb_id,
1949-
fa->fa_type,
1950-
xkey,
1951-
KEYLENGTH - fa->fa_slen,
1952-
fa->fa_tos,
1953-
fa->fa_info, NLM_F_MULTI) < 0) {
1947+
err = fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
1948+
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1949+
tb->tb_id, fa->fa_type,
1950+
xkey, KEYLENGTH - fa->fa_slen,
1951+
fa->fa_tos, fa->fa_info, NLM_F_MULTI);
1952+
if (err < 0) {
19541953
cb->args[4] = i;
1955-
return -1;
1954+
return err;
19561955
}
19571956
i++;
19581957
}
@@ -1974,10 +1973,13 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
19741973
t_key key = cb->args[3];
19751974

19761975
while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
1977-
if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
1976+
int err;
1977+
1978+
err = fn_trie_dump_leaf(l, tb, skb, cb);
1979+
if (err < 0) {
19781980
cb->args[3] = key;
19791981
cb->args[2] = count;
1980-
return -1;
1982+
return err;
19811983
}
19821984

19831985
++count;

0 commit comments

Comments
 (0)