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. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJYDlz8AAoJEEEQszewGV1z0ScP/R9vZsE4zGyb2xLdFZ9H0tHW dg19NDpB98IGA86QMnrKzkbG35ulj8oMAWVyUp8N1pJY0WWpx4ld32lVRZxMZAfg pigM4e61FrYJaG41ZM82Z6WrhAHiz0utK3wZbNPVByOxPIzOZ8V9tobouaNVzYJ6 +yuITgCEOCxhcw+eCxfmI83Foj1kq0aKKA20MNufFKoq+QVZxft8mFHwaFKkFtvi jtoRo5/dtN7Fuk5zOr8XJLOzOKe82PqDT7fJQRqIkAf8prrlz2V18Qv/b+mkXKsO rdkfIEqCCZkRJW5q0LwZZIYSDZF0fcabggryQR803WyGC9AQKNCfSPpRA3TEUatG f4umySuTI9cnWt7RqvjDfBU6PJqbN8N6A8asH+e+ipxVqny5YnQsjfVf++cOjAWH Z9qIujD1jgEs5y6sxkRYp4b+vYIkmKRf1yDEI09jx3mUN3W1u+spkQgZ/M0cOaO3 J7IUPB+NFHEbNnxJ3CrpxV6IoAi//4wu4s46Q0lis0ibNJmPrlN63bmWgviPUVXx yaxDWTqJ3zBoGqdQfPqCF139Kaj6nsqmjJ4dTX83jH6UAZzBJR5J/lbnOKgA/zfr BkUqRYgolF5zLFLPXBomP0uieGaBF3sKwOQuP5Kn8V0unXOw1w/W9I++cFnETJVd +T8xURRSZ3TblxEx4ARx =dVE6 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
1ce5bdb831
@ -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
|
||||
gpio-legacy.txt (actually, there is no real mapping possible with the old
|
||||
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
|
||||
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:
|
||||
|
||||
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
|
||||
as active-low, its actual signal will be 0 after this code. Contrary to the legacy
|
||||
integer GPIO interface, the active-low property is handled during mapping and is
|
||||
thus transparent to GPIO consumers.
|
||||
as active-low, its actual signal will be 0 after this code. Contrary to the
|
||||
legacy integer GPIO interface, the active-low property is handled during
|
||||
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
|
||||
|
||||
config GPIO_MOCKUP
|
||||
tristate "GPIO Testing Driver"
|
||||
depends on GPIOLIB
|
||||
depends on GPIOLIB && SYSFS
|
||||
select GPIO_SYSFS
|
||||
help
|
||||
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[] = {
|
||||
{ .compatible = "qca,ar9340-gpio" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ath79_gpio_of_match);
|
||||
|
||||
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,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -308,8 +308,10 @@ static int mxs_gpio_probe(struct platform_device *pdev)
|
||||
writel(~0U, port->base + PINCTRL_IRQSTAT(port) + MXS_CLR);
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
|
||||
if (irq_base < 0)
|
||||
return irq_base;
|
||||
if (irq_base < 0) {
|
||||
err = irq_base;
|
||||
goto out_iounmap;
|
||||
}
|
||||
|
||||
port->domain = irq_domain_add_legacy(np, 32, irq_base, 0,
|
||||
&irq_domain_simple_ops, NULL);
|
||||
@ -349,6 +351,8 @@ out_irqdomain_remove:
|
||||
irq_domain_remove(port->domain);
|
||||
out_irqdesc_free:
|
||||
irq_free_descs(irq_base, 32);
|
||||
out_iounmap:
|
||||
iounmap(port->base);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -409,7 +409,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
|
||||
* 801/1801/1600, bits are cleared when read.
|
||||
* 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_reg_write(stmpe, statmsbreg + i, status[i]);
|
||||
stmpe_reg_write(stmpe,
|
||||
|
@ -66,6 +66,7 @@ static const struct of_device_id ts4800_gpio_of_match[] = {
|
||||
{ .compatible = "technologic,ts4800-gpio", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ts4800_gpio_of_match);
|
||||
|
||||
static struct platform_driver ts4800_gpio_driver = {
|
||||
.driver = {
|
||||
|
@ -653,14 +653,17 @@ int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
||||
{
|
||||
int idx, i;
|
||||
unsigned int irq_flags;
|
||||
int ret = -ENOENT;
|
||||
|
||||
for (i = 0, idx = 0; idx <= index; i++) {
|
||||
struct acpi_gpio_info info;
|
||||
struct gpio_desc *desc;
|
||||
|
||||
desc = acpi_get_gpiod_by_index(adev, NULL, i, &info);
|
||||
if (IS_ERR(desc))
|
||||
if (IS_ERR(desc)) {
|
||||
ret = PTR_ERR(desc);
|
||||
break;
|
||||
}
|
||||
if (info.gpioint && idx++ == index) {
|
||||
int irq = gpiod_to_irq(desc);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
@ -333,6 +333,13 @@ struct linehandle_state {
|
||||
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,
|
||||
unsigned long arg)
|
||||
{
|
||||
@ -344,6 +351,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd,
|
||||
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
|
||||
int val;
|
||||
|
||||
memset(&ghd, 0, sizeof(ghd));
|
||||
|
||||
/* TODO: check if descriptors are really input */
|
||||
for (i = 0; i < lh->numdescs; i++) {
|
||||
val = gpiod_get_value_cansleep(lh->descs[i]);
|
||||
@ -444,6 +453,17 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
|
||||
u32 lflags = handlereq.flags;
|
||||
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];
|
||||
ret = gpiod_request(desc, lh->label);
|
||||
if (ret)
|
||||
@ -536,6 +556,10 @@ struct lineevent_state {
|
||||
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,
|
||||
struct poll_table_struct *wait)
|
||||
{
|
||||
@ -623,6 +647,8 @@ static long lineevent_ioctl(struct file *filep, unsigned int cmd,
|
||||
if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) {
|
||||
int val;
|
||||
|
||||
memset(&ghd, 0, sizeof(ghd));
|
||||
|
||||
val = gpiod_get_value_cansleep(le->desc);
|
||||
if (val < 0)
|
||||
return val;
|
||||
@ -726,6 +752,18 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
|
||||
lflags = eventreq.handleflags;
|
||||
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 */
|
||||
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
|
||||
ret = -EINVAL;
|
||||
@ -823,6 +861,8 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
if (cmd == GPIO_GET_CHIPINFO_IOCTL) {
|
||||
struct gpiochip_info chipinfo;
|
||||
|
||||
memset(&chipinfo, 0, sizeof(chipinfo));
|
||||
|
||||
strncpy(chipinfo.name, dev_name(&gdev->dev),
|
||||
sizeof(chipinfo.name));
|
||||
chipinfo.name[sizeof(chipinfo.name)-1] = '\0';
|
||||
@ -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)))
|
||||
return -EFAULT;
|
||||
if (lineinfo.line_offset > gdev->ngpio)
|
||||
if (lineinfo.line_offset >= gdev->ngpio)
|
||||
return -EINVAL;
|
||||
|
||||
desc = &gdev->descs[lineinfo.line_offset];
|
||||
|
Loading…
Reference in New Issue
Block a user