[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAM0EoMmVchdXPrmnFObON4kf3FOz2SbjFptRmqTev3GtkxWGvQ@mail.gmail.com>
Date: Thu, 29 Jan 2026 08:40:45 -0500
From: Jamal Hadi Salim <jhs@...atatu.com>
To: GangMin Kim <km.kim1503@...il.com>
Cc: davem@...emloft.net, Eric Dumazet <edumazet@...gle.com>, jiri@...nulli.us,
kuba@...nel.org, netdev@...r.kernel.org, pabeni@...hat.com,
stephen@...workplumber.org, xiyou.wangcong@...il.com, horms@...nel.org,
linux-kernel@...r.kernel.org, syzkaller@...glegroups.com
Subject: Re: [BUG] divide error in tabledist
On Wed, Jan 28, 2026 at 11:20 PM GangMin Kim <km.kim1503@...il.com> wrote:
>
> Dear Linux kernel developers and maintainers,
> Using a modified version of syzkaller, I identified a new bug and
> refined the PoC, and the bug-related information is attached
> below.Please let me know if you need any further information.
>
Thanks for the report. I will take a closer look later today.
cheers,
jamal
> Summary
> In netem, when jitter is set to 0x80000000, a divide error occurs when
> tabledist is processed during the subsequent netem_enqueue operation.
>
> Keywords
> - net/sched
>
> Kernel Info
> Version: (Output of /proc/version)
> - Linux version 6.19.0-rc7
> Commit: (Git hash if applicable)
> - 63804fed149a6750ffd28610c5c1c98cce6bd377
>
> Description(Root Cause)
> ```
> static int netem_change(struct Qdisc *sch, struct nlattr *opt,
> struct netlink_ext_ack *extack)
> {
> struct netem_sched_data *q = qdisc_priv(sch);
> struct nlattr *tb[TCA_NETEM_MAX + 1];
> struct disttable *delay_dist = NULL;
> struct disttable *slot_dist = NULL;
> struct tc_netem_qopt *qopt;
> struct clgstate old_clg;
> int old_loss_model = CLG_RANDOM;
> int ret;
>
> qopt = nla_data(opt);
> ...
> sch->limit = qopt->limit;
>
> q->latency = PSCHED_TICKS2NS(qopt->latency);
> q->jitter = PSCHED_TICKS2NS(qopt->jitter); // [1]
> q->limit = qopt->limit;
> q->gap = qopt->gap;
> q->counter = 0;
> q->loss = qopt->loss;
>
> ret = check_netem_in_tree(sch, qopt->duplicate, extack); // [2]
> if (ret)
> goto unlock;
> ...
> /* capping jitter to the range acceptable by tabledist() */
> q->jitter = min_t(s64, abs(q->jitter), INT_MAX); // [3]
> ...
> unlock:
> sch_tree_unlock(sch);
>
> table_free:
> dist_free(delay_dist);
> dist_free(slot_dist);
> return ret;
> }
> ```
> When qopt->jitter is 0x6e000000, at [1] q->jitter is set to
> 0x1b80000000. If netem is already configured and a change operation is
> attempted but fails at [2], the q values are modified but the process
> at [3] is not executed. Therefore, q->jitter can be set to a value
> exceeding INT_MAX.
>
> ```
> static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
> struct sk_buff **to_free)
> {
> struct netem_sched_data *q = qdisc_priv(sch);
> /* We don't fill cb now as skb_unshare() may invalidate it */
> struct netem_skb_cb *cb;
> struct sk_buff *skb2 = NULL;
> struct sk_buff *segs = NULL;
> unsigned int prev_len = qdisc_pkt_len(skb);
> int count = 1;
> ...
> if (q->gap == 0 || /* not doing reordering */
> q->counter < q->gap - 1 || /* inside last reordering gap */
> q->reorder < get_crandom(&q->reorder_cor, &q->prng)) {
> u64 now;
> s64 delay;
>
> delay = tabledist(q->latency, q->jitter, // [4]
> &q->delay_cor, &q->prng, q->delay_dist);
>
> ...
> }
> ...
> return NET_XMIT_SUCCESS;
> }
>
> static s64 tabledist(s64 mu, s32 sigma,
> struct crndstate *state,
> struct prng *prng,
> const struct disttable *dist)
> {
> s64 x;
> long t;
> u32 rnd;
>
> if (sigma == 0)
> return mu;
>
> rnd = get_crandom(state, prng);
>
> /* default uniform distribution */
> if (dist == NULL)
> return ((rnd % (2 * (u32)sigma)) + mu) - sigma; // [5]
> ...
> return x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
> }
> ```
> Subsequently, in netem_enqueue(), the previously set value is passed
> at [4], and in tabledist(), sigma is set to 0x80000000. This causes
> the calculation at [5] to become 2 * 0x80000000, which overflows to 0,
> resulting in a divide-by-zero error.
>
> Kasan Report
> Oops: divide error: 0000 [#1] SMP KASAN NOPTI
> CPU: 0 UID: 0 PID: 332 Comm: test Not tainted 6.19.0-rc7 #8 PREEMPT(full)
> Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS
> 1.16.3-debian-1.16.3-2 04/01/2014
> RIP: 0010:tabledist.part.0+0x21e/0x290 net/sched/sch_netem.c:345
> Code: 4c 01 f0 48 c1 e8 20 41 89 45 00 41 89 c6 e8 49 d1 9a fd 48 85
> db 0f 85 78 fe ff ff e8 3b d1 9a fd 8d 4c 2d 00 44 89 f0 31 d2 <f7> f1
> 49 29 ec 49 01 d4 e9 2a ff ff ff e8 20 d1 9a fd 48 81 eb 00
> RSP: 0018:ffff88810f61f1f8 EFLAGS: 00010246
> RAX: 00000000aecf3ad7 RBX: 0000000000000000 RCX: 0000000000000000
> RDX: 0000000000000000 RSI: 0000000080000000 RDI: ffff88810900da7c
> RBP: ffffffff80000000 R08: 0000000000000000 R09: ffffed10233895cc
> R10: ffff888119c4ae67 R11: 0000000000000000 R12: 0000000001000300
> R13: ffff88810900da3c R14: 00000000aecf3ad7 R15: ffff88810900da40
> FS: 00007f2531e11540(0000) GS:ffff88834ad89000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007f2531cfe1c0 CR3: 00000001215fe000 CR4: 0000000000750ef0
> PKRU: 55555554
> Call Trace:
> <TASK>
> tabledist net/sched/sch_netem.c:559 [inline]
> netem_enqueue+0x4f4/0x3180 net/sched/sch_netem.c:559
> qdisc_enqueue include/net/sch_generic.h:887 [inline]
> qfq_enqueue+0x46f/0x13c0 net/sched/sch_qfq.c:1256
> dev_qdisc_enqueue+0x45/0x160 net/core/dev.c:4147
> __dev_xmit_skb net/core/dev.c:4262 [inline]
> __dev_queue_xmit+0x1eea/0x3060 net/core/dev.c:4798
> dev_queue_xmit include/linux/netdevice.h:3381 [inline]
> neigh_hh_output include/net/neighbour.h:540 [inline]
> neigh_output include/net/neighbour.h:554 [inline]
> ip_finish_output2+0xdd2/0x1710 net/ipv4/ip_output.c:237
> __ip_finish_output.part.0+0x182/0x2f0 net/ipv4/ip_output.c:315
> __ip_finish_output net/ipv4/ip_output.c:444 [inline]
> ip_finish_output net/ipv4/ip_output.c:325 [inline]
> NF_HOOK_COND include/linux/netfilter.h:307 [inline]
> ip_output+0x288/0x510 net/ipv4/ip_output.c:438
> dst_output include/net/dst.h:464 [inline]
> ip_local_out net/ipv4/ip_output.c:131 [inline]
> ip_send_skb+0x160/0x1b0 net/ipv4/ip_output.c:1508
> udp_send_skb+0x6d6/0x1000 net/ipv4/udp.c:1195
> udp_sendmsg+0x1463/0x1eb0 net/ipv4/udp.c:1484
> inet_sendmsg+0xfa/0x140 net/ipv4/af_inet.c:859
> sock_sendmsg_nosec net/socket.c:727 [inline]
> __sock_sendmsg net/socket.c:742 [inline]
> sock_write_iter+0x493/0x5b0 net/socket.c:1195
> new_sync_write fs/read_write.c:593 [inline]
> vfs_write+0x657/0xd30 fs/read_write.c:686
> ksys_write+0x1b2/0x200 fs/read_write.c:738
> do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> do_syscall_64+0xa4/0x320 arch/x86/entry/syscall_64.c:94
> entry_SYSCALL_64_after_hwframe+0x77/0x7f
> RIP: 0033:0x7f2531d27513
> Code: 8b 15 81 29 0e 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f
> 1f 00 64 8b 04 25 18 00 00 00 85 c0 75 14 b8 01 00 00 00 0f 05 <48> 3d
> 00 f0 ff ff 77 55 c3 0f 1f 40 00 48 83 ec 28 48 89 54 24 18
> RSP: 002b:00007ffe09e5d858 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f2531d27513
> RDX: 0000000000000040 RSI: 00007ffe09e5d890 RDI: 0000000000000004
> RBP: 00007ffe09e5d8f0 R08: 0000000000000004 R09: 0000000000020000
> R10: 00007ffe09e5d87c R11: 0000000000000246 R12: 000055c28686a100
> R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
> </TASK>
> Modules linked in:
> ---[ end trace 0000000000000000 ]---
> RIP: 0010:tabledist.part.0+0x21e/0x290 net/sched/sch_netem.c:345
> Code: 4c 01 f0 48 c1 e8 20 41 89 45 00 41 89 c6 e8 49 d1 9a fd 48 85
> db 0f 85 78 fe ff ff e8 3b d1 9a fd 8d 4c 2d 00 44 89 f0 31 d2 <f7> f1
> 49 29 ec 49 01 d4 e9 2a ff ff ff e8 20 d1 9a fd 48 81 eb 00
> RSP: 0018:ffff88810f61f1f8 EFLAGS: 00010246
> RAX: 00000000aecf3ad7 RBX: 0000000000000000 RCX: 0000000000000000
> RDX: 0000000000000000 RSI: 0000000080000000 RDI: ffff88810900da7c
> RBP: ffffffff80000000 R08: 0000000000000000 R09: ffffed10233895cc
> R10: ffff888119c4ae67 R11: 0000000000000000 R12: 0000000001000300
> R13: ffff88810900da3c R14: 00000000aecf3ad7 R15: ffff88810900da40
> FS: 00007f2531e11540(0000) GS:ffff88834ad89000(0000) knlGS:0000000000000000
> CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007f2531cfe1c0 CR3: 00000001215fe000 CR4: 0000000000750ef0
> PKRU: 55555554
> ----------------
> Code disassembly (best guess):
> 0: 4c 01 f0 add %r14,%rax
> 3: 48 c1 e8 20 shr $0x20,%rax
> 7: 41 89 45 00 mov %eax,0x0(%r13)
> b: 41 89 c6 mov %eax,%r14d
> e: e8 49 d1 9a fd call 0xfd9ad15c
> 13: 48 85 db test %rbx,%rbx
> 16: 0f 85 78 fe ff ff jne 0xfffffe94
> 1c: e8 3b d1 9a fd call 0xfd9ad15c
> 21: 8d 4c 2d 00 lea 0x0(%rbp,%rbp,1),%ecx
> 25: 44 89 f0 mov %r14d,%eax
> 28: 31 d2 xor %edx,%edx
> * 2a: f7 f1 div %ecx <-- trapping instruction
> 2c: 49 29 ec sub %rbp,%r12
> 2f: 49 01 d4 add %rdx,%r12
> 32: e9 2a ff ff ff jmp 0xffffff61
> 37: e8 20 d1 9a fd call 0xfd9ad15c
> 3c: 48 rex.W
> 3d: 81 .byte 0x81
> 3e: eb 00 jmp 0x40
Powered by blists - more mailing lists