Skip to content

Commit 6787927

Browse files
Tung Nguyendavem330
authored andcommitted
tipc: buffer overflow handling in listener socket
Default socket receive buffer size for a listener socket is 2Mb. For each arriving empty SYN, the linux kernel allocates a 768 bytes buffer. This means that a listener socket can serve maximum 2700 simultaneous empty connection setup requests before it hits a receive buffer overflow, and much fewer if the SYN is carrying any significant amount of data. When this happens the setup request is rejected, and the client receives an ECONNREFUSED error. This commit mitigates this problem by letting the client socket try to retransmit the SYN message multiple times when it sees it rejected with the code TIPC_ERR_OVERLOAD. Retransmission is done at random intervals in the range of [100 ms, setup_timeout / 4], as many times as there is room for within the setup timeout limit. Signed-off-by: Tung Nguyen <tung.q.nguyen@dektech.com.au> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 25b9221 commit 6787927

File tree

3 files changed

+64
-6
lines changed

3 files changed

+64
-6
lines changed

net/tipc/msg.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,10 @@ bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err)
525525
if (hlen == SHORT_H_SIZE)
526526
hlen = BASIC_H_SIZE;
527527

528+
/* Don't return data along with SYN+, - sender has a clone */
529+
if (msg_is_syn(_hdr) && err == TIPC_ERR_OVERLOAD)
530+
dlen = 0;
531+
528532
/* Allocate new buffer to return */
529533
*skb = tipc_buf_acquire(hlen + dlen, GFP_ATOMIC);
530534
if (!*skb)
@@ -552,6 +556,22 @@ bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err)
552556
return false;
553557
}
554558

559+
bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy)
560+
{
561+
struct sk_buff *skb, *_skb;
562+
563+
skb_queue_walk(msg, skb) {
564+
_skb = skb_clone(skb, GFP_ATOMIC);
565+
if (!_skb) {
566+
__skb_queue_purge(cpy);
567+
pr_err_ratelimited("Failed to clone buffer chain\n");
568+
return false;
569+
}
570+
__skb_queue_tail(cpy, _skb);
571+
}
572+
return true;
573+
}
574+
555575
/**
556576
* tipc_msg_lookup_dest(): try to find new destination for named message
557577
* @skb: the buffer containing the message.

net/tipc/msg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,7 @@ bool tipc_msg_pskb_copy(u32 dst, struct sk_buff_head *msg,
980980
struct sk_buff_head *cpy);
981981
void __tipc_skb_queue_sorted(struct sk_buff_head *list, u16 seqno,
982982
struct sk_buff *skb);
983+
bool tipc_msg_skb_clone(struct sk_buff_head *msg, struct sk_buff_head *cpy);
983984

984985
static inline u16 buf_seqno(struct sk_buff *skb)
985986
{

net/tipc/socket.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
#include "netlink.h"
4848
#include "group.h"
4949

50-
#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */
50+
#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */
5151
#define CONN_PROBING_INTV msecs_to_jiffies(3600000) /* [ms] => 1 h */
5252
#define TIPC_FWD_MSG 1
5353
#define TIPC_MAX_PORT 0xffffffff
@@ -80,7 +80,6 @@ struct sockaddr_pair {
8080
* @publications: list of publications for port
8181
* @blocking_link: address of the congested link we are currently sleeping on
8282
* @pub_count: total # of publications port has made during its lifetime
83-
* @probing_state:
8483
* @conn_timeout: the time we can wait for an unresponded setup request
8584
* @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
8685
* @cong_link_cnt: number of congested links
@@ -102,8 +101,8 @@ struct tipc_sock {
102101
struct list_head cong_links;
103102
struct list_head publications;
104103
u32 pub_count;
105-
uint conn_timeout;
106104
atomic_t dupl_rcvcnt;
105+
u16 conn_timeout;
107106
bool probe_unacked;
108107
u16 cong_link_cnt;
109108
u16 snt_unacked;
@@ -507,6 +506,9 @@ static void __tipc_shutdown(struct socket *sock, int error)
507506
tipc_wait_for_cond(sock, &timeout, (!tsk->cong_link_cnt &&
508507
!tsk_conn_cong(tsk)));
509508

509+
/* Remove any pending SYN message */
510+
__skb_queue_purge(&sk->sk_write_queue);
511+
510512
/* Reject all unreceived messages, except on an active connection
511513
* (which disconnects locally & sends a 'FIN+' to peer).
512514
*/
@@ -1362,6 +1364,8 @@ static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dlen)
13621364
rc = tipc_msg_build(hdr, m, 0, dlen, mtu, &pkts);
13631365
if (unlikely(rc != dlen))
13641366
return rc;
1367+
if (unlikely(syn && !tipc_msg_skb_clone(&pkts, &sk->sk_write_queue)))
1368+
return -ENOMEM;
13651369

13661370
rc = tipc_node_xmit(net, &pkts, dnode, tsk->portid);
13671371
if (unlikely(rc == -ELINKCONG)) {
@@ -1491,6 +1495,7 @@ static void tipc_sk_finish_conn(struct tipc_sock *tsk, u32 peer_port,
14911495
tipc_node_add_conn(net, peer_node, tsk->portid, peer_port);
14921496
tsk->max_pkt = tipc_node_get_mtu(net, peer_node, tsk->portid);
14931497
tsk->peer_caps = tipc_node_get_capabilities(net, peer_node);
1498+
__skb_queue_purge(&sk->sk_write_queue);
14941499
if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL)
14951500
return;
14961501

@@ -1977,6 +1982,7 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
19771982
u32 oport = msg_origport(hdr);
19781983
u32 onode = msg_orignode(hdr);
19791984
int err = msg_errcode(hdr);
1985+
unsigned long delay;
19801986

19811987
if (unlikely(msg_mcast(hdr)))
19821988
return false;
@@ -2001,8 +2007,18 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb)
20012007
if (oport != pport || onode != pnode)
20022008
return false;
20032009

2004-
/* Rejected SYN - abort */
2005-
break;
2010+
/* Rejected SYN */
2011+
if (err != TIPC_ERR_OVERLOAD)
2012+
break;
2013+
2014+
/* Prepare for new setup attempt if we have a SYN clone */
2015+
if (skb_queue_empty(&sk->sk_write_queue))
2016+
break;
2017+
get_random_bytes(&delay, 2);
2018+
delay %= (tsk->conn_timeout / 4);
2019+
delay = msecs_to_jiffies(delay + 100);
2020+
sk_reset_timer(sk, &sk->sk_timer, jiffies + delay);
2021+
return false;
20062022
case TIPC_OPEN:
20072023
case TIPC_DISCONNECTING:
20082024
return false;
@@ -2561,12 +2577,26 @@ static void tipc_sk_check_probing_state(struct sock *sk,
25612577
sk_reset_timer(sk, &sk->sk_timer, jiffies + CONN_PROBING_INTV);
25622578
}
25632579

2580+
static void tipc_sk_retry_connect(struct sock *sk, struct sk_buff_head *list)
2581+
{
2582+
struct tipc_sock *tsk = tipc_sk(sk);
2583+
2584+
/* Try again later if dest link is congested */
2585+
if (tsk->cong_link_cnt) {
2586+
sk_reset_timer(sk, &sk->sk_timer, msecs_to_jiffies(100));
2587+
return;
2588+
}
2589+
/* Prepare SYN for retransmit */
2590+
tipc_msg_skb_clone(&sk->sk_write_queue, list);
2591+
}
2592+
25642593
static void tipc_sk_timeout(struct timer_list *t)
25652594
{
25662595
struct sock *sk = from_timer(sk, t, sk_timer);
25672596
struct tipc_sock *tsk = tipc_sk(sk);
25682597
u32 pnode = tsk_peer_node(tsk);
25692598
struct sk_buff_head list;
2599+
int rc = 0;
25702600

25712601
skb_queue_head_init(&list);
25722602
bh_lock_sock(sk);
@@ -2580,12 +2610,19 @@ static void tipc_sk_timeout(struct timer_list *t)
25802610

25812611
if (sk->sk_state == TIPC_ESTABLISHED)
25822612
tipc_sk_check_probing_state(sk, &list);
2613+
else if (sk->sk_state == TIPC_CONNECTING)
2614+
tipc_sk_retry_connect(sk, &list);
25832615

25842616
bh_unlock_sock(sk);
25852617

25862618
if (!skb_queue_empty(&list))
2587-
tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid);
2619+
rc = tipc_node_xmit(sock_net(sk), &list, pnode, tsk->portid);
25882620

2621+
/* SYN messages may cause link congestion */
2622+
if (rc == -ELINKCONG) {
2623+
tipc_dest_push(&tsk->cong_links, pnode, 0);
2624+
tsk->cong_link_cnt = 1;
2625+
}
25892626
sock_put(sk);
25902627
}
25912628

0 commit comments

Comments
 (0)