Page MenuHomeFreeBSD

gpioc: fix race in ioctl(GPIOCONFIGEVENTS)
ClosedPublic

Authored by vexeduxr on Mon, Sep 29, 3:47 PM.
Tags
None
Referenced Files
F133575791: D52783.id163079.diff
Sun, Oct 26, 6:36 PM
F133575776: D52783.id163023.diff
Sun, Oct 26, 6:36 PM
F133575767: D52783.id.diff
Sun, Oct 26, 6:36 PM
F133575741: D52783.id163062.diff
Sun, Oct 26, 6:36 PM
F133574986: D52783.diff
Sun, Oct 26, 6:27 PM
Unknown Object (File)
Sat, Oct 25, 9:45 PM
Unknown Object (File)
Thu, Oct 23, 11:33 PM
Unknown Object (File)
Sat, Oct 18, 2:40 AM
Subscribers

Details

Summary

A race can occur in gpioc_ioctl when it is called with GPIOCONFIGEVENTS
closely followed by GPIOSETCONFIG. GPIOSETCONFIG can alter the
priv->pins list, making it no longer empty and opening the door for
access to priv->events while we are reallocating it. Fix this by holding
priv->mtx while handling GPIOCONFIGEVENTS.

Reported by: Qiu-ji Chen
PR: 289120
MFC after: 3 days

Test Plan

This race would be quite hard to hit "naturally", but I managed to hit it with a strategically placed DELAY.
As expected, the race is gone when we hold priv->mtx.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 67407
Build 64290: arc lint + arc unit

Event Timeline

malloc priv->events with the correct size

sys/dev/gpio/gpioc.c
938

imho, M_NOWAIT is incorrect in this context. M_NOWAIT allocation can fail at any time, and in a non-deterministic manner. Not only when the system runs out of memory, but also when the other side locks one of the allocator's internal structures.

sys/dev/gpio/gpioc.c
938

We can't use M_WAITOK while holding a mutex though. We do the same in gpioc_attach_priv_pin when allocating a new list entry.

sys/dev/gpio/gpioc.c
938

malloc() should not be used with a mutex if the code cannot retry in case of failure; this is bad design practice. In this case, I don't see any disadvantage in using SX lock at first glance if malloc() cannot be moved outside.
However, this raises another question: if the GPIO is located on serial buses (SPI, I2C), its functions may sleep. Is GPIOC aware of this fact?

sys/dev/gpio/gpioc.c
938

Oups, sorry. Mutex is used in interrupt, so SX lock is out of the question.

sys/dev/gpio/gpioc.c
938

The malloc can be moved outside with some rearchitecting. And giving this some more thought, I agree that the call shouldn't fail if the system is under memory strain.

Allocate fifo before locking priv->mtx

This revision is now accepted and ready to land.Tue, Sep 30, 10:13 AM
This revision was automatically updated to reflect the committed changes.
sys/dev/gpio/gpioc.c
938

However, this raises another question: if the GPIO is located on serial buses (SPI, I2C), its functions may sleep. Is GPIOC aware of this fact?

Ah, forgot to reply to this. The code doesn't hold any locks when calling the GPIO functions, and it drops it's locks when setting up the interrupt.