lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <b36fcdf1-45ab-0c06-efe4-237df0612466@alliedtelesis.co.nz>
Date:   Sun, 14 May 2023 22:27:39 +0000
From:   Chris Packham <Chris.Packham@...iedtelesis.co.nz>
To:     Linus Walleij <linus.walleij@...aro.org>
CC:     "brgl@...ev.pl" <brgl@...ev.pl>,
        "johan@...nel.org" <johan@...nel.org>,
        "andy.shevchenko@...il.com" <andy.shevchenko@...il.com>,
        "maz@...nel.org" <maz@...nel.org>,
        Ben Brown <Ben.Brown@...iedtelesis.co.nz>,
        "linux-gpio@...r.kernel.org" <linux-gpio@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH] gpiolib: Avoid side effects in gpio_is_visible()


On 12/05/23 19:56, Linus Walleij wrote:
> On Fri, May 12, 2023 at 6:28 AM Chris Packham
> <chris.packham@...iedtelesis.co.nz> wrote:
>
>> Calling gpiod_to_irq() creates an irq_desc for the GPIO.
> Normally gpiod_to_irq() should not have side effects, it's just
> a helper function that is there to translate a descriptor to the
> corresponding IRQ number.
>
>> This is not
>> something that should happen when just exporting the GPIO via sysfs. The
>> effect of this was observed as triggering a warning in
>> gpiochip_disable_irq() when kexec()ing after exporting a GPIO.

For clarity this is the problem I see on kexec

WARNING: CPU: 1 PID: 235 at drivers/gpio/gpiolib.c:3440 
gpiochip_disable_irq+0x64/0x6c
Call trace:
  gpiochip_disable_irq+0x64/0x6c
  machine_crash_shutdown+0xac/0x114
  __crash_kexec+0x74/0x154
  panic+0x300/0x370
  sysrq_reset_seq_param_set+0x0/0x8c
  __handle_sysrq+0xb8/0x1b8
  write_sysrq_trigger+0x74/0xa0
  proc_reg_write+0x9c/0xf0
  vfs_write+0xc4/0x298
  ksys_write+0x68/0xf4
  __arm64_sys_write+0x1c/0x28
  invoke_syscall+0x48/0x114
  el0_svc_common.constprop.0+0x44/0xf4
  do_el0_svc+0x3c/0xa8
  el0_svc+0x2c/0x84
  el0t_64_sync_handler+0xbc/0x138
  el0t_64_sync+0x190/0x194

>> Remove the call to gpiod_to_irq() from gpio_is_visible(). The actual
>> intended creation of the irq_desc comes via edge_store() when requested
>> by the user.
>>
>> Fixes: ebbeba120ab2 ("gpio: sysfs: fix gpio attribute-creation race")
>> Signed-off-by: Chris Packham <chris.packham@...iedtelesis.co.nz>
> I have a hard time understanding this fix.

The problem (as I far as I've been able to determine). Is that 
gpio_is_visible() uses gpiod_to_irq() to decide whether to provide the 
"edge" attribute. The problem is that instead of just looking up the 
irq_desc from the GPIO pin gpiod_to_irq() actually creates the irq_desc 
(via  gpiochip_to_irq()).

Because gpio_sysfs_request_irq() calls gpiochip_to_irq() anyway to 
create the irq_desc I thought removing gpiochip_to_irq() from 
gpio_is_visible() should be safe.

>
> The problem is rather this see gpiolib.c:
>
> int gpiod_to_irq(const struct gpio_desc *desc)
> {
>          struct gpio_chip *gc;
>          int offset;
>
>          /*
>           * Cannot VALIDATE_DESC() here as gpiod_to_irq() consumer semantics
>           * requires this function to not return zero on an invalid descriptor
>           * but rather a negative error number.
>           */
>          if (!desc || IS_ERR(desc) || !desc->gdev || !desc->gdev->chip)
>                  return -EINVAL;
>
>          gc = desc->gdev->chip;
>          offset = gpio_chip_hwgpio(desc);
>          if (gc->to_irq) {
>                  int retirq = gc->to_irq(gc, offset);
>
> Here gc->to_irq() is called unconditionally.
>
> Since this is using gpiolib_irqchip this ->to_irq() will be
> gpiochip_to_irq() and that finally ends in the call:
>
> return irq_create_mapping(domain, offset);
>
> which seems to be the problem here. Why is this a problem?
> The IRQ mappings are dynamic, meaning they are created
> on-demand, but for this hardware it should be fine to essentially
> just call irq_create_mapping() on all of them as the device
> is created, we just don't do it in order to save space.

In my original case which is a kernel module that exports a GPIO for 
userspace using gpiod_export() it's inappropriate because the GPIO in 
question is configured as an output but gpio_is_visible() still causes 
an irq_desc to be created even though the very next line of code knows 
that it should not make the edge attribute visible.

The manually exporting things via sysfs case is a bit more murky because 
it's not known if the GPIO is an input or output so the code must assume 
both are possible (obviously this is one thing libgpio fixes). I still 
think creating the irq_desc on export is wrong, it seems unnecessary as 
it'll happen if an interrupt is actually requested via edge_store().

> I don't understand why calling irq_create_mapping(domain, offset);
> creates a problem? It's just a mapping between a GPIO and the
> corresponding IRQ. What am I missing here?

The crux of the problem is that the irq_desc is created when it hasn't 
been requested. In some cases we know the GPIO pin is an output so we 
could avoid it, in others we could delay the creation until an interrupt 
is actually requested (which is what I'm attempting to do).

>
> Yours,
> Linus Walleij

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ