2015-11-25 15:37:52

by Dmitry Vyukov

[permalink] [raw]
Subject: use-after-free in irtty_open

Hello,

The following program causes a use-after-free in irtty_open:

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int main()
{
int fd = open("/dev/ptmx", O_RDONLY|O_NOCTTY);
int val = 9;
ioctl(fd, TIOCSETD, &val);
val = 11;
ioctl(fd, TIOCSETD, &val);
return 0;
}


==================================================================
BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068
Read of size 4 by task a.out/13960
=============================================================================
BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected
-----------------------------------------------------------------------------

INFO: Allocated in r3964_open+0x4a/0x630 age=4 cpu=1 pid=13960
[< inline >] kmalloc include/linux/slab.h:458
[< none >] r3964_open+0x4a/0x630 drivers/tty/n_r3964.c:950
[< none >] tty_ldisc_open.isra.2+0x60/0xa0 drivers/tty/tty_ldisc.c:447
[< none >] tty_set_ldisc+0x1a0/0x940 drivers/tty/tty_ldisc.c:567
[< inline >] tiocsetd drivers/tty/tty_io.c:2650
[< none >] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883
[< inline >] vfs_ioctl fs/ioctl.c:43
[< none >] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607
[< inline >] SYSC_ioctl fs/ioctl.c:622
[< none >] SyS_ioctl+0x74/0x80 fs/ioctl.c:613
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185

INFO: Freed in r3964_close+0x20f/0x290 age=9 cpu=1 pid=13960
[< none >] kfree+0x1a2/0x1c0 mm/slub.c:3632
[< none >] r3964_close+0x20f/0x290 drivers/tty/n_r3964.c:1052
[< none >] tty_ldisc_close.isra.1+0x85/0xc0
drivers/tty/tty_ldisc.c:471
[< none >] tty_set_ldisc+0x121/0x940 drivers/tty/tty_ldisc.c:561
[< inline >] tiocsetd drivers/tty/tty_io.c:2650
[< none >] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883
[< inline >] vfs_ioctl fs/ioctl.c:43
[< none >] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607
[< inline >] SYSC_ioctl fs/ioctl.c:622
[< none >] SyS_ioctl+0x74/0x80 fs/ioctl.c:613
[< none >] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185

INFO: Slab 0xffffea0000cc7700 objects=19 used=0 fp=0xffff8800331dd068
flags=0x1fffc0000004080
INFO: Object 0xffff8800331dd068 @offset=4200 fp=0xffff8800331dfb10
CPU: 1 PID: 13960 Comm: a.out Tainted: G B 4.4.0-rc2+ #51
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
ffff8800331dc000 ffff88003eba7980 ffffffff826c8be0 ffff88003e804c80
ffff88003eba79b0 ffffffff815f1604 ffff88003e804c80 ffffea0000cc7700
ffff8800331dd068 ffff8800336a9808 ffff88003eba79d8 ffffffff815f775f

Call Trace:
[<ffffffff815fa2ae>] __asan_report_load4_noabort+0x3e/0x40
mm/kasan/report.c:279
[<ffffffff836938a2>] irtty_open+0x422/0x550 drivers/net/irda/irtty-sir.c:436
[<ffffffff829f1b80>] tty_ldisc_open.isra.2+0x60/0xa0
drivers/tty/tty_ldisc.c:447
[<ffffffff829f21c0>] tty_set_ldisc+0x1a0/0x940 drivers/tty/tty_ldisc.c:567
[< inline >] tiocsetd drivers/tty/tty_io.c:2650
[<ffffffff829da49e>] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883
[< inline >] vfs_ioctl fs/ioctl.c:43
[<ffffffff816708ac>] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607
[< inline >] SYSC_ioctl fs/ioctl.c:622
[<ffffffff81671204>] SyS_ioctl+0x74/0x80 fs/ioctl.c:613
[<ffffffff852a7876>] entry_SYSCALL_64_fastpath+0x16/0x7a
arch/x86/entry/entry_64.S:185
==================================================================

I am on commit 6ffeba9607343f15303a399bc402a538800d89d9 (Nov 24).

Thank you


2015-11-26 14:12:10

by Peter Hurley

[permalink] [raw]
Subject: Re: use-after-free in irtty_open

[ + David Miller ]

On 11/25/2015 10:37 AM, Dmitry Vyukov wrote:
> Hello,
>
> The following program causes a use-after-free in irtty_open:
>
> // autogenerated by syzkaller (http://github.com/google/syzkaller)
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
> #include <sys/ioctl.h>
>
> int main()
> {
> int fd = open("/dev/ptmx", O_RDONLY|O_NOCTTY);
> int val = 9;
> ioctl(fd, TIOCSETD, &val);
> val = 11;
> ioctl(fd, TIOCSETD, &val);
> return 0;
> }
>
>
> ==================================================================
> BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068
> Read of size 4 by task a.out/13960
> =============================================================================
> BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected
> -----------------------------------------------------------------------------

Thanks for the report, Dmitry.
Would you please test the patch below?

As I wrote to Sasha a couple of days ago, the ldisc api should really prevent
these kinds of errors. I have a patch for the ldisc core that eliminates
these errors (reduces them to dead code).

Seems like this was a common pattern at some point; probably need to challenge
my coccinelle-fu to remove this pattern tree-wide.

Regards,
Peter Hurley

--- >% ---
Subject: [PATCH] net: irda: Fix use-after-free in irtty_open()

The N_IRDA line discipline may access the previous line discipline's closed
and already-fre private data on open [1].

The tty->disc_data field _never_ refers to valid data on entry to the
line discipline's open() method. Rather, the ldisc is expected to
initialize that field for its own use for the lifetime of the instance
(ie. from open() to close() only).

[1] Report from Dmitry Vyukov <[email protected]>
==================================================================
BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068
Read of size 4 by task a.out/13960
=============================================================================
BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected
-----------------------------------------------------------------------------
...
Call Trace:
[<ffffffff815fa2ae>] __asan_report_load4_noabort+0x3e/0x40 mm/kasan/report.c:279
[<ffffffff836938a2>] irtty_open+0x422/0x550 drivers/net/irda/irtty-sir.c:436
[<ffffffff829f1b80>] tty_ldisc_open.isra.2+0x60/0xa0 drivers/tty/tty_ldisc.c:447
[<ffffffff829f21c0>] tty_set_ldisc+0x1a0/0x940 drivers/tty/tty_ldisc.c:567
[< inline >] tiocsetd drivers/tty/tty_io.c:2650
[<ffffffff829da49e>] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883
[< inline >] vfs_ioctl fs/ioctl.c:43
[<ffffffff816708ac>] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607
[< inline >] SYSC_ioctl fs/ioctl.c:622
[<ffffffff81671204>] SyS_ioctl+0x74/0x80 fs/ioctl.c:613
[<ffffffff852a7876>] entry_SYSCALL_64_fastpath+0x16/0x7a

Reported-by: Dmitry Vyukov <[email protected]>
Signed-off-by: Peter Hurley <[email protected]>
---
drivers/net/irda/irtty-sir.c | 10 ----------
1 file changed, 10 deletions(-)

diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 696852e..7a3f990 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty)

/* Module stuff handled via irda_ldisc.owner - Jean II */

- /* First make sure we're not already connected. */
- if (tty->disc_data != NULL) {
- priv = tty->disc_data;
- if (priv && priv->magic == IRTTY_MAGIC) {
- ret = -EEXIST;
- goto out;
- }
- tty->disc_data = NULL; /* ### */
- }
-
/* stop the underlying driver */
irtty_stop_receiver(tty, TRUE);
if (tty->ops->stop)
--
2.6.3

2015-11-26 15:26:19

by Dmitry Vyukov

[permalink] [raw]
Subject: Re: use-after-free in irtty_open

On Thu, Nov 26, 2015 at 3:12 PM, Peter Hurley <[email protected]> wrote:
> [ + David Miller ]
>
> On 11/25/2015 10:37 AM, Dmitry Vyukov wrote:
>> Hello,
>>
>> The following program causes a use-after-free in irtty_open:
>>
>> // autogenerated by syzkaller (http://github.com/google/syzkaller)
>> #include <sys/types.h>
>> #include <sys/stat.h>
>> #include <fcntl.h>
>> #include <sys/ioctl.h>
>>
>> int main()
>> {
>> int fd = open("/dev/ptmx", O_RDONLY|O_NOCTTY);
>> int val = 9;
>> ioctl(fd, TIOCSETD, &val);
>> val = 11;
>> ioctl(fd, TIOCSETD, &val);
>> return 0;
>> }
>>
>>
>> ==================================================================
>> BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068
>> Read of size 4 by task a.out/13960
>> =============================================================================
>> BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected
>> -----------------------------------------------------------------------------
>
> Thanks for the report, Dmitry.
> Would you please test the patch below?

The patch fixes the bug for me.

Tested-by: Dmitry Vyukov <[email protected]>

> As I wrote to Sasha a couple of days ago, the ldisc api should really prevent
> these kinds of errors. I have a patch for the ldisc core that eliminates
> these errors (reduces them to dead code).
>
> Seems like this was a common pattern at some point; probably need to challenge
> my coccinelle-fu to remove this pattern tree-wide.
>
> Regards,
> Peter Hurley
>
> --- >% ---
> Subject: [PATCH] net: irda: Fix use-after-free in irtty_open()
>
> The N_IRDA line discipline may access the previous line discipline's closed
> and already-fre private data on open [1].
>
> The tty->disc_data field _never_ refers to valid data on entry to the
> line discipline's open() method. Rather, the ldisc is expected to
> initialize that field for its own use for the lifetime of the instance
> (ie. from open() to close() only).
>
> [1] Report from Dmitry Vyukov <[email protected]>
> ==================================================================
> BUG: KASAN: use-after-free in irtty_open+0x422/0x550 at addr ffff8800331dd068
> Read of size 4 by task a.out/13960
> =============================================================================
> BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected
> -----------------------------------------------------------------------------
> ...
> Call Trace:
> [<ffffffff815fa2ae>] __asan_report_load4_noabort+0x3e/0x40 mm/kasan/report.c:279
> [<ffffffff836938a2>] irtty_open+0x422/0x550 drivers/net/irda/irtty-sir.c:436
> [<ffffffff829f1b80>] tty_ldisc_open.isra.2+0x60/0xa0 drivers/tty/tty_ldisc.c:447
> [<ffffffff829f21c0>] tty_set_ldisc+0x1a0/0x940 drivers/tty/tty_ldisc.c:567
> [< inline >] tiocsetd drivers/tty/tty_io.c:2650
> [<ffffffff829da49e>] tty_ioctl+0xace/0x1fd0 drivers/tty/tty_io.c:2883
> [< inline >] vfs_ioctl fs/ioctl.c:43
> [<ffffffff816708ac>] do_vfs_ioctl+0x57c/0xe60 fs/ioctl.c:607
> [< inline >] SYSC_ioctl fs/ioctl.c:622
> [<ffffffff81671204>] SyS_ioctl+0x74/0x80 fs/ioctl.c:613
> [<ffffffff852a7876>] entry_SYSCALL_64_fastpath+0x16/0x7a
>
> Reported-by: Dmitry Vyukov <[email protected]>
> Signed-off-by: Peter Hurley <[email protected]>
> ---
> drivers/net/irda/irtty-sir.c | 10 ----------
> 1 file changed, 10 deletions(-)
>
> diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
> index 696852e..7a3f990 100644
> --- a/drivers/net/irda/irtty-sir.c
> +++ b/drivers/net/irda/irtty-sir.c
> @@ -430,16 +430,6 @@ static int irtty_open(struct tty_struct *tty)
>
> /* Module stuff handled via irda_ldisc.owner - Jean II */
>
> - /* First make sure we're not already connected. */
> - if (tty->disc_data != NULL) {
> - priv = tty->disc_data;
> - if (priv && priv->magic == IRTTY_MAGIC) {
> - ret = -EEXIST;
> - goto out;
> - }
> - tty->disc_data = NULL; /* ### */
> - }
> -
> /* stop the underlying driver */
> irtty_stop_receiver(tty, TRUE);
> if (tty->ops->stop)
> --
> 2.6.3
>
>