Skip to content

Commit 4952cd3

Browse files
Richard Alpedavem330
authored andcommitted
tipc: refactor node xmit and fix memory leaks
Refactor tipc_node_xmit() to fail fast and fail early. Fix several potential memory leaks in unexpected error paths. Reported-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: Richard Alpe <richard.alpe@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 37ace20 commit 4952cd3

File tree

2 files changed

+38
-24
lines changed

2 files changed

+38
-24
lines changed

net/tipc/link.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,8 +903,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
903903
if (unlikely(l->backlog[i].len >= l->backlog[i].limit))
904904
return link_schedule_user(l, list);
905905
}
906-
if (unlikely(msg_size(hdr) > mtu))
906+
if (unlikely(msg_size(hdr) > mtu)) {
907+
skb_queue_purge(list);
907908
return -EMSGSIZE;
909+
}
908910

909911
/* Prepare each packet for sending, and add to relevant queue: */
910912
while (skb_queue_len(list)) {
@@ -916,8 +918,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
916918

917919
if (likely(skb_queue_len(transmq) < maxwin)) {
918920
_skb = skb_clone(skb, GFP_ATOMIC);
919-
if (!_skb)
921+
if (!_skb) {
922+
skb_queue_purge(list);
920923
return -ENOBUFS;
924+
}
921925
__skb_dequeue(list);
922926
__skb_queue_tail(transmq, skb);
923927
__skb_queue_tail(xmitq, _skb);

net/tipc/node.c

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,41 +1166,51 @@ static int __tipc_nl_add_node(struct tipc_nl_msg *msg, struct tipc_node *node)
11661166
* @dnode: address of destination node
11671167
* @selector: a number used for deterministic link selection
11681168
* Consumes the buffer chain, except when returning -ELINKCONG
1169-
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
1169+
* Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF
11701170
*/
11711171
int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
11721172
u32 dnode, int selector)
11731173
{
11741174
struct tipc_link_entry *le = NULL;
11751175
struct tipc_node *n;
11761176
struct sk_buff_head xmitq;
1177-
int bearer_id = -1;
1178-
int rc = -EHOSTUNREACH;
1177+
int bearer_id;
1178+
int rc;
1179+
1180+
if (in_own_node(net, dnode)) {
1181+
tipc_sk_rcv(net, list);
1182+
return 0;
1183+
}
11791184

1180-
__skb_queue_head_init(&xmitq);
11811185
n = tipc_node_find(net, dnode);
1182-
if (likely(n)) {
1183-
tipc_node_read_lock(n);
1184-
bearer_id = n->active_links[selector & 1];
1185-
if (bearer_id >= 0) {
1186-
le = &n->links[bearer_id];
1187-
spin_lock_bh(&le->lock);
1188-
rc = tipc_link_xmit(le->link, list, &xmitq);
1189-
spin_unlock_bh(&le->lock);
1190-
}
1186+
if (unlikely(!n)) {
1187+
skb_queue_purge(list);
1188+
return -EHOSTUNREACH;
1189+
}
1190+
1191+
tipc_node_read_lock(n);
1192+
bearer_id = n->active_links[selector & 1];
1193+
if (unlikely(bearer_id == INVALID_BEARER_ID)) {
11911194
tipc_node_read_unlock(n);
1192-
if (likely(!rc))
1193-
tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
1194-
else if (rc == -ENOBUFS)
1195-
tipc_node_link_down(n, bearer_id, false);
11961195
tipc_node_put(n);
1197-
return rc;
1196+
skb_queue_purge(list);
1197+
return -EHOSTUNREACH;
11981198
}
11991199

1200-
if (likely(in_own_node(net, dnode))) {
1201-
tipc_sk_rcv(net, list);
1202-
return 0;
1203-
}
1200+
__skb_queue_head_init(&xmitq);
1201+
le = &n->links[bearer_id];
1202+
spin_lock_bh(&le->lock);
1203+
rc = tipc_link_xmit(le->link, list, &xmitq);
1204+
spin_unlock_bh(&le->lock);
1205+
tipc_node_read_unlock(n);
1206+
1207+
if (likely(rc == 0))
1208+
tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
1209+
else if (rc == -ENOBUFS)
1210+
tipc_node_link_down(n, bearer_id, false);
1211+
1212+
tipc_node_put(n);
1213+
12041214
return rc;
12051215
}
12061216

0 commit comments

Comments
 (0)