Skip to content

Commit 640bfcf

Browse files
dsaherngregkh
authored andcommitted
net: Improve handling of failures on link and route dumps
[ Upstream commit f6c5775ff0bfa62b072face6bf1d40f659f194b2 ] 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 <mq@ucw.cz> Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 7ede5c9 commit 640bfcf

3 files changed

Lines changed: 49 additions & 28 deletions

File tree

net/core/rtnetlink.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,24 +1458,26 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
14581458
cb->nlh->nlmsg_seq, 0,
14591459
NLM_F_MULTI,
14601460
ext_filter_mask);
1461-
/* If we ran out of room on the first message,
1462-
* we're in trouble
1463-
*/
1464-
WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
14651461

1466-
if (err < 0)
1467-
goto out;
1462+
if (err < 0) {
1463+
if (likely(skb->len))
1464+
goto out;
1465+
1466+
goto out_err;
1467+
}
14681468

14691469
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
14701470
cont:
14711471
idx++;
14721472
}
14731473
}
14741474
out:
1475+
err = skb->len;
1476+
out_err:
14751477
cb->args[1] = idx;
14761478
cb->args[0] = h;
14771479

1478-
return skb->len;
1480+
return err;
14791481
}
14801482

14811483
int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len)
@@ -3127,8 +3129,12 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
31273129
err = br_dev->netdev_ops->ndo_bridge_getlink(
31283130
skb, portid, seq, dev,
31293131
filter_mask, NLM_F_MULTI);
3130-
if (err < 0 && err != -EOPNOTSUPP)
3131-
break;
3132+
if (err < 0 && err != -EOPNOTSUPP) {
3133+
if (likely(skb->len))
3134+
break;
3135+
3136+
goto out_err;
3137+
}
31323138
}
31333139
idx++;
31343140
}
@@ -3139,16 +3145,22 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
31393145
seq, dev,
31403146
filter_mask,
31413147
NLM_F_MULTI);
3142-
if (err < 0 && err != -EOPNOTSUPP)
3143-
break;
3148+
if (err < 0 && err != -EOPNOTSUPP) {
3149+
if (likely(skb->len))
3150+
break;
3151+
3152+
goto out_err;
3153+
}
31443154
}
31453155
idx++;
31463156
}
31473157
}
3158+
err = skb->len;
3159+
out_err:
31483160
rcu_read_unlock();
31493161
cb->args[0] = idx;
31503162

3151-
return skb->len;
3163+
return err;
31523164
}
31533165

31543166
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
@@ -757,7 +757,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
757757
unsigned int e = 0, s_e;
758758
struct fib_table *tb;
759759
struct hlist_head *head;
760-
int dumped = 0;
760+
int dumped = 0, err;
761761

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

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

793-
return skb->len;
800+
return err;
794801
}
795802

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

19071907
/* rcu_read_lock is hold by caller */
19081908
hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) {
1909+
int err;
1910+
19091911
if (i < s_i) {
19101912
i++;
19111913
continue;
@@ -1916,17 +1918,14 @@ static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb,
19161918
continue;
19171919
}
19181920

1919-
if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
1920-
cb->nlh->nlmsg_seq,
1921-
RTM_NEWROUTE,
1922-
tb->tb_id,
1923-
fa->fa_type,
1924-
xkey,
1925-
KEYLENGTH - fa->fa_slen,
1926-
fa->fa_tos,
1927-
fa->fa_info, NLM_F_MULTI) < 0) {
1921+
err = fib_dump_info(skb, NETLINK_CB(cb->skb).portid,
1922+
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
1923+
tb->tb_id, fa->fa_type,
1924+
xkey, KEYLENGTH - fa->fa_slen,
1925+
fa->fa_tos, fa->fa_info, NLM_F_MULTI);
1926+
if (err < 0) {
19281927
cb->args[4] = i;
1929-
return -1;
1928+
return err;
19301929
}
19311930
i++;
19321931
}
@@ -1948,10 +1947,13 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
19481947
t_key key = cb->args[3];
19491948

19501949
while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
1951-
if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) {
1950+
int err;
1951+
1952+
err = fn_trie_dump_leaf(l, tb, skb, cb);
1953+
if (err < 0) {
19521954
cb->args[3] = key;
19531955
cb->args[2] = count;
1954-
return -1;
1956+
return err;
19551957
}
19561958

19571959
++count;

0 commit comments

Comments
 (0)