Re: net/irda: use-after-free in ircomm_param_request

2016-01-26 Thread Cong Wang
On Mon, Jan 25, 2016 at 7:59 AM, Dmitry Vyukov  wrote:
> It seems that skb can be freed after skb_put() and spinlock unlock,
> but ircomm_param_request reads skb->len afterwards:
>
> int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
> {
> ...
> skb_put(skb, count);
> spin_unlock_irqrestore(&self->spinlock, flags);
> pr_debug("%s(), skb->len=%d\n", __func__ , skb->len);
>

This looks correct to me. We can either get rid of that debugging
print or move it under spinlock.


net/irda: use-after-free in ircomm_param_request

2016-01-25 Thread Dmitry Vyukov
Hello,

I've hit the following use-after-free report while running syzkaller fuzzer:

==
BUG: KASAN: use-after-free in ircomm_param_request+0x514/0x570 at addr
880035732c78
Read of size 4 by task syz-executor/10736
=
BUG skbuff_head_cache (Not tainted): kasan: bad access detected
-

INFO: Allocated in __alloc_skb+0xba/0x5f0 age=4 cpu=1 pid=10738
[<  none  >] kmem_cache_alloc_node+0x93/0x2f0 mm/slub.c:2632
[<  none  >] __alloc_skb+0xba/0x5f0 net/core/skbuff.c:216
[< inline >] alloc_skb include/linux/skbuff.h:894
[<  none  >] ircomm_param_request+0x34b/0x570
net/irda/ircomm/ircomm_param.c:115
[<  none  >] ircomm_port_raise_dtr_rts+0x6a/0xc0
net/irda/ircomm/ircomm_tty.c:122
[<  none  >] tty_port_raise_dtr_rts+0x6a/0x90 drivers/tty/tty_port.c:313
[< inline >] ircomm_tty_block_til_ready net/irda/ircomm/ircomm_tty.c:291
[<  none  >] ircomm_tty_open+0xad7/0x12f0
net/irda/ircomm/ircomm_tty.c:462
[<  none  >] tty_open+0x34d/0xf80 drivers/tty/tty_io.c:2099
[<  none  >] chrdev_open+0x22a/0x4c0 fs/char_dev.c:388
[<  none  >] do_dentry_open+0x6a2/0xcb0 fs/open.c:736
[<  none  >] vfs_open+0x17b/0x1f0 fs/open.c:853
[< inline >] do_last fs/namei.c:3254
[<  none  >] path_openat+0xde9/0x5e30 fs/namei.c:3386
[<  none  >] do_filp_open+0x18e/0x250 fs/namei.c:3421
[<  none  >] do_sys_open+0x1fc/0x420 fs/open.c:1022
[< inline >] SYSC_open fs/open.c:1040
[<  none  >] SyS_open+0x2d/0x40 fs/open.c:1035

INFO: Freed in kfree_skbmem+0xe6/0x100 age=10 cpu=1 pid=1362
[<  none  >] kmem_cache_free+0x2e4/0x360 mm/slub.c:2844
[<  none  >] kfree_skbmem+0xe6/0x100 net/core/skbuff.c:612
[< inline >] __kfree_skb net/core/skbuff.c:674
[<  none  >] consume_skb+0xe4/0x2c0 net/core/skbuff.c:746
[<  none  >] ircomm_tty_do_softint+0x131/0x280
net/irda/ircomm/ircomm_tty.c:552
[<  none  >] process_one_work+0x796/0x1440 kernel/workqueue.c:2037
[<  none  >] worker_thread+0xdb/0xfc0 kernel/workqueue.c:2171
[<  none  >] kthread+0x23f/0x2d0 drivers/block/aoe/aoecmd.c:1303
[<  none  >] ret_from_fork+0x3f/0x70 arch/x86/entry/entry_64.S:468

INFO: Slab 0xead5cc00 objects=23 used=0 fp=0x880035732c00
flags=0x1fffc004080
INFO: Object 0x880035732c00 @offset=11264 fp=0x880035731340
CPU: 0 PID: 10736 Comm: syz-executor Tainted: GB   4.5.0-rc1+ #280
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
  88b174c8 8299a06d 88003de85200
 880035732c00 88003573 88b174f8 81752854
 88003de85200 ead5cc00 880035732c00 0001

Call Trace:
 [] __asan_report_load4_noabort+0x3e/0x40
mm/kasan/report.c:294
 [] ircomm_param_request+0x514/0x570
net/irda/ircomm/ircomm_param.c:140
 [] ircomm_port_raise_dtr_rts+0x6a/0xc0
net/irda/ircomm/ircomm_tty.c:122
 [] tty_port_raise_dtr_rts+0x6a/0x90
drivers/tty/tty_port.c:313
 [< inline >] ircomm_tty_block_til_ready
net/irda/ircomm/ircomm_tty.c:291
 [] ircomm_tty_open+0xad7/0x12f0
net/irda/ircomm/ircomm_tty.c:462
 [] tty_open+0x34d/0xf80 drivers/tty/tty_io.c:2099
 [] chrdev_open+0x22a/0x4c0 fs/char_dev.c:388
 [] do_dentry_open+0x6a2/0xcb0 fs/open.c:736
 [] vfs_open+0x17b/0x1f0 fs/open.c:853
 [< inline >] do_last fs/namei.c:3254
 [] path_openat+0xde9/0x5e30 fs/namei.c:3386
 [] do_filp_open+0x18e/0x250 fs/namei.c:3421
 [] do_sys_open+0x1fc/0x420 fs/open.c:1022
 [< inline >] SYSC_open fs/open.c:1040
 [] SyS_open+0x2d/0x40 fs/open.c:1035
 [] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
==

It seems that skb can be freed after skb_put() and spinlock unlock,
but ircomm_param_request reads skb->len afterwards:

int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
{
...
skb_put(skb, count);
spin_unlock_irqrestore(&self->spinlock, flags);
pr_debug("%s(), skb->len=%d\n", __func__ , skb->len);

On commit 92e963f50fc74041b5e9e744c330dca48e04f08d (Jan 24).