Skip to content

Commit 26ecf62

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 88e50d8 commit 26ecf62

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);
@@ -333,7 +338,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
333338
}
334339
#endif
335340

336-
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
341+
sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto);
337342

338343
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
339344
do {
@@ -705,9 +710,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
705710

706711
/* restart RTO timer if not all outstanding data has been acked */
707712
if (hc->tx_pipe == 0)
708-
sk_stop_timer(sk, &hc->tx_rtotimer);
713+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
709714
else
710-
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
715+
sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto);
711716
done:
712717
/* check if incoming Acks allow pending packets to be sent */
713718
if (sender_was_blocked && !ccid2_cwnd_network_limited(hc))
@@ -742,17 +747,18 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
742747
hc->tx_last_cong = hc->tx_lsndtime = hc->tx_cwnd_stamp = ccid2_jiffies32;
743748
hc->tx_cwnd_used = 0;
744749
hc->sk = sk;
745-
timer_setup(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, 0);
750+
timer_setup(&dp->dccps_ccid_timer, ccid2_hc_tx_rto_expire, 0);
746751
INIT_LIST_HEAD(&hc->tx_av_chunks);
747752
return 0;
748753
}
749754

750755
static void ccid2_hc_tx_exit(struct sock *sk)
751756
{
757+
struct dccp_sock *dp = dccp_sk(sk);
752758
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
753759
int i;
754760

755-
sk_stop_timer(sk, &hc->tx_rtotimer);
761+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
756762

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

net/dccp/ccids/ccid3.c

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

189189
static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t)
190190
{
191-
struct ccid3_hc_tx_sock *hc = from_timer(hc, t, tx_no_feedback_timer);
192-
struct sock *sk = hc->sk;
191+
struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer);
192+
struct ccid3_hc_tx_sock *hc;
193+
struct sock *sk = (struct sock *)dp;
193194
unsigned long t_nfb = USEC_PER_SEC / 5;
194195

195196
bh_lock_sock(sk);
197+
198+
if (inet_sk_state_load(sk) == DCCP_CLOSED)
199+
goto out;
200+
196201
if (sock_owned_by_user(sk)) {
197202
/* Try again later. */
198203
/* XXX: set some sensible MIB */
199204
goto restart_timer;
200205
}
201206

207+
hc = ccid_priv(dp->dccps_hc_tx_ccid);
208+
202209
ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk,
203210
ccid3_tx_state_name(hc->tx_state));
204211

@@ -254,8 +261,8 @@ static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t)
254261
t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
255262

256263
restart_timer:
257-
sk_reset_timer(sk, &hc->tx_no_feedback_timer,
258-
jiffies + usecs_to_jiffies(t_nfb));
264+
sk_reset_timer(sk, &dp->dccps_ccid_timer,
265+
jiffies + usecs_to_jiffies(t_nfb));
259266
out:
260267
bh_unlock_sock(sk);
261268
sock_put(sk);
@@ -285,7 +292,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
285292
return -EBADMSG;
286293

287294
if (hc->tx_state == TFRC_SSTATE_NO_SENT) {
288-
sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
295+
sk_reset_timer(sk, &dp->dccps_ccid_timer, (jiffies +
289296
usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
290297
hc->tx_last_win_count = 0;
291298
hc->tx_t_last_win_count = now;
@@ -359,6 +366,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len)
359366
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
360367
{
361368
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
369+
struct dccp_sock *dp = dccp_sk(sk);
362370
struct tfrc_tx_hist_entry *acked;
363371
ktime_t now;
364372
unsigned long t_nfb;
@@ -425,7 +433,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
425433
(unsigned int)(hc->tx_x >> 6));
426434

427435
/* unschedule no feedback timer */
428-
sk_stop_timer(sk, &hc->tx_no_feedback_timer);
436+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
429437

430438
/*
431439
* As we have calculated new ipi, delta, t_nom it is possible
@@ -450,8 +458,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
450458
"expire in %lu jiffies (%luus)\n",
451459
dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb);
452460

453-
sk_reset_timer(sk, &hc->tx_no_feedback_timer,
454-
jiffies + usecs_to_jiffies(t_nfb));
461+
sk_reset_timer(sk, &dp->dccps_ccid_timer,
462+
jiffies + usecs_to_jiffies(t_nfb));
455463
}
456464

457465
static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type,
@@ -493,21 +501,23 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type,
493501

494502
static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
495503
{
504+
struct dccp_sock *dp = dccp_sk(sk);
496505
struct ccid3_hc_tx_sock *hc = ccid_priv(ccid);
497506

498507
hc->tx_state = TFRC_SSTATE_NO_SENT;
499508
hc->tx_hist = NULL;
500509
hc->sk = sk;
501-
timer_setup(&hc->tx_no_feedback_timer,
510+
timer_setup(&dp->dccps_ccid_timer,
502511
ccid3_hc_tx_no_feedback_timer, 0);
503512
return 0;
504513
}
505514

506515
static void ccid3_hc_tx_exit(struct sock *sk)
507516
{
517+
struct dccp_sock *dp = dccp_sk(sk);
508518
struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
509519

510-
sk_stop_timer(sk, &hc->tx_no_feedback_timer);
520+
sk_stop_timer(sk, &dp->dccps_ccid_timer);
511521
tfrc_tx_hist_purge(&hc->tx_hist);
512522
}
513523

0 commit comments

Comments
 (0)