diff mbox

[2/2] lgdt3306a: Fix a double kfree on i2c device remove

Message ID 1515164233-2423-3-git-send-email-brad@nextdimension.cc (mailing list archive)
State New, archived
Headers show

Commit Message

Brad Love Jan. 5, 2018, 2:57 p.m. UTC
Both lgdt33606a_release and lgdt3306a_remove kfree state, but _release is
called first, then _remove operates on states members before kfree'ing it.
This can lead to random oops/GPF/etc on USB disconnect.

Signed-off-by: Brad Love <brad@nextdimension.cc>
---
 drivers/media/dvb-frontends/lgdt3306a.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Comments

Matthias Schwarzott Jan. 8, 2018, 8:34 p.m. UTC | #1
Am 05.01.2018 um 15:57 schrieb Brad Love:
> Both lgdt33606a_release and lgdt3306a_remove kfree state, but _release is
> called first, then _remove operates on states members before kfree'ing it.
> This can lead to random oops/GPF/etc on USB disconnect.
> 
lgdt3306a_release does nothing but the kfree. So the exact same effect
can be archived by setting state->frontend.ops.release to NULL. This
need to be done already at probe time I think.
lgdt3306a_remove does this, but too late (after the call to release).

Regards
Matthias

> Signed-off-by: Brad Love <brad@nextdimension.cc>
> ---
>  drivers/media/dvb-frontends/lgdt3306a.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
> index d370671..3642e6e 100644
> --- a/drivers/media/dvb-frontends/lgdt3306a.c
> +++ b/drivers/media/dvb-frontends/lgdt3306a.c
> @@ -1768,7 +1768,13 @@ static void lgdt3306a_release(struct dvb_frontend *fe)
>  	struct lgdt3306a_state *state = fe->demodulator_priv;
>  
>  	dbg_info("\n");
> -	kfree(state);
> +
> +	/*
> +	 * If state->muxc is not NULL, then we are an i2c device
> +	 * and lgdt3306a_remove will clean up state
> +	 */
> +	if (!state->muxc)
> +		kfree(state);
>  }
>  
>  static const struct dvb_frontend_ops lgdt3306a_ops;
>
Brad Love Jan. 8, 2018, 8:43 p.m. UTC | #2
On 2018-01-08 14:34, Matthias Schwarzott wrote:
> Am 05.01.2018 um 15:57 schrieb Brad Love:
>> Both lgdt33606a_release and lgdt3306a_remove kfree state, but _release is
>> called first, then _remove operates on states members before kfree'ing it.
>> This can lead to random oops/GPF/etc on USB disconnect.
>>
> lgdt3306a_release does nothing but the kfree. So the exact same effect
> can be archived by setting state->frontend.ops.release to NULL. This
> need to be done already at probe time I think.
> lgdt3306a_remove does this, but too late (after the call to release).
>
> Regards
> Matthias

Hi Matthias,

I agree. This was my rationale in the previous patch:

/patch/46328

Both methods handle the issue. I thought the previous
attempt was fairly clean, but it did not pass review, so
I provided this solution.

Cheers,

Brad







>> Signed-off-by: Brad Love <brad@nextdimension.cc>
>> ---
>>  drivers/media/dvb-frontends/lgdt3306a.c | 8 +++++++-
>>  1 file changed, 7 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
>> index d370671..3642e6e 100644
>> --- a/drivers/media/dvb-frontends/lgdt3306a.c
>> +++ b/drivers/media/dvb-frontends/lgdt3306a.c
>> @@ -1768,7 +1768,13 @@ static void lgdt3306a_release(struct dvb_frontend *fe)
>>  	struct lgdt3306a_state *state = fe->demodulator_priv;
>>  
>>  	dbg_info("\n");
>> -	kfree(state);
>> +
>> +	/*
>> +	 * If state->muxc is not NULL, then we are an i2c device
>> +	 * and lgdt3306a_remove will clean up state
>> +	 */
>> +	if (!state->muxc)
>> +		kfree(state);
>>  }
>>  
>>  static const struct dvb_frontend_ops lgdt3306a_ops;
>>
diff mbox

Patch

diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
index d370671..3642e6e 100644
--- a/drivers/media/dvb-frontends/lgdt3306a.c
+++ b/drivers/media/dvb-frontends/lgdt3306a.c
@@ -1768,7 +1768,13 @@  static void lgdt3306a_release(struct dvb_frontend *fe)
 	struct lgdt3306a_state *state = fe->demodulator_priv;
 
 	dbg_info("\n");
-	kfree(state);
+
+	/*
+	 * If state->muxc is not NULL, then we are an i2c device
+	 * and lgdt3306a_remove will clean up state
+	 */
+	if (!state->muxc)
+		kfree(state);
 }
 
 static const struct dvb_frontend_ops lgdt3306a_ops;