Commit 1ce5bdb8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO fixes from Linus Walleij:
 "Here is a set of GPIO fixes for the v4.9 kernel series:

   - Fix up off-by one and line offset validation, info leak to
     userspace, and reject invalid flags. Those are especially valuable
     hardening patches from Lars-Peter Clausen, all tagged for stable.

   - Fix module autoload for TS4800 and ATH79.

   - Correct the IRQ handler for MPC8xxx to use handle_level_irq() as it
     (a) reacts to edges not levels and (b) even implements .irq_ack().
     We were missing IRQs here.

   - Fix the error path for acpi_dev_gpio_irq_get()

   - Fix a memory leak in the MXS driver.

   - Fix an annoying typo in the STMPE driver.

   - Put a dependency on sysfs to the mockup driver"

* tag 'gpio-v4.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpio: mpc8xxx: Correct irq handler function
  gpio: ath79: Fix module autoload
  gpio: ts4800: Fix module autoload
  gpio: GPIO_GET_LINEEVENT_IOCTL: Reject invalid line and event flags
  gpio: GPIO_GET_LINEHANDLE_IOCTL: Reject invalid line flags
  gpio: GPIOHANDLE_GET_LINE_VALUES_IOCTL: Fix information leak
  gpio: GPIO_GET_LINEEVENT_IOCTL: Validate line offset
  gpio: GPIOHANDLE_GET_LINE_VALUES_IOCTL: Fix information leak
  gpio: GPIO_GET_LINEHANDLE_IOCTL: Validate line offset
  gpio: GPIO_GET_CHIPINFO_IOCTL: Fix information leak
  gpio: GPIO_GET_CHIPINFO_IOCTL: Fix line offset validation
  gpio / ACPI: fix returned error from acpi_dev_gpio_irq_get()
  gpio: mockup: add sysfs dependency
  gpio: stmpe: || vs && typo
  gpio: mxs: Unmap region obtained by of_iomap
  gpio/board.txt: point to gpiod_set_value
parents aa34e07e d71cf15b
...@@ -6,7 +6,7 @@ Note that it only applies to the new descriptor-based interface. For a ...@@ -6,7 +6,7 @@ Note that it only applies to the new descriptor-based interface. For a
description of the deprecated integer-based GPIO interface please refer to description of the deprecated integer-based GPIO interface please refer to
gpio-legacy.txt (actually, there is no real mapping possible with the old gpio-legacy.txt (actually, there is no real mapping possible with the old
interface; you just fetch an integer from somewhere and request the interface; you just fetch an integer from somewhere and request the
corresponding GPIO. corresponding GPIO).
All platforms can enable the GPIO library, but if the platform strictly All platforms can enable the GPIO library, but if the platform strictly
requires GPIO functionality to be present, it needs to select GPIOLIB from its requires GPIO functionality to be present, it needs to select GPIOLIB from its
...@@ -162,6 +162,9 @@ The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: ...@@ -162,6 +162,9 @@ The driver controlling "foo.0" will then be able to obtain its GPIOs as follows:
Since the "led" GPIOs are mapped as active-high, this example will switch their Since the "led" GPIOs are mapped as active-high, this example will switch their
signals to 1, i.e. enabling the LEDs. And for the "power" GPIO, which is mapped signals to 1, i.e. enabling the LEDs. And for the "power" GPIO, which is mapped
as active-low, its actual signal will be 0 after this code. Contrary to the legacy as active-low, its actual signal will be 0 after this code. Contrary to the
integer GPIO interface, the active-low property is handled during mapping and is legacy integer GPIO interface, the active-low property is handled during
thus transparent to GPIO consumers. mapping and is thus transparent to GPIO consumers.
A set of functions such as gpiod_set_value() is available to work with
the new descriptor-oriented interface.
...@@ -284,7 +284,7 @@ config GPIO_MM_LANTIQ ...@@ -284,7 +284,7 @@ config GPIO_MM_LANTIQ
config GPIO_MOCKUP config GPIO_MOCKUP
tristate "GPIO Testing Driver" tristate "GPIO Testing Driver"
depends on GPIOLIB depends on GPIOLIB && SYSFS
select GPIO_SYSFS select GPIO_SYSFS
help help
This enables GPIO Testing driver, which provides a way to test GPIO This enables GPIO Testing driver, which provides a way to test GPIO
......
...@@ -219,6 +219,7 @@ static const struct of_device_id ath79_gpio_of_match[] = { ...@@ -219,6 +219,7 @@ static const struct of_device_id ath79_gpio_of_match[] = {
{ .compatible = "qca,ar9340-gpio" }, { .compatible = "qca,ar9340-gpio" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
static int ath79_gpio_probe(struct platform_device *pdev) static int ath79_gpio_probe(struct platform_device *pdev)
{ {
......
...@@ -239,7 +239,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, ...@@ -239,7 +239,7 @@ static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
irq_set_chip_data(irq, h->host_data); irq_set_chip_data(irq, h->host_data);
irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq);
return 0; return 0;
} }
......
...@@ -308,8 +308,10 @@ static int mxs_gpio_probe(struct platform_device *pdev) ...@@ -308,8 +308,10 @@ static int mxs_gpio_probe(struct platform_device *pdev)
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR); writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id()); irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
if (irq_base < 0) if (irq_base < 0) {
return irq_base; err = irq_base;
goto out_iounmap;
}
port->domain = irq_domain_add_legacy(np, 32, irq_base, 0, port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,
&irq_domain_simple_ops, NULL); &irq_domain_simple_ops, NULL);
...@@ -349,6 +351,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) ...@@ -349,6 +351,8 @@ static int mxs_gpio_probe(struct platform_device *pdev)
irq_domain_remove(port->domain); irq_domain_remove(port->domain);
out_irqdesc_free: out_irqdesc_free:
irq_free_descs(irq_base, 32); irq_free_descs(irq_base, 32);
out_iounmap:
iounmap(port->base);
return err; return err;
} }
......
...@@ -409,7 +409,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) ...@@ -409,7 +409,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
* 801/1801/1600, bits are cleared when read. * 801/1801/1600, bits are cleared when read.
* Edge detect register is not present on 801/1600/1801 * Edge detect register is not present on 801/1600/1801
*/ */
if (stmpe->partnum != STMPE801 || stmpe->partnum != STMPE1600 || if (stmpe->partnum != STMPE801 && stmpe->partnum != STMPE1600 &&
stmpe->partnum != STMPE1801) { stmpe->partnum != STMPE1801) {
stmpe_reg_write(stmpe, statmsbreg + i, status[i]); stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
stmpe_reg_write(stmpe, stmpe_reg_write(stmpe,
......
...@@ -66,6 +66,7 @@ static const struct of_device_id ts4800_gpio_of_match[] = { ...@@ -66,6 +66,7 @@ static const struct of_device_id ts4800_gpio_of_match[] = {
{ .compatible = "technologic,ts4800-gpio", }, { .compatible = "technologic,ts4800-gpio", },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, ts4800_gpio_of_match);
static struct platform_driver ts4800_gpio_driver = { static struct platform_driver ts4800_gpio_driver = {
.driver = { .driver = {
......
...@@ -653,14 +653,17 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) ...@@ -653,14 +653,17 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
{ {
int idx, i; int idx, i;
unsigned int irq_flags; unsigned int irq_flags;
int ret = -ENOENT;
for (i = 0, idx = 0; idx <= index; i++) { for (i = 0, idx = 0; idx <= index; i++) {
struct acpi_gpio_info info; struct acpi_gpio_info info;
struct gpio_desc *desc; struct gpio_desc *desc;
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info); desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
if (IS_ERR(desc)) if (IS_ERR(desc)) {
ret = PTR_ERR(desc);
break; break;
}
if (info.gpioint && idx++ == index) { if (info.gpioint && idx++ == index) {
int irq = gpiod_to_irq(desc); int irq = gpiod_to_irq(desc);
...@@ -679,7 +682,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) ...@@ -679,7 +682,7 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
} }
} }
return -ENOENT; return ret;
} }
EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get); EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_get);
......
...@@ -333,6 +333,13 @@ struct linehandle_state { ...@@ -333,6 +333,13 @@ struct linehandle_state {
u32 numdescs; u32 numdescs;
}; };
#define GPIOHANDLE_REQUEST_VALID_FLAGS \
(GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT | \
GPIOHANDLE_REQUEST_ACTIVE_LOW | \
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE)
static long linehandle_ioctl(struct file *filep, unsigned int cmd, static long linehandle_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
...@@ -344,6 +351,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, ...@@ -344,6 +351,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
int val; int val;
memset(&ghd, 0, sizeof(ghd));
/* TODO: check if descriptors are really input */ /* TODO: check if descriptors are really input */
for (i = 0; i < lh->numdescs; i++) { for (i = 0; i < lh->numdescs; i++) {
val = gpiod_get_value_cansleep(lh->descs[i]); val = gpiod_get_value_cansleep(lh->descs[i]);
...@@ -444,6 +453,17 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) ...@@ -444,6 +453,17 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
u32 lflags = handlereq.flags; u32 lflags = handlereq.flags;
struct gpio_desc *desc; struct gpio_desc *desc;
if (offset >= gdev->ngpio) {
ret = -EINVAL;
goto out_free_descs;
}
/* Return an error if a unknown flag is set */
if (lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) {
ret = -EINVAL;
goto out_free_descs;
}
desc = &gdev->descs[offset]; desc = &gdev->descs[offset];
ret = gpiod_request(desc, lh->label); ret = gpiod_request(desc, lh->label);
if (ret) if (ret)
...@@ -536,6 +556,10 @@ struct lineevent_state { ...@@ -536,6 +556,10 @@ struct lineevent_state {
struct mutex read_lock; struct mutex read_lock;
}; };
#define GPIOEVENT_REQUEST_VALID_FLAGS \
(GPIOEVENT_REQUEST_RISING_EDGE | \
GPIOEVENT_REQUEST_FALLING_EDGE)
static unsigned int lineevent_poll(struct file *filep, static unsigned int lineevent_poll(struct file *filep,
struct poll_table_struct *wait) struct poll_table_struct *wait)
{ {
...@@ -623,6 +647,8 @@ static long lineevent_ioctl(struct file *filep, unsigned int cmd, ...@@ -623,6 +647,8 @@ static long lineevent_ioctl(struct file *filep, unsigned int cmd,
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
int val; int val;
memset(&ghd, 0, sizeof(ghd));
val = gpiod_get_value_cansleep(le->desc); val = gpiod_get_value_cansleep(le->desc);
if (val < 0) if (val < 0)
return val; return val;
...@@ -726,6 +752,18 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) ...@@ -726,6 +752,18 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
lflags = eventreq.handleflags; lflags = eventreq.handleflags;
eflags = eventreq.eventflags; eflags = eventreq.eventflags;
if (offset >= gdev->ngpio) {
ret = -EINVAL;
goto out_free_label;
}
/* Return an error if a unknown flag is set */
if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
(eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) {
ret = -EINVAL;
goto out_free_label;
}
/* This is just wrong: we don't look for events on output lines */ /* This is just wrong: we don't look for events on output lines */
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
ret = -EINVAL; ret = -EINVAL;
...@@ -823,6 +861,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -823,6 +861,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (cmd == GPIO_GET_CHIPINFO_IOCTL) { if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
struct gpiochip_info chipinfo; struct gpiochip_info chipinfo;
memset(&chipinfo, 0, sizeof(chipinfo));
strncpy(chipinfo.name, dev_name(&gdev->dev), strncpy(chipinfo.name, dev_name(&gdev->dev),
sizeof(chipinfo.name)); sizeof(chipinfo.name));
chipinfo.name[sizeof(chipinfo.name)-1] = '\0'; chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
...@@ -839,7 +879,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -839,7 +879,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
return -EFAULT; return -EFAULT;
if (lineinfo.line_offset > gdev->ngpio) if (lineinfo.line_offset >= gdev->ngpio)
return -EINVAL; return -EINVAL;
desc = &gdev->descs[lineinfo.line_offset]; desc = &gdev->descs[lineinfo.line_offset];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment