Re: [PATCH] of/irq: Consider device address size in interrupt map walk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Aug 7, 2024 at 6:04 AM Stefan Wiehler <stefan.wiehler@xxxxxxxxx> wrote:
>
> When of_irq_parse_raw() is invoked with a device address smaller than
> the interrupt parent node (from #address-cells property), KASAN detects
> the following out-of-bounds read when populating the initial match table
> (dyndbg="func of_irq_parse_* +p"):

You've missed a bunch of people/lists. Use get_maintainers.pl.

>   OF: of_irq_parse_one: dev=/soc@0/picasso/watchdog, index=0
>   OF:  parent=/soc@0/pci@878000000000/gpio0@17,0, intsize=2
>   OF:  intspec=4
>   OF: of_irq_parse_raw: ipar=/soc@0/pci@878000000000/gpio0@17,0, size=2
>   OF:  -> addrsize=3

Can you provide some details on what these nodes look like. The
interrupt provider to an SoC device is a PCI device? That's weird...


>   ==================================================================
>   BUG: KASAN: slab-out-of-bounds in of_irq_parse_raw+0x2b8/0x8d0
>   Read of size 4 at addr ffffff81beca5608 by task bash/764
>
>   CPU: 1 PID: 764 Comm: bash Tainted: G           O       6.1.67-484c613561-nokia_sm_arm64 #1

Note that of_irq_parse_raw() was refactored in 6.10, so your patch is
not going to apply.

>   Hardware name: Unknown Unknown Product/Unknown Product, BIOS 2023.01-12.24.03-dirty 01/01/2023
>   Call trace:
>    dump_backtrace+0xdc/0x130
>    show_stack+0x1c/0x30
>    dump_stack_lvl+0x6c/0x84
>    print_report+0x150/0x448
>    kasan_report+0x98/0x140
>    __asan_load4+0x78/0xa0
>    of_irq_parse_raw+0x2b8/0x8d0
>    of_irq_parse_one+0x24c/0x270
>    parse_interrupts+0xc0/0x120
>    of_fwnode_add_links+0x100/0x2d0
>    fw_devlink_parse_fwtree+0x64/0xc0
>    device_add+0xb38/0xc30
>    of_device_add+0x64/0x90
>    of_platform_device_create_pdata+0xd0/0x170
>    of_platform_bus_create+0x244/0x600
>    of_platform_notify+0x1b0/0x254
>    blocking_notifier_call_chain+0x9c/0xd0
>    __of_changeset_entry_notify+0x1b8/0x230
>    __of_changeset_apply_notify+0x54/0xe4
>    of_overlay_fdt_apply+0xc04/0xd94

I wonder if it is possible for KASAN to detect this if it is a base DT
given the allocation is done by memblock.

>    ...
>
>   The buggy address belongs to the object at ffffff81beca5600
>    which belongs to the cache kmalloc-128 of size 128
>   The buggy address is located 8 bytes inside of
>    128-byte region [ffffff81beca5600, ffffff81beca5680)
>
>   The buggy address belongs to the physical page:
>   page:00000000230d3d03 refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1beca4
>   head:00000000230d3d03 order:1 compound_mapcount:0 compound_pincount:0
>   flags: 0x8000000000010200(slab|head|zone=2)
>   raw: 8000000000010200 0000000000000000 dead000000000122 ffffff810000c300
>   raw: 0000000000000000 0000000000200020 00000001ffffffff 0000000000000000
>   page dumped because: kasan: bad access detected
>
>   Memory state around the buggy address:
>    ffffff81beca5500: 04 fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>    ffffff81beca5580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>   >ffffff81beca5600: 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>                         ^
>    ffffff81beca5680: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>    ffffff81beca5700: 00 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc
>   ==================================================================
>   OF:  -> got it !
>
> Signed-off-by: Stefan Wiehler <stefan.wiehler@xxxxxxxxx>
> ---
>  arch/powerpc/platforms/fsl_uli1575.c |  2 +-
>  drivers/bcma/main.c                  |  2 +-
>  drivers/of/irq.c                     | 64 ++++++++++++++++------------
>  drivers/pci/of.c                     |  2 +-
>  include/linux/of_irq.h               |  3 +-
>  5 files changed, 41 insertions(+), 32 deletions(-)
>
> diff --git a/arch/powerpc/platforms/fsl_uli1575.c b/arch/powerpc/platforms/fsl_uli1575.c
> index b8d37a9932f1b..8da36f72b7b48 100644
> --- a/arch/powerpc/platforms/fsl_uli1575.c
> +++ b/arch/powerpc/platforms/fsl_uli1575.c
> @@ -335,7 +335,7 @@ static void hpcd_final_uli5288(struct pci_dev *dev)
>         oirq.args_count = 1;
>         laddr[0] = (hose->first_busno << 16) | (PCI_DEVFN(31, 0) << 8);
>         laddr[1] = laddr[2] = 0;
> -       of_irq_parse_raw(laddr, &oirq);
> +       of_irq_parse_raw(laddr, ARRAY_SIZE(laddr), &oirq);

That's not the right information to parse the address correctly. You
would need the device's #address-cells. However, in most cases we
don't really need to parse the address. The address is not really used
except in cases where interrupt routing matches the bus and so there
is only one size. That's effectively only PCI devices today. In that
case, the address size would always be equal, and the code implicitly
assumes that. It would be better if we could just detect when to use
the address or not. I think we'd have to look at 'interrupt-map-mask'
first to see whether or not to read the address cells. Or maybe we
could detect when the interrupt parent is the device's parent node.
Either way, this code is tricky and hard to change without breaking
something.

A simpler way to fix this is just always pass in an address buffer of
3 cells to of_irq_parse_raw. You would just need to copy the cells in
of_irq_parse_one() to a temporary buffer.

Rob





[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux