Skip to content

Commit 2d28964

Browse files
dcarattiintel-lab-lkp
authored andcommitted
net/sched: act_gate: fix NULL dereference in tcf_gate_init()
it is possible to see a KASAN use-after-free, immediately followed by a NULL dereference crash, with the following command: # tc action add action gate index 3 cycle-time 100000000ns \ > cycle-time-ext 100000000ns clockid CLOCK_TAI BUG: KASAN: use-after-free in tcf_action_init_1+0x8eb/0x960 Write of size 1 at addr ffff88810a5908bc by task tc/883 CPU: 0 PID: 883 Comm: tc Not tainted 5.7.0+ torvalds#188 Hardware name: Red Hat KVM, BIOS 1.11.1-4.module+el8.1.0+4066+0f1aadab 04/01/2014 Call Trace: dump_stack+0x75/0xa0 print_address_description.constprop.6+0x1a/0x220 kasan_report.cold.9+0x37/0x7c tcf_action_init_1+0x8eb/0x960 tcf_action_init+0x157/0x2a0 tcf_action_add+0xd9/0x2f0 tc_ctl_action+0x2a3/0x39d rtnetlink_rcv_msg+0x5f3/0x920 netlink_rcv_skb+0x120/0x380 netlink_unicast+0x439/0x630 netlink_sendmsg+0x714/0xbf0 sock_sendmsg+0xe2/0x110 ____sys_sendmsg+0x5b4/0x890 ___sys_sendmsg+0xe9/0x160 __sys_sendmsg+0xd3/0x170 do_syscall_64+0x9a/0x370 entry_SYSCALL_64_after_hwframe+0x44/0xa9 [...] KASAN: null-ptr-deref in range [0x0000000000000070-0x0000000000000077] CPU: 0 PID: 883 Comm: tc Tainted: G B 5.7.0+ torvalds#188 Hardware name: Red Hat KVM, BIOS 1.11.1-4.module+el8.1.0+4066+0f1aadab 04/01/2014 RIP: 0010:tcf_action_fill_size+0xa3/0xf0 [....] RSP: 0018:ffff88813a48f250 EFLAGS: 00010212 RAX: dffffc0000000000 RBX: 0000000000000094 RCX: ffffffffa47c3eb6 RDX: 000000000000000e RSI: 0000000000000008 RDI: 0000000000000070 RBP: ffff88810a590800 R08: 0000000000000004 R09: ffffed1027491e03 R10: 0000000000000003 R11: ffffed1027491e03 R12: 0000000000000000 R13: 0000000000000000 R14: dffffc0000000000 R15: ffff88810a590800 FS: 00007f62cae8ce40(0000) GS:ffff888147c00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f62c9d20a10 CR3: 000000013a52a000 CR4: 0000000000340ef0 Call Trace: tcf_action_init+0x172/0x2a0 tcf_action_add+0xd9/0x2f0 tc_ctl_action+0x2a3/0x39d rtnetlink_rcv_msg+0x5f3/0x920 netlink_rcv_skb+0x120/0x380 netlink_unicast+0x439/0x630 netlink_sendmsg+0x714/0xbf0 sock_sendmsg+0xe2/0x110 ____sys_sendmsg+0x5b4/0x890 ___sys_sendmsg+0xe9/0x160 __sys_sendmsg+0xd3/0x170 do_syscall_64+0x9a/0x370 entry_SYSCALL_64_after_hwframe+0x44/0xa9 this is caused by the test on 'cycletime_ext', that is still unassigned when the action is newly created. This makes the action .init() return 0 without calling tcf_idr_insert(), hence the UAF + crash. rework the logic that prevents zero values of cycle-time, as follows: 1) 'tcfg_cycletime_ext' seems to be unused in the action software path, and it was already possible by other means to obtain non-zero cycletime and zero cycletime-ext. So, removing that test should not cause any damage. 2) while at it, we must prevent overwriting configuration data with wrong ones: use a temporary variable for 'tcfg_cycletime', and validate it preserving the original semantic (that allowed computing the cycle time as the sum of all intervals, when not specified by TCA_GATE_CYCLE_TIME). 3) remove the test on 'tcfg_cycletime', no more useful, and avoid returning -EFAULT, which did not seem an appropriate return value for a wrong netlink attribute. v2: remove useless 'return;' at the end of void gate_get_start_time() Fixes: a51c328 ("net: qos: introduce a gate control flow action") CC: Ivan Vecera <[email protected]> Signed-off-by: Davide Caratti <[email protected]>
1 parent 96144c5 commit 2d28964

File tree

1 file changed

+13
-23
lines changed

1 file changed

+13
-23
lines changed

net/sched/act_gate.c

+13-23
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static ktime_t gate_get_time(struct tcf_gate *gact)
3232
return KTIME_MAX;
3333
}
3434

35-
static int gate_get_start_time(struct tcf_gate *gact, ktime_t *start)
35+
static void gate_get_start_time(struct tcf_gate *gact, ktime_t *start)
3636
{
3737
struct tcf_gate_params *param = &gact->param;
3838
ktime_t now, base, cycle;
@@ -43,18 +43,13 @@ static int gate_get_start_time(struct tcf_gate *gact, ktime_t *start)
4343

4444
if (ktime_after(base, now)) {
4545
*start = base;
46-
return 0;
46+
return;
4747
}
4848

4949
cycle = param->tcfg_cycletime;
5050

51-
/* cycle time should not be zero */
52-
if (!cycle)
53-
return -EFAULT;
54-
5551
n = div64_u64(ktime_sub_ns(now, base), cycle);
5652
*start = ktime_add_ns(base, (n + 1) * cycle);
57-
return 0;
5853
}
5954

6055
static void gate_start_timer(struct tcf_gate *gact, ktime_t start)
@@ -287,12 +282,12 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
287282
enum tk_offsets tk_offset = TK_OFFS_TAI;
288283
struct nlattr *tb[TCA_GATE_MAX + 1];
289284
struct tcf_chain *goto_ch = NULL;
285+
u64 cycletime, basetime = 0;
290286
struct tcf_gate_params *p;
291287
s32 clockid = CLOCK_TAI;
292288
struct tcf_gate *gact;
293289
struct tc_gate *parm;
294290
int ret = 0, err;
295-
u64 basetime = 0;
296291
u32 gflags = 0;
297292
s32 prio = -1;
298293
ktime_t start;
@@ -375,26 +370,28 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
375370
spin_lock_bh(&gact->tcf_lock);
376371
p = &gact->param;
377372

378-
if (tb[TCA_GATE_CYCLE_TIME]) {
379-
p->tcfg_cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
380-
if (!p->tcfg_cycletime_ext)
381-
goto chain_put;
382-
}
373+
if (tb[TCA_GATE_CYCLE_TIME])
374+
cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
383375

384376
if (tb[TCA_GATE_ENTRY_LIST]) {
385377
err = parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack);
386378
if (err < 0)
387379
goto chain_put;
388380
}
389381

390-
if (!p->tcfg_cycletime) {
382+
if (!cycletime) {
391383
struct tcfg_gate_entry *entry;
392384
ktime_t cycle = 0;
393385

394386
list_for_each_entry(entry, &p->entries, list)
395387
cycle = ktime_add_ns(cycle, entry->interval);
396-
p->tcfg_cycletime = cycle;
388+
cycletime = cycle;
389+
if (!cycletime) {
390+
err = -EINVAL;
391+
goto chain_put;
392+
}
397393
}
394+
p->tcfg_cycletime = cycletime;
398395

399396
if (tb[TCA_GATE_CYCLE_TIME_EXT])
400397
p->tcfg_cycletime_ext =
@@ -408,14 +405,7 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
408405
gact->tk_offset = tk_offset;
409406
hrtimer_init(&gact->hitimer, clockid, HRTIMER_MODE_ABS_SOFT);
410407
gact->hitimer.function = gate_timer_func;
411-
412-
err = gate_get_start_time(gact, &start);
413-
if (err < 0) {
414-
NL_SET_ERR_MSG(extack,
415-
"Internal error: failed get start time");
416-
release_entry_list(&p->entries);
417-
goto chain_put;
418-
}
408+
gate_get_start_time(gact, &start);
419409

420410
gact->current_close_time = start;
421411
gact->current_gate_status = GATE_ACT_GATE_OPEN | GATE_ACT_PENDING;

0 commit comments

Comments
 (0)