[PATCH 0/8] counter: Remove struct counter_device::priv

Uwe Kleine-König posted 8 patches 4 years, 6 months ago
drivers/counter/104-quad-8.c            | 64 +++++++++++++------------
drivers/counter/ftm-quaddec.c           | 14 ++++--
drivers/counter/intel-qep.c             | 24 ++++++----
drivers/counter/interrupt-cnt.c         | 16 ++++---
drivers/counter/microchip-tcb-capture.c | 18 ++++---
drivers/counter/stm32-lptimer-cnt.c     | 24 ++++++----
drivers/counter/stm32-timer-cnt.c       | 24 ++++++----
drivers/counter/ti-eqep.c               |  1 -
include/linux/counter.h                 |  3 --
9 files changed, 106 insertions(+), 82 deletions(-)
[PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Uwe Kleine-König 4 years, 6 months ago
Hello,

similar to patch
https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
the usage of struct counter_device::priv can be replaced by
container_of which improves type safety and code size.

This series depends on above patch, converts the remaining drivers and
finally drops struct counter_device::priv.

This series was compile tested using ARCH=arm allmodconfig with the
following change:

 config 104_QUAD_8
        tristate "ACCES 104-QUAD-8 driver"
-       depends on PC104 && X86
+       depends on PC104 && X86 || COMPILE_TEST
        select ISA_BUS_API

in drivers/counter/Kconfig.

Best regards
Uwe

Uwe Kleine-König (8):
  counter: 104-quad-8: Use container_of instead of struct
    counter_device::priv
  counter: ftm-quaddec: Use container_of instead of struct
    counter_device::priv
  counter: intel-qeb: Use container_of instead of struct
    counter_device::priv
  counter: interrupt-cnt: Use container_of instead of struct
    counter_device::priv
  counter: microchip-tcp-capture: Use container_of instead of struct
    counter_device::priv
  counter: stm32-lptimer-cnt: Use container_of instead of struct
    counter_device::priv
  counter: stm32-timer-cnt: Use container_of instead of struct
    counter_device::priv
  counter: Remove unused member from struct counter_device

 drivers/counter/104-quad-8.c            | 64 +++++++++++++------------
 drivers/counter/ftm-quaddec.c           | 14 ++++--
 drivers/counter/intel-qep.c             | 24 ++++++----
 drivers/counter/interrupt-cnt.c         | 16 ++++---
 drivers/counter/microchip-tcb-capture.c | 18 ++++---
 drivers/counter/stm32-lptimer-cnt.c     | 24 ++++++----
 drivers/counter/stm32-timer-cnt.c       | 24 ++++++----
 drivers/counter/ti-eqep.c               |  1 -
 include/linux/counter.h                 |  3 --
 9 files changed, 106 insertions(+), 82 deletions(-)


base-commit: fa55b7dcdc43c1aa1ba12bca9d2dd4318c2a0dbf
prerequisite-patch-id: 9459ad8bc78190558df9123f8bebe28ca1c396ea
-- 
2.33.0

Re: [PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Lars-Peter Clausen 4 years, 6 months ago
On 12/21/21 11:45 AM, Uwe Kleine-König wrote:
> Hello,
>
> similar to patch
> https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
> the usage of struct counter_device::priv can be replaced by
> container_of which improves type safety and code size.
>
> This series depends on above patch, converts the remaining drivers and
> finally drops struct counter_device::priv.

Not sure if this is such a good idea. struct counter_device should not 
be embedded in the drivers state struct in the first place.

struct counter_device contains a struct device, which is a reference 
counted object. But by embedding it in the driver state struct the life 
time of both the struct counter_device and and struct device are bound 
to the life time of the driver state struct.

Which means the struct device memory can get freed before the last 
reference is dropped, which leads to a use-after-free and undefined 
behavior.

The framework should be changed to rather then embedding the struct 
counter_device in the state struct to just have a pointer to it. With 
the struct counter_device having its own allocation that will be freed 
when the last reference to the struct device is dropped.

- Lars

Re: [PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Uwe Kleine-König 4 years, 6 months ago
Hello Lars,

On Tue, Dec 21, 2021 at 12:12:12PM +0100, Lars-Peter Clausen wrote:
> On 12/21/21 11:45 AM, Uwe Kleine-König wrote:
> > similar to patch
> > https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
> > the usage of struct counter_device::priv can be replaced by
> > container_of which improves type safety and code size.
> > 
> > This series depends on above patch, converts the remaining drivers and
> > finally drops struct counter_device::priv.
> 
> Not sure if this is such a good idea. struct counter_device should not be
> embedded in the drivers state struct in the first place.

Just to mention it: My patch series didn't change this, this was already
broken before.

> struct counter_device contains a struct device, which is a reference counted
> object. But by embedding it in the driver state struct the life time of both
> the struct counter_device and and struct device are bound to the life time
> of the driver state struct.
> 
> Which means the struct device memory can get freed before the last reference
> is dropped, which leads to a use-after-free and undefined behavior.

Well, the driver struct is allocated using devm_kzalloc for all drivers.
So I think it's not *very* urgent to fix. Still you're right, this
should be addressed.
 
> The framework should be changed to rather then embedding the struct
> counter_device in the state struct to just have a pointer to it. With the
> struct counter_device having its own allocation that will be freed when the
> last reference to the struct device is dropped.

My favourite would be to implement a counter_device_alloc /
counter_device_add approach, similar to what spi_alloc_controller and
alloc_etherdev do. The downside is that this isn't typesafe either :-\

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |
Re: [PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Lars-Peter Clausen 4 years, 6 months ago
On 12/21/21 12:35 PM, Uwe Kleine-König wrote:
> Hello Lars,
>
> On Tue, Dec 21, 2021 at 12:12:12PM +0100, Lars-Peter Clausen wrote:
>> On 12/21/21 11:45 AM, Uwe Kleine-König wrote:
>>> similar to patch
>>> https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
>>> the usage of struct counter_device::priv can be replaced by
>>> container_of which improves type safety and code size.
>>>
>>> This series depends on above patch, converts the remaining drivers and
>>> finally drops struct counter_device::priv.
>> Not sure if this is such a good idea. struct counter_device should not be
>> embedded in the drivers state struct in the first place.
> Just to mention it: My patch series didn't change this, this was already
> broken before.
I know, but this series has to be reverted when the framework is fixed.
>
>> struct counter_device contains a struct device, which is a reference counted
>> object. But by embedding it in the driver state struct the life time of both
>> the struct counter_device and and struct device are bound to the life time
>> of the driver state struct.
>>
>> Which means the struct device memory can get freed before the last reference
>> is dropped, which leads to a use-after-free and undefined behavior.
> Well, the driver struct is allocated using devm_kzalloc for all drivers.

devm_kzalloc() doesn't make a difference. The managed memory is freed 
when the parent device is unbound/removed. There may very well be 
reference to the counter_device at this point.

> So I think it's not *very* urgent to fix. Still you're right, this
> should be addressed.

Yes and no, this can trivially be used for privilege escalation, but 
then again on systems with a counter_device probably everything runs as 
root anyway.

>   
>> The framework should be changed to rather then embedding the struct
>> counter_device in the state struct to just have a pointer to it. With the
>> struct counter_device having its own allocation that will be freed when the
>> last reference to the struct device is dropped.
> My favourite would be to implement a counter_device_alloc /
> counter_device_add approach, similar to what spi_alloc_controller and
> alloc_etherdev do. The downside is that this isn't typesafe either :-\


Re: [PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Uwe Kleine-König 4 years, 6 months ago
On Tue, Dec 21, 2021 at 01:04:50PM +0100, Lars-Peter Clausen wrote:
> On 12/21/21 12:35 PM, Uwe Kleine-König wrote:
> > On Tue, Dec 21, 2021 at 12:12:12PM +0100, Lars-Peter Clausen wrote:
> > > On 12/21/21 11:45 AM, Uwe Kleine-König wrote:
> > > > similar to patch
> > > > https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
> > > > the usage of struct counter_device::priv can be replaced by
> > > > container_of which improves type safety and code size.
> > > > 
> > > > This series depends on above patch, converts the remaining drivers and
> > > > finally drops struct counter_device::priv.
> > > Not sure if this is such a good idea. struct counter_device should not be
> > > embedded in the drivers state struct in the first place.
> > Just to mention it: My patch series didn't change this, this was already
> > broken before.
> 
> I know, but this series has to be reverted when the framework is fixed.

All drivers have to be touched. With my patch series you have to modify
one function in each driver, without my patch you have touch nearly
every function.

*shrug*

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |
Re: [PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Lars-Peter Clausen 4 years, 6 months ago
On 12/21/21 2:22 PM, Uwe Kleine-König wrote:
> On Tue, Dec 21, 2021 at 01:04:50PM +0100, Lars-Peter Clausen wrote:
>> On 12/21/21 12:35 PM, Uwe Kleine-König wrote:
>>> On Tue, Dec 21, 2021 at 12:12:12PM +0100, Lars-Peter Clausen wrote:
>>>> On 12/21/21 11:45 AM, Uwe Kleine-König wrote:
>>>>> similar to patch
>>>>> https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
>>>>> the usage of struct counter_device::priv can be replaced by
>>>>> container_of which improves type safety and code size.
>>>>>
>>>>> This series depends on above patch, converts the remaining drivers and
>>>>> finally drops struct counter_device::priv.
>>>> Not sure if this is such a good idea. struct counter_device should not be
>>>> embedded in the drivers state struct in the first place.
>>> Just to mention it: My patch series didn't change this, this was already
>>> broken before.
>> I know, but this series has to be reverted when the framework is fixed.
> All drivers have to be touched. With my patch series you have to modify
> one function in each driver, without my patch you have touch nearly
> every function.
>
I'm not so sure. I don't see how you have to modify every function. 
You'd keep using priv to get a pointer to the state struct.

That said having a centralized function in each driver to get the state 
struct from the counter device doesn't hurt either.


Re: [PATCH 0/8] counter: Remove struct counter_device::priv
Posted by Uwe Kleine-König 4 years, 6 months ago
Hello,

On Tue, Dec 21, 2021 at 01:04:50PM +0100, Lars-Peter Clausen wrote:
> On 12/21/21 12:35 PM, Uwe Kleine-König wrote:
> > On Tue, Dec 21, 2021 at 12:12:12PM +0100, Lars-Peter Clausen wrote:
> > > On 12/21/21 11:45 AM, Uwe Kleine-König wrote:
> > > > similar to patch
> > > > https://lore.kernel.org/r/4bde7cbd9e43a5909208102094444219d3154466.1640072891.git.vilhelm.gray@gmail.com
> > > > the usage of struct counter_device::priv can be replaced by
> > > > container_of which improves type safety and code size.
> > > > 
> > > > This series depends on above patch, converts the remaining drivers and
> > > > finally drops struct counter_device::priv.
> > > Not sure if this is such a good idea. struct counter_device should not be
> > > embedded in the drivers state struct in the first place.
> > Just to mention it: My patch series didn't change this, this was already
> > broken before.
> I know, but this series has to be reverted when the framework is fixed.
> > 
> > > struct counter_device contains a struct device, which is a reference counted
> > > object. But by embedding it in the driver state struct the life time of both
> > > the struct counter_device and and struct device are bound to the life time
> > > of the driver state struct.
> > > 
> > > Which means the struct device memory can get freed before the last reference
> > > is dropped, which leads to a use-after-free and undefined behavior.
> > Well, the driver struct is allocated using devm_kzalloc for all drivers.
> 
> devm_kzalloc() doesn't make a difference. The managed memory is freed when
> the parent device is unbound/removed. There may very well be reference to
> the counter_device at this point.
> 
> > So I think it's not *very* urgent to fix. Still you're right, this
> > should be addressed.
> 
> Yes and no, this can trivially be used for privilege escalation, but then
> again on systems with a counter_device probably everything runs as root
> anyway.

I could provoke an oops with the following shell command:


	{ sleep 5; echo bang; } > /dev/counter0 & sleep 1; echo 40000000.timer:counter > /sys/bus/platform/drivers/stm32-timer-counter/unbind

I have a protype here to split counter_register() into counter_alloc() +
counter_add(), but I didn't convert a driver to it yet. If you want to
take a look, it's currently available from

	https://git.pengutronix.de/git/ukl/linux counter-dev-livetime

(or if you prefer a webif:

	https://git.pengutronix.de/cgit/ukl/linux/log/?h=counter-dev-livetime

). I planned to just invest a two or so hours to fix this. But the plan
failed (one reason is that v5.16-rc6 failed to boot on the stm32mp1 I
work on and I bisected that first.)

Maybe I find some time between the years to get this forward a bit.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |