Skip to content

Commit 70a1592

Browse files
Thadeu Lima de Souza Cascardoanthraxx
authored andcommitted
dccp: ccid: move timers to struct dccp_sock
When dccps_hc_tx_ccid is freed, ccid timers may still trigger. The reason del_timer_sync can't be used is because this relies on keeping a reference to struct sock. But as we keep a pointer to dccps_hc_tx_ccid and free that during disconnect, the timer should really belong to struct dccp_sock. This addresses CVE-2020-16119. Fixes: 839a609 (net: dccp: Convert timers to use timer_setup()) Signed-off-by: Thadeu Lima de Souza Cascardo <[email protected]> Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
1 parent 7591ae1 commit 70a1592

File tree

3 files changed

+41
-23
lines changed

3 files changed

+41
-23
lines changed

include/linux/dccp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ struct dccp_ackvec;
259259
* @dccps_sync_scheduled - flag which signals "send out-of-band message soon"
260260
* @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets
261261
* @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing)
262+
* @dccps_ccid_timer - used by the CCIDs
262263
* @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs)
263264
*/
264265
struct dccp_sock {
@@ -303,6 +304,7 @@ struct dccp_sock {
303304
__u8 dccps_sync_scheduled:1;
304305
struct tasklet_struct dccps_xmitlet;
305306
struct timer_list dccps_xmit_timer;
307+
struct timer_list dccps_ccid_timer;
306308
};
307309

308310
static inline struct dccp_sock *dccp_sk(const struct sock *sk)

net/dccp/ccids/ccid2.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,26 @@ static void dccp_tasklet_schedule(struct sock *sk)
126126

127127
static void ccid2_hc_tx_rto_expire(struct timer_list *t)
128128
{
129-
struct ccid2_hc_tx_sock *hc = from_timer(hc, t, tx_rtotimer);
130-
struct sock *sk = hc->sk;
131-
const bool sender_was_blocked = ccid2_cwnd_network_limited(hc);
129+
struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer);
130+
struct sock *sk = (struct sock *)dp;
131+
struct ccid2_hc_tx_sock *hc;
132+
bool sender_was_blocked;
132133

133134
bh_lock_sock(sk);
135+
136+
if (inet_sk_state_load(sk) == DCCP_CLOSED)
137+
goto out;
138+
139+
hc = ccid_priv(dp->dccps_hc_tx_ccid);
140+
sender_was_blocked = ccid2_cwnd_network_limited(hc);
141+
134142
if (sock_owned_by_user(sk)) {
135-
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + HZ / 5);
143+
sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + HZ / 5);
136144
goto out;
137145
}
138146

139147
ccid2_pr_debug("RTO_EXPIRE\n");
140148

141-
if (sk->sk_state == DCCP_CLOSED)
142-
goto out;
143-
144149
/* back-off timer */
145150
hc->tx_rto <<= 1;
146151
if (hc->tx_rto > DCCP_RTO_MAX)
@@ -166,7 +171,7 @@ static void ccid2_hc_tx_rto_expire(struct timer_list *t)
166171
if (sender_was_blocked)
167172
dccp_tasklet_schedule(sk);
168173
/* restart backed-off timer */
169-
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
174+
sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto);
170175
out:
171176
bh_unlock_sock(sk);
172177
sock_put(sk);
@@ -330,7 +335,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
330335
}
331336
#endif
332337

333-
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
338+
sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto);
334339

335340
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
336341
do {
@@ -700,9 +705,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
700705

701706
/* restart RTO timer if not all outstanding data has been acked */
702707
if (hc->tx_pipe == 0)
703-
sk_stop_timer(sk, &hc->tx_rtotimer);
708+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
704709
else
705-
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
710+
sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto);
706711
done:
707712
/* check if incoming Acks allow pending packets to be sent */
708713
if (sender_was_blocked && !ccid2_cwnd_network_limited(hc))
@@ -737,17 +742,18 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
737742
hc->tx_last_cong = hc->tx_lsndtime = hc->tx_cwnd_stamp = ccid2_jiffies32;
738743
hc->tx_cwnd_used = 0;
739744
hc->sk = sk;
740-
timer_setup(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, 0);
745+
timer_setup(&dp->dccps_ccid_timer, ccid2_hc_tx_rto_expire, 0);
741746
INIT_LIST_HEAD(&hc->tx_av_chunks);
742747
return 0;
743748
}
744749

745750
static void ccid2_hc_tx_exit(struct sock *sk)
746751
{
752+
struct dccp_sock *dp = dccp_sk(sk);
747753
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
748754
int i;
749755

750-
sk_stop_timer(sk, &hc->tx_rtotimer);
756+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
751757

752758
for (i = 0; i < hc->tx_seqbufc; i++)
753759
kfree(hc->tx_seqbuf[i]);

net/dccp/ccids/ccid3.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -184,17 +184,24 @@ static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hc,
184184

185185
static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t)
186186
{
187-
struct ccid3_hc_tx_sock *hc = from_timer(hc, t, tx_no_feedback_timer);
188-
struct sock *sk = hc->sk;
187+
struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer);
188+
struct ccid3_hc_tx_sock *hc;
189+
struct sock *sk = (struct sock *)dp;
189190
unsigned long t_nfb = USEC_PER_SEC / 5;
190191

191192
bh_lock_sock(sk);
193+
194+
if (inet_sk_state_load(sk) == DCCP_CLOSED)
195+
goto out;
196+
192197
if (sock_owned_by_user(sk)) {
193198
/* Try again later. */
194199
/* XXX: set some sensible MIB */
195200
goto restart_timer;
196201
}
197202

203+
hc = ccid_priv(dp->dccps_hc_tx_ccid);
204+
198205
ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk,
199206
ccid3_tx_state_name(hc->tx_state));
200207

@@ -250,8 +257,8 @@ static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t)
250257
t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
251258

252259
restart_timer:
253-
sk_reset_timer(sk, &hc->tx_no_feedback_timer,
254-
jiffies + usecs_to_jiffies(t_nfb));
260+
sk_reset_timer(sk, &dp->dccps_ccid_timer,
261+
jiffies + usecs_to_jiffies(t_nfb));
255262
out:
256263
bh_unlock_sock(sk);
257264
sock_put(sk);
@@ -280,7 +287,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
280287
return -EBADMSG;
281288

282289
if (hc->tx_state == TFRC_SSTATE_NO_SENT) {
283-
sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
290+
sk_reset_timer(sk, &dp->dccps_ccid_timer, (jiffies +
284291
usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
285292
hc->tx_last_win_count = 0;
286293
hc->tx_t_last_win_count = now;
@@ -354,6 +361,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len)
354361
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
355362
{
356363
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
364+
struct dccp_sock *dp = dccp_sk(sk);
357365
struct tfrc_tx_hist_entry *acked;
358366
ktime_t now;
359367
unsigned long t_nfb;
@@ -420,7 +428,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
420428
(unsigned int)(hc->tx_x >> 6));
421429

422430
/* unschedule no feedback timer */
423-
sk_stop_timer(sk, &hc->tx_no_feedback_timer);
431+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
424432

425433
/*
426434
* As we have calculated new ipi, delta, t_nom it is possible
@@ -445,8 +453,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
445453
"expire in %lu jiffies (%luus)\n",
446454
dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb);
447455

448-
sk_reset_timer(sk, &hc->tx_no_feedback_timer,
449-
jiffies + usecs_to_jiffies(t_nfb));
456+
sk_reset_timer(sk, &dp->dccps_ccid_timer,
457+
jiffies + usecs_to_jiffies(t_nfb));
450458
}
451459

452460
static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type,
@@ -488,21 +496,23 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type,
488496

489497
static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
490498
{
499+
struct dccp_sock *dp = dccp_sk(sk);
491500
struct ccid3_hc_tx_sock *hc = ccid_priv(ccid);
492501

493502
hc->tx_state = TFRC_SSTATE_NO_SENT;
494503
hc->tx_hist = NULL;
495504
hc->sk = sk;
496-
timer_setup(&hc->tx_no_feedback_timer,
505+
timer_setup(&dp->dccps_ccid_timer,
497506
ccid3_hc_tx_no_feedback_timer, 0);
498507
return 0;
499508
}
500509

501510
static void ccid3_hc_tx_exit(struct sock *sk)
502511
{
512+
struct dccp_sock *dp = dccp_sk(sk);
503513
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
504514

505-
sk_stop_timer(sk, &hc->tx_no_feedback_timer);
515+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
506516
tfrc_tx_hist_purge(&hc->tx_hist);
507517
}
508518

0 commit comments

Comments
 (0)