Skip to content

Commit f6c5775

Browse files
dsaherndavem330
authored andcommitted
net: Improve handling of failures on link and route dumps
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]>
1 parent 19a0f7e commit f6c5775

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
@@ -1627,24 +1627,26 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
16271627
cb->nlh->nlmsg_seq, 0,
16281628
flags,
16291629
ext_filter_mask);
1630-
/* If we ran out of room on the first message,
1631-
* we're in trouble
1632-
*/
1633-
WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
16341630

1635-
if (err < 0)
1636-
goto out;
1631+
if (err < 0) {
1632+
if (likely(skb->len))
1633+
goto out;
1634+
1635+
goto out_err;
1636+
}
16371637

16381638
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
16391639
cont:
16401640
idx++;
16411641
}
16421642
}
16431643
out:
1644+
err = skb->len;
1645+
out_err:
16441646
cb->args[1] = idx;
16451647
cb->args[0] = h;
16461648

1647-
return skb->len;
1649+
return err;
16481650
}
16491651

16501652
int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len,
@@ -3453,8 +3455,12 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
34533455
err = br_dev->netdev_ops->ndo_bridge_getlink(
34543456
skb, portid, seq, dev,
34553457
filter_mask, NLM_F_MULTI);
3456-
if (err < 0 && err != -EOPNOTSUPP)
3457-
break;
3458+
if (err < 0 && err != -EOPNOTSUPP) {
3459+
if (likely(skb->len))
3460+
break;
3461+
3462+
goto out_err;
3463+
}
34583464
}
34593465
idx++;
34603466
}
@@ -3465,16 +3471,22 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
34653471
seq, dev,
34663472
filter_mask,
34673473
NLM_F_MULTI);
3468-
if (err < 0 && err != -EOPNOTSUPP)
3469-
break;
3474+
if (err < 0 && err != -EOPNOTSUPP) {
3475+
if (likely(skb->len))
3476+
break;
3477+
3478+
goto out_err;
3479+
}
34703480
}
34713481
idx++;
34723482
}
34733483
}
3484+
err = skb->len;
3485+
out_err:
34743486
rcu_read_unlock();
34753487
cb->args[0] = idx;
34763488

3477-
return skb->len;
3489+
return err;
34783490
}
34793491

34803492
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
@@ -763,7 +763,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
763763
unsigned int e = 0, s_e;
764764
struct fib_table *tb;
765765
struct hlist_head *head;
766-
int dumped = 0;
766+
int dumped = 0, err;
767767

768768
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
769769
((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
@@ -783,20 +783,27 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
783783
if (dumped)
784784
memset(&cb->args[2], 0, sizeof(cb->args) -
785785
2 * sizeof(cb->args[0]));
786-
if (fib_table_dump(tb, skb, cb) < 0)
787-
goto out;
786+
err = fib_table_dump(tb, skb, cb);
787+
if (err < 0) {
788+
if (likely(skb->len))
789+
goto out;
790+
791+
goto out_err;
792+
}
788793
dumped = 1;
789794
next:
790795
e++;
791796
}
792797
}
793798
out:
799+
err = skb->len;
800+
out_err:
794801
rcu_read_unlock();
795802

796803
cb->args[1] = e;
797804
cb->args[0] = h;
798805

799-
return skb->len;
806+
return err;
800807
}
801808

802809
/* 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
@@ -1983,6 +1983,8 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
19831983

19841984
/* rcu_read_lock is hold by caller */
19851985
hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
1986+
int err;
1987+
19861988
if (i < s_i) {
19871989
i++;
19881990
continue;
@@ -1993,17 +1995,14 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
19931995
continue;
19941996
}
19951997

1996-
if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
1997-
cb->nlh->nlmsg_seq,
1998-
RTM_NEWROUTE,
1999-
tb->tb_id,
2000-
fa->fa_type,
2001-
xkey,
2002-
KEYLENGTH - fa->fa_slen,
2003-
fa->fa_tos,
2004-
fa->fa_info, NLM_F_MULTI) < 0) {
1998+
err = fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
1999+
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
2000+
tb->tb_id, fa->fa_type,
2001+
xkey, KEYLENGTH - fa->fa_slen,
2002+
fa->fa_tos, fa->fa_info, NLM_F_MULTI);
2003+
if (err < 0) {
20052004
cb->args[4] = i;
2006-
return -1;
2005+
return err;
20072006
}
20082007
i++;
20092008
}
@@ -2025,10 +2024,13 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
20252024
t_key key = cb->args[3];
20262025

20272026
while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
2028-
if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
2027+
int err;
2028+
2029+
err = fn_trie_dump_leaf(l, tb, skb, cb);
2030+
if (err < 0) {
20292031
cb->args[3] = key;
20302032
cb->args[2] = count;
2031-
return -1;
2033+
return err;
20322034
}
20332035

20342036
++count;

0 commit comments

Comments
 (0)