diff mbox series

[1/1] coresight: prevent deactivate active config while enable the config

Message ID 20241218084833.609876-1-yeoreum.yun@arm.com (mailing list archive)
State New
Headers show
Series [1/1] coresight: prevent deactivate active config while enable the config | expand

Commit Message

Yeoreum Yun Dec. 18, 2024, 8:48 a.m. UTC
While enable active config via cscfg_csdev_enable_active_config(),
active config could be deactivated via configfs' sysfs interface.
This could make UAF issue in below scenario:

CPU0                                          CPU1
(perf or sysfs enable)                        load module
                                              cscfg_load_config_sets()
                                              activate config. // sysfs
                                              (sys_active_cnt == 1)
...
cscfg_csdev_enable_active_config()
  lock(csdev->cscfg_csdev_lock)
  // here load config activate by CPU1
  unlock(csdev->cscfg_csdev_lock)

                                              deactivate config // sysfs
                                              (sys_activec_cnt == 0)
                                              cscfg_unload_config_sets()
                                              unload module

  // access to config_desc which freed
  // while unloading module.
  cfs_csdev_enable_config

To address this, introduce sys_enable_cnt in cscfg_mgr to prevent
deactivate while there is enabled configuration.

Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
 .../hwtracing/coresight/coresight-etm4x-core.c |  3 +++
 drivers/hwtracing/coresight/coresight-syscfg.c | 18 ++++++++++++++++--
 drivers/hwtracing/coresight/coresight-syscfg.h |  2 ++
 3 files changed, 21 insertions(+), 2 deletions(-)

Comments

James Clark Dec. 23, 2024, 4:03 p.m. UTC | #1
On 18/12/2024 8:48 am, Yeoreum Yun wrote:
> While enable active config via cscfg_csdev_enable_active_config(),
> active config could be deactivated via configfs' sysfs interface.
> This could make UAF issue in below scenario:
> 
> CPU0                                          CPU1
> (perf or sysfs enable)                        load module
>                                                cscfg_load_config_sets()
>                                                activate config. // sysfs
>                                                (sys_active_cnt == 1)
> ...
> cscfg_csdev_enable_active_config()
>    lock(csdev->cscfg_csdev_lock)
>    // here load config activate by CPU1
>    unlock(csdev->cscfg_csdev_lock)
> 
>                                                deactivate config // sysfs
>                                                (sys_activec_cnt == 0)

Assuming the left side does Perf, are there some steps missing? To get 
to enable_active_config() you first need to pass through etm_setup_aux() 
-> cscfg_activate_config(). That would also increment sys_active_cnt 
which would leave it at 2 if there were two concurrent sessions. Then it 
would end up as 1 here after deactivate, rather than 0.

It's not explicitly mentioned in the sequence but I'm assuming the left 
and right are the same config, but I suppose it could be an issue with 
different configs too.

>                                                cscfg_unload_config_sets()
>                                                unload module

On the left cscfg_activate_config() also bumps the module refcount, so 
unload wouldn't cause a UAF here as far as I can see.

> 
>    // access to config_desc which freed
>    // while unloading module.
>    cfs_csdev_enable_config
> 
> To address this, introduce sys_enable_cnt in cscfg_mgr to prevent
> deactivate while there is enabled configuration.
> 
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
>   .../hwtracing/coresight/coresight-etm4x-core.c |  3 +++
>   drivers/hwtracing/coresight/coresight-syscfg.c | 18 ++++++++++++++++--
>   drivers/hwtracing/coresight/coresight-syscfg.h |  2 ++
>   3 files changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 86893115df17..6218ef40acbc 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -986,6 +986,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
>   	smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
>   
>   	raw_spin_unlock(&drvdata->spinlock);
> +
> +	cscfg_csdev_disable_active_config(csdev);
> +
>   	cpus_read_unlock();
>   
>   	/*
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> index a70c1454b410..dfa7dcbaf25d 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
>   			cscfg_mgr->sysfs_active_config = cfg_hash;
>   	} else {
>   		/* disable if matching current value */
> -		if (cscfg_mgr->sysfs_active_config == cfg_hash) {
> +		if (cscfg_mgr->sysfs_active_config == cfg_hash &&
> +		    !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
>   			_cscfg_deactivate_config(cfg_hash);

So is sys_enable_cnt a global value? If a fix is needed doesn't it need 
to be a per-config refcount?

Say you have two active configs, sys_enable_cnt is now 2, how do you 
disable one without it always skipping here when the other config is 
enabled?

>   			cscfg_mgr->sysfs_active_config = 0;
>   		} else
> @@ -1055,6 +1056,12 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>   	if (!atomic_read(&cscfg_mgr->sys_active_cnt))
>   		return 0;
>   
> +	/*
> +	 * increment sys_enable_cnt first to prevent deactivate the config
> +	 * while enable active config.
> +	 */
> +	atomic_inc(&cscfg_mgr->sys_enable_cnt);
> +
>   	/*
>   	 * Look for matching configuration - set the active configuration
>   	 * context if found.
> @@ -1098,6 +1105,10 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>   			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
>   		}
>   	}
> +
> +	if (!config_csdev_active || err)
> +		atomic_dec(&cscfg_mgr->sys_enable_cnt);
> +
>   	return err;
>   }
>   EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
> @@ -1129,8 +1140,10 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
>   	if (config_csdev) {
>   		if (!config_csdev->enabled)
>   			config_csdev = NULL;
> -		else
> +		else {
>   			config_csdev->enabled = false;
> +			atomic_dec(&cscfg_mgr->sys_enable_cnt);
> +		}
>   	}
>   	csdev->active_cscfg_ctxt = NULL;
>   	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
> @@ -1179,6 +1192,7 @@ static int cscfg_create_device(void)
>   	INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
>   	INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
>   	atomic_set(&cscfg_mgr->sys_active_cnt, 0);
> +	atomic_set(&cscfg_mgr->sys_enable_cnt, 0);
>   	cscfg_mgr->load_state = CSCFG_NONE;
>   
>   	/* setup the device */
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
> index 66e2db890d82..2fc397919985 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.h
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.h
> @@ -38,6 +38,7 @@ enum cscfg_load_ops {
>    * @config_desc_list:	List of system configuration descriptors to load into registered devices.
>    * @load_order_list:    Ordered list of owners for dynamically loaded configurations.
>    * @sys_active_cnt:	Total number of active config descriptor references.
> + * @sys_enable_cnt:	Total number of enable of active config descriptor references.

When these are next to each other it makes me wonder why active_cnt 
isn't enough to prevent unloading? Enabled is always a subset of active, 
so as long as you gate unloads or modifications on the existing active 
count it seems fine?

>    * @cfgfs_subsys:	configfs subsystem used to manage configurations.
>    * @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
>    * @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
> @@ -50,6 +51,7 @@ struct cscfg_manager {
>   	struct list_head config_desc_list;
>   	struct list_head load_order_list;
>   	atomic_t sys_active_cnt;
> +	atomic_t sys_enable_cnt;
>   	struct configfs_subsystem cfgfs_subsys;
>   	u32 sysfs_active_config;
>   	int sysfs_active_preset;
Yeoreum Yun Dec. 23, 2024, 6:29 p.m. UTC | #2
Hi James.
>
>
> On 18/12/2024 8:48 am, Yeoreum Yun wrote:
> > While enable active config via cscfg_csdev_enable_active_config(),
> > active config could be deactivated via configfs' sysfs interface.
> > This could make UAF issue in below scenario:
> >
> > CPU0                                          CPU1
> > (perf or sysfs enable)                        load module
> >                                                cscfg_load_config_sets()
> >                                                activate config. // sysfs
> >                                                (sys_active_cnt == 1)
> > ...
> > cscfg_csdev_enable_active_config()
> >    lock(csdev->cscfg_csdev_lock)
> >    // here load config activate by CPU1
> >    unlock(csdev->cscfg_csdev_lock)
> >
> >                                                deactivate config // sysfs
> >                                                (sys_activec_cnt == 0)
>
> Assuming the left side does Perf, are there some steps missing? To get to
> enable_active_config() you first need to pass through etm_setup_aux() ->
> cscfg_activate_config(). That would also increment sys_active_cnt which
> would leave it at 2 if there were two concurrent sessions. Then it would end
> up as 1 here after deactivate, rather than 0.
>
> It's not explicitly mentioned in the sequence but I'm assuming the left and
> right are the same config, but I suppose it could be an issue with different
> configs too.

Sorry! This happens only in sysfs mode. not perf.
I've forgotten update the diagram...

>
> >                                                cscfg_unload_config_sets()
> >                                                unload module
>
> On the left cscfg_activate_config() also bumps the module refcount, so
> unload wouldn't cause a UAF here as far as I can see.
>
In case of perf yes. However sysfs is done via configfs interface.
IOW, while cscfg_csdev_enable_active_config() iterating to find out the
config, it's possible to deactivate config via confis interface,
and unload moudle.

Above diagram explains this when coresight is configured with sysfs &
configfs interface NOT perf.
Sorry!


> >
> >    // access to config_desc which freed
> >    // while unloading module.
> >    cfs_csdev_enable_config
> >
> > To address this, introduce sys_enable_cnt in cscfg_mgr to prevent
> > deactivate while there is enabled configuration.
> >
> > Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> > ---
> >   .../hwtracing/coresight/coresight-etm4x-core.c |  3 +++
> >   drivers/hwtracing/coresight/coresight-syscfg.c | 18 ++++++++++++++++--
> >   drivers/hwtracing/coresight/coresight-syscfg.h |  2 ++
> >   3 files changed, 21 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > index 86893115df17..6218ef40acbc 100644
> > --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> > @@ -986,6 +986,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
> >   	smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
> >   	raw_spin_unlock(&drvdata->spinlock);
> > +
> > +	cscfg_csdev_disable_active_config(csdev);
> > +
> >   	cpus_read_unlock();
> >   	/*
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> > index a70c1454b410..dfa7dcbaf25d 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> > @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
> >   			cscfg_mgr->sysfs_active_config = cfg_hash;
> >   	} else {
> >   		/* disable if matching current value */
> > -		if (cscfg_mgr->sysfs_active_config == cfg_hash) {
> > +		if (cscfg_mgr->sysfs_active_config == cfg_hash &&
> > +		    !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
> >   			_cscfg_deactivate_config(cfg_hash);
>
> So is sys_enable_cnt a global value? If a fix is needed doesn't it need to
> be a per-config refcount?
>
> Say you have two active configs, sys_enable_cnt is now 2, how do you disable
> one without it always skipping here when the other config is enabled?
>
> >   			cscfg_mgr->sysfs_active_config = 0;
> >   		} else
> > @@ -1055,6 +1056,12 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
> >   	if (!atomic_read(&cscfg_mgr->sys_active_cnt))
> >   		return 0;
> > +	/*
> > +	 * increment sys_enable_cnt first to prevent deactivate the config
> > +	 * while enable active config.
> > +	 */
> > +	atomic_inc(&cscfg_mgr->sys_enable_cnt);
> > +
> >   	/*
> >   	 * Look for matching configuration - set the active configuration
> >   	 * context if found.
> > @@ -1098,6 +1105,10 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
> >   			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
> >   		}
> >   	}
> > +
> > +	if (!config_csdev_active || err)
> > +		atomic_dec(&cscfg_mgr->sys_enable_cnt);
> > +
> >   	return err;
> >   }
> >   EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
> > @@ -1129,8 +1140,10 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
> >   	if (config_csdev) {
> >   		if (!config_csdev->enabled)
> >   			config_csdev = NULL;
> > -		else
> > +		else {
> >   			config_csdev->enabled = false;
> > +			atomic_dec(&cscfg_mgr->sys_enable_cnt);
> > +		}
> >   	}
> >   	csdev->active_cscfg_ctxt = NULL;
> >   	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
> > @@ -1179,6 +1192,7 @@ static int cscfg_create_device(void)
> >   	INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
> >   	INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
> >   	atomic_set(&cscfg_mgr->sys_active_cnt, 0);
> > +	atomic_set(&cscfg_mgr->sys_enable_cnt, 0);
> >   	cscfg_mgr->load_state = CSCFG_NONE;
> >   	/* setup the device */
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
> > index 66e2db890d82..2fc397919985 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg.h
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg.h
> > @@ -38,6 +38,7 @@ enum cscfg_load_ops {
> >    * @config_desc_list:	List of system configuration descriptors to load into registered devices.
> >    * @load_order_list:    Ordered list of owners for dynamically loaded configurations.
> >    * @sys_active_cnt:	Total number of active config descriptor references.
> > + * @sys_enable_cnt:	Total number of enable of active config descriptor references.
>
> When these are next to each other it makes me wonder why active_cnt isn't
> enough to prevent unloading? Enabled is always a subset of active, so as
> long as you gate unloads or modifications on the existing active count it
> seems fine?
>
> >    * @cfgfs_subsys:	configfs subsystem used to manage configurations.
> >    * @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
> >    * @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
> > @@ -50,6 +51,7 @@ struct cscfg_manager {
> >   	struct list_head config_desc_list;
> >   	struct list_head load_order_list;
> >   	atomic_t sys_active_cnt;
> > +	atomic_t sys_enable_cnt;
> >   	struct configfs_subsystem cfgfs_subsys;
> >   	u32 sysfs_active_config;
> >   	int sysfs_active_preset;
>
Yeoreum Yun Dec. 24, 2024, 10:13 a.m. UTC | #3
Hi James.
> > diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> > index a70c1454b410..dfa7dcbaf25d 100644
> > --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> > +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> > @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
> >   			cscfg_mgr->sysfs_active_config = cfg_hash;
> >   	} else {
> >   		/* disable if matching current value */
> > -		if (cscfg_mgr->sysfs_active_config == cfg_hash) {
> > +		if (cscfg_mgr->sysfs_active_config == cfg_hash &&
> > +		    !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
> >   			_cscfg_deactivate_config(cfg_hash);
>
> So is sys_enable_cnt a global value? If a fix is needed doesn't it need to
> be a per-config refcount?
>
> Say you have two active configs, sys_enable_cnt is now 2, how do you disable
> one without it always skipping here when the other config is enabled?

Sorry to miss this one!.
Because when one configuration is enabled,
cscfg_mgr->sysfs_active_config becomes !NULL, so it wouldn't happen
there is no two activate configurations. so sys_enable_cnt wouldn't be
2.
James Clark Dec. 24, 2024, 11:41 a.m. UTC | #4
On 24/12/2024 10:13 am, Yeoreum Yun wrote:
> Hi James.
>>> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
>>> index a70c1454b410..dfa7dcbaf25d 100644
>>> --- a/drivers/hwtracing/coresight/coresight-syscfg.c
>>> +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
>>> @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
>>>    			cscfg_mgr->sysfs_active_config = cfg_hash;
>>>    	} else {
>>>    		/* disable if matching current value */
>>> -		if (cscfg_mgr->sysfs_active_config == cfg_hash) {
>>> +		if (cscfg_mgr->sysfs_active_config == cfg_hash &&
>>> +		    !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
>>>    			_cscfg_deactivate_config(cfg_hash);
>>
>> So is sys_enable_cnt a global value? If a fix is needed doesn't it need to
>> be a per-config refcount?
>>
>> Say you have two active configs, sys_enable_cnt is now 2, how do you disable
>> one without it always skipping here when the other config is enabled?
> 
> Sorry to miss this one!.
> Because when one configuration is enabled,
> cscfg_mgr->sysfs_active_config becomes !NULL, so it wouldn't happen
> there is no two activate configurations. so sys_enable_cnt wouldn't be
> 2.
> 
> 
> 

Maybe "sys_enabled" is a better name then. Count implies that it can be 
more than one. And the doc could be updated to say it's only ever 0 or 1.

But what about my other point about enabled always being a subset of 
active? Can we not change "sys_active_cnt" to a more generic "refcount", 
then both activation and enabling steps increment that same refcount, 
because they are both technically users of the config. Then you can 
solve the problem without adding another separate counter. I think 
that's potentially easier to understand.

Although the easiest is just locking every function with the mutex (or a 
spinlock if it also needs to be used from Perf). Obviously all these 
atomics are harder to get right than that, and this isn't performance 
sensitive in any way.
Yeoreum Yun Dec. 24, 2024, 1:07 p.m. UTC | #5
Hi James,

> > Hi James.
> > > > diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> > > > index a70c1454b410..dfa7dcbaf25d 100644
> > > > --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> > > > +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> > > > @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
> > > >    			cscfg_mgr->sysfs_active_config = cfg_hash;
> > > >    	} else {
> > > >    		/* disable if matching current value */
> > > > -		if (cscfg_mgr->sysfs_active_config == cfg_hash) {
> > > > +		if (cscfg_mgr->sysfs_active_config == cfg_hash &&
> > > > +		    !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
> > > >    			_cscfg_deactivate_config(cfg_hash);
> > >
> > > So is sys_enable_cnt a global value? If a fix is needed doesn't it need to
> > > be a per-config refcount?
> > >
> > > Say you have two active configs, sys_enable_cnt is now 2, how do you disable
> > > one without it always skipping here when the other config is enabled?
> >
> > Sorry to miss this one!.
> > Because when one configuration is enabled,
> > cscfg_mgr->sysfs_active_config becomes !NULL, so it wouldn't happen
> > there is no two activate configurations. so sys_enable_cnt wouldn't be
> > 2.
> >
> >
> >
>
> Maybe "sys_enabled" is a better name then. Count implies that it can be more
> than one. And the doc could be updated to say it's only ever 0 or 1.

I think I'm not fully explained. sys_enable_cnt could be more than 2
if it runs with perf and sysfs both.
Because, perf uses cscfg_active_config() to activate configuration.
but, "sysfs" only can activate 1 configuration because it enables with
cscfg_config_sysfs_activate(). so the sys_enable_cnt could be more than
However, sys_enable_cnt can be increased only 1 by sysfs interface.

Maybe It could be hinder to disable by enabled activated by the sysfs.
However, That's wouldn't be critical.

>
> But what about my other point about enabled always being a subset of active?
> Can we not change "sys_active_cnt" to a more generic "refcount", then both
> activation and enabling steps increment that same refcount, because they are
> both technically users of the config. Then you can solve the problem without
> adding another separate counter. I think that's potentially easier to
> understand.

Actually, I think merging this two count (or with module ref too),
seems increasing commplexity right now.
To make clear It would be good However to fix bug for above case,
I think it's enough to add sys_enable_cnt and I think it doesn't loss
its name meaning and it seems more to be backportable.

> Although the easiest is just locking every function with the mutex (or a
> spinlock if it also needs to be used from Perf). Obviously all these atomics
> are harder to get right than that, and this isn't performance sensitive in
> any way.

Agree, That's why there's one option to merge cscfg_mutex with
coresight_mutex. But I think this is too much to fix this problem.

Thanks.
Yeoreum Yun Dec. 31, 2024, 2:37 p.m. UTC | #6
Gentle ping in case of forgotten.
Suzuki K Poulose Jan. 6, 2025, 1:37 p.m. UTC | #7
Hi Yeo,


On 31/12/2024 14:37, Yeo Reum Yun wrote:
> Gentle ping in case of forgotten.
> 

Gentle reminder: Please avoid top posting.

I thought there is a v2 of this one ? I am now confused.

Kind regards
Suzuki

> ________________________________________
> From: Yeoreum Yun <yeoreum.yun@arm.com>
> Sent: 18 December 2024 08:48
> To: Suzuki Poulose; mike.leach@linaro.org; james.clark@linaro.org; alexander.shishkin@linux.intel.com
> Cc: coresight@lists.linaro.org; linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; nd; Yeo Reum Yun
> Subject: [PATCH 1/1] coresight: prevent deactivate active config while enable the config
> 
> While enable active config via cscfg_csdev_enable_active_config(),
> active config could be deactivated via configfs' sysfs interface.
> This could make UAF issue in below scenario:
> 
> CPU0                                          CPU1
> (perf or sysfs enable)                        load module
>                                                cscfg_load_config_sets()
>                                                activate config. // sysfs
>                                                (sys_active_cnt == 1)
> ...
> cscfg_csdev_enable_active_config()
>    lock(csdev->cscfg_csdev_lock)
>    // here load config activate by CPU1
>    unlock(csdev->cscfg_csdev_lock)
> 
>                                                deactivate config // sysfs
>                                                (sys_activec_cnt == 0)
>                                                cscfg_unload_config_sets()
>                                                unload module
> 
>    // access to config_desc which freed
>    // while unloading module.
>    cfs_csdev_enable_config
> 
> To address this, introduce sys_enable_cnt in cscfg_mgr to prevent
> deactivate while there is enabled configuration.
> 
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
>   .../hwtracing/coresight/coresight-etm4x-core.c |  3 +++
>   drivers/hwtracing/coresight/coresight-syscfg.c | 18 ++++++++++++++++--
>   drivers/hwtracing/coresight/coresight-syscfg.h |  2 ++
>   3 files changed, 21 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> index 86893115df17..6218ef40acbc 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
> @@ -986,6 +986,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
>          smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
> 
>          raw_spin_unlock(&drvdata->spinlock);
> +
> +       cscfg_csdev_disable_active_config(csdev);
> +
>          cpus_read_unlock();
> 
>          /*
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
> index a70c1454b410..dfa7dcbaf25d 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.c
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
> @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
>                          cscfg_mgr->sysfs_active_config = cfg_hash;
>          } else {
>                  /* disable if matching current value */
> -               if (cscfg_mgr->sysfs_active_config == cfg_hash) {
> +               if (cscfg_mgr->sysfs_active_config == cfg_hash &&
> +                   !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
>                          _cscfg_deactivate_config(cfg_hash);
>                          cscfg_mgr->sysfs_active_config = 0;
>                  } else
> @@ -1055,6 +1056,12 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>          if (!atomic_read(&cscfg_mgr->sys_active_cnt))
>                  return 0;
> 
> +       /*
> +        * increment sys_enable_cnt first to prevent deactivate the config
> +        * while enable active config.
> +        */
> +       atomic_inc(&cscfg_mgr->sys_enable_cnt);
> +
>          /*
>           * Look for matching configuration - set the active configuration
>           * context if found.
> @@ -1098,6 +1105,10 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>                          raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
>                  }
>          }
> +
> +       if (!config_csdev_active || err)
> +               atomic_dec(&cscfg_mgr->sys_enable_cnt);
> +
>          return err;
>   }
>   EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
> @@ -1129,8 +1140,10 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
>          if (config_csdev) {
>                  if (!config_csdev->enabled)
>                          config_csdev = NULL;
> -               else
> +               else {
>                          config_csdev->enabled = false;
> +                       atomic_dec(&cscfg_mgr->sys_enable_cnt);
> +               }
>          }
>          csdev->active_cscfg_ctxt = NULL;
>          raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
> @@ -1179,6 +1192,7 @@ static int cscfg_create_device(void)
>          INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
>          INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
>          atomic_set(&cscfg_mgr->sys_active_cnt, 0);
> +       atomic_set(&cscfg_mgr->sys_enable_cnt, 0);
>          cscfg_mgr->load_state = CSCFG_NONE;
> 
>          /* setup the device */
> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
> index 66e2db890d82..2fc397919985 100644
> --- a/drivers/hwtracing/coresight/coresight-syscfg.h
> +++ b/drivers/hwtracing/coresight/coresight-syscfg.h
> @@ -38,6 +38,7 @@ enum cscfg_load_ops {
>    * @config_desc_list:  List of system configuration descriptors to load into registered devices.
>    * @load_order_list:    Ordered list of owners for dynamically loaded configurations.
>    * @sys_active_cnt:    Total number of active config descriptor references.
> + * @sys_enable_cnt:    Total number of enable of active config descriptor references.
>    * @cfgfs_subsys:      configfs subsystem used to manage configurations.
>    * @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
>    * @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
> @@ -50,6 +51,7 @@ struct cscfg_manager {
>          struct list_head config_desc_list;
>          struct list_head load_order_list;
>          atomic_t sys_active_cnt;
> +       atomic_t sys_enable_cnt;
>          struct configfs_subsystem cfgfs_subsys;
>          u32 sysfs_active_config;
>          int sysfs_active_preset;
> --
> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>
Suzuki K Poulose Jan. 6, 2025, 3:23 p.m. UTC | #8
On 06/01/2025 13:41, Yeo Reum Yun wrote:
> Hi Suzuki,
> 
> Sorry this ping was my mistake.
> As you said, v2 is the recent one.
> You can ignore this.
> 

Thanks, will respond on v2.

Also, fyi, your emails not plain text ! Please fix your email client.

Suzuki


> Thanks!
> ------------------------------------------------------------------------
> *보낸 사람:* Suzuki K Poulose <suzuki.poulose@arm.com>
> *보낸 날짜:* Monday, January 6, 2025 1:37:40 PM
> *받는 사람:* Yeo Reum Yun <YeoReum.Yun@arm.com>; mike.leach@linaro.org 
> <mike.leach@linaro.org>; james.clark@linaro.org 
> <james.clark@linaro.org>; alexander.shishkin@linux.intel.com 
> <alexander.shishkin@linux.intel.com>
> *참조:* coresight@lists.linaro.org <coresight@lists.linaro.org>; linux- 
> arm-kernel@lists.infradead.org <linux-arm-kernel@lists.infradead.org>; 
> linux-kernel@vger.kernel.org <linux-kernel@vger.kernel.org>; nd <nd@arm.com>
> *제목:* Re: [PATCH 1/1] coresight: prevent deactivate active config 
> while enable the config
> Hi Yeo,
> 
> 
> On 31/12/2024 14:37, Yeo Reum Yun wrote:
>> Gentle ping in case of forgotten.
>> 
> 
> Gentle reminder: Please avoid top posting.
> 
> I thought there is a v2 of this one ? I am now confused.
> 
> Kind regards
> Suzuki
> 
>> ________________________________________
>> From: Yeoreum Yun <yeoreum.yun@arm.com>
>> Sent: 18 December 2024 08:48
>> To: Suzuki Poulose; mike.leach@linaro.org; james.clark@linaro.org; alexander.shishkin@linux.intel.com
>> Cc: coresight@lists.linaro.org; linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; nd; Yeo Reum Yun
>> Subject: [PATCH 1/1] coresight: prevent deactivate active config while enable the config
>> 
>> While enable active config via cscfg_csdev_enable_active_config(),
>> active config could be deactivated via configfs' sysfs interface.
>> This could make UAF issue in below scenario:
>> 
>> CPU0                                          CPU1
>> (perf or sysfs enable)                        load module
>>                                                cscfg_load_config_sets()
>>                                                activate config. // sysfs
>>                                                (sys_active_cnt == 1)
>> ...
>> cscfg_csdev_enable_active_config()
>>    lock(csdev->cscfg_csdev_lock)
>>    // here load config activate by CPU1
>>    unlock(csdev->cscfg_csdev_lock)
>> 
>>                                                deactivate config // sysfs
>>                                                (sys_activec_cnt == 0)
>>                                                cscfg_unload_config_sets()
>>                                                unload module
>> 
>>    // access to config_desc which freed
>>    // while unloading module.
>>    cfs_csdev_enable_config
>> 
>> To address this, introduce sys_enable_cnt in cscfg_mgr to prevent
>> deactivate while there is enabled configuration.
>> 
>> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
>> ---
>>   .../hwtracing/coresight/coresight-etm4x-core.c |  3 +++
>>   drivers/hwtracing/coresight/coresight-syscfg.c | 18 ++++++++++++++++--
>>   drivers/hwtracing/coresight/coresight-syscfg.h |  2 ++
>>   3 files changed, 21 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> index 86893115df17..6218ef40acbc 100644
>> --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
>> @@ -986,6 +986,9 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
>>          smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
>> 
>>          raw_spin_unlock(&drvdata->spinlock);
>> +
>> +       cscfg_csdev_disable_active_config(csdev);
>> +
>>          cpus_read_unlock();
>> 
>>          /*
>> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
>> index a70c1454b410..dfa7dcbaf25d 100644
>> --- a/drivers/hwtracing/coresight/coresight-syscfg.c
>> +++ b/drivers/hwtracing/coresight/coresight-syscfg.c
>> @@ -953,7 +953,8 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
>>                          cscfg_mgr->sysfs_active_config = cfg_hash;
>>          } else {
>>                  /* disable if matching current value */
>> -               if (cscfg_mgr->sysfs_active_config == cfg_hash) {
>> +               if (cscfg_mgr->sysfs_active_config == cfg_hash &&
>> +                   !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
>>                          _cscfg_deactivate_config(cfg_hash);
>>                          cscfg_mgr->sysfs_active_config = 0;
>>                  } else
>> @@ -1055,6 +1056,12 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>>          if (!atomic_read(&cscfg_mgr->sys_active_cnt))
>>                  return 0;
>> 
>> +       /*
>> +        * increment sys_enable_cnt first to prevent deactivate the config
>> +        * while enable active config.
>> +        */
>> +       atomic_inc(&cscfg_mgr->sys_enable_cnt);
>> +
>>          /*
>>           * Look for matching configuration - set the active configuration
>>           * context if found.
>> @@ -1098,6 +1105,10 @@ int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
>>                          raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
>>                  }
>>          }
>> +
>> +       if (!config_csdev_active || err)
>> +               atomic_dec(&cscfg_mgr->sys_enable_cnt);
>> +
>>          return err;
>>   }
>>   EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
>> @@ -1129,8 +1140,10 @@ void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
>>          if (config_csdev) {
>>                  if (!config_csdev->enabled)
>>                          config_csdev = NULL;
>> -               else
>> +               else {
>>                          config_csdev->enabled = false;
>> +                       atomic_dec(&cscfg_mgr->sys_enable_cnt);
>> +               }
>>          }
>>          csdev->active_cscfg_ctxt = NULL;
>>          raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
>> @@ -1179,6 +1192,7 @@ static int cscfg_create_device(void)
>>          INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
>>          INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
>>          atomic_set(&cscfg_mgr->sys_active_cnt, 0);
>> +       atomic_set(&cscfg_mgr->sys_enable_cnt, 0);
>>          cscfg_mgr->load_state = CSCFG_NONE;
>> 
>>          /* setup the device */
>> diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
>> index 66e2db890d82..2fc397919985 100644
>> --- a/drivers/hwtracing/coresight/coresight-syscfg.h
>> +++ b/drivers/hwtracing/coresight/coresight-syscfg.h
>> @@ -38,6 +38,7 @@ enum cscfg_load_ops {
>>    * @config_desc_list:  List of system configuration descriptors to load into registered devices.
>>    * @load_order_list:    Ordered list of owners for dynamically loaded configurations.
>>    * @sys_active_cnt:    Total number of active config descriptor references.
>> + * @sys_enable_cnt:    Total number of enable of active config descriptor references.
>>    * @cfgfs_subsys:      configfs subsystem used to manage configurations.
>>    * @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
>>    * @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
>> @@ -50,6 +51,7 @@ struct cscfg_manager {
>>          struct list_head config_desc_list;
>>          struct list_head load_order_list;
>>          atomic_t sys_active_cnt;
>> +       atomic_t sys_enable_cnt;
>>          struct configfs_subsystem cfgfs_subsys;
>>          u32 sysfs_active_config;
>>          int sysfs_active_preset;
>> --
>> LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
>> 
>
diff mbox series

Patch

diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 86893115df17..6218ef40acbc 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -986,6 +986,9 @@  static void etm4_disable_sysfs(struct coresight_device *csdev)
 	smp_call_function_single(drvdata->cpu, etm4_disable_hw, drvdata, 1);
 
 	raw_spin_unlock(&drvdata->spinlock);
+
+	cscfg_csdev_disable_active_config(csdev);
+
 	cpus_read_unlock();
 
 	/*
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index a70c1454b410..dfa7dcbaf25d 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -953,7 +953,8 @@  int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
 			cscfg_mgr->sysfs_active_config = cfg_hash;
 	} else {
 		/* disable if matching current value */
-		if (cscfg_mgr->sysfs_active_config == cfg_hash) {
+		if (cscfg_mgr->sysfs_active_config == cfg_hash &&
+		    !atomic_read(&cscfg_mgr->sys_enable_cnt)) {
 			_cscfg_deactivate_config(cfg_hash);
 			cscfg_mgr->sysfs_active_config = 0;
 		} else
@@ -1055,6 +1056,12 @@  int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 	if (!atomic_read(&cscfg_mgr->sys_active_cnt))
 		return 0;
 
+	/*
+	 * increment sys_enable_cnt first to prevent deactivate the config
+	 * while enable active config.
+	 */
+	atomic_inc(&cscfg_mgr->sys_enable_cnt);
+
 	/*
 	 * Look for matching configuration - set the active configuration
 	 * context if found.
@@ -1098,6 +1105,10 @@  int cscfg_csdev_enable_active_config(struct coresight_device *csdev,
 			raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
 		}
 	}
+
+	if (!config_csdev_active || err)
+		atomic_dec(&cscfg_mgr->sys_enable_cnt);
+
 	return err;
 }
 EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config);
@@ -1129,8 +1140,10 @@  void cscfg_csdev_disable_active_config(struct coresight_device *csdev)
 	if (config_csdev) {
 		if (!config_csdev->enabled)
 			config_csdev = NULL;
-		else
+		else {
 			config_csdev->enabled = false;
+			atomic_dec(&cscfg_mgr->sys_enable_cnt);
+		}
 	}
 	csdev->active_cscfg_ctxt = NULL;
 	raw_spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags);
@@ -1179,6 +1192,7 @@  static int cscfg_create_device(void)
 	INIT_LIST_HEAD(&cscfg_mgr->config_desc_list);
 	INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
 	atomic_set(&cscfg_mgr->sys_active_cnt, 0);
+	atomic_set(&cscfg_mgr->sys_enable_cnt, 0);
 	cscfg_mgr->load_state = CSCFG_NONE;
 
 	/* setup the device */
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
index 66e2db890d82..2fc397919985 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.h
+++ b/drivers/hwtracing/coresight/coresight-syscfg.h
@@ -38,6 +38,7 @@  enum cscfg_load_ops {
  * @config_desc_list:	List of system configuration descriptors to load into registered devices.
  * @load_order_list:    Ordered list of owners for dynamically loaded configurations.
  * @sys_active_cnt:	Total number of active config descriptor references.
+ * @sys_enable_cnt:	Total number of enable of active config descriptor references.
  * @cfgfs_subsys:	configfs subsystem used to manage configurations.
  * @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
  * @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
@@ -50,6 +51,7 @@  struct cscfg_manager {
 	struct list_head config_desc_list;
 	struct list_head load_order_list;
 	atomic_t sys_active_cnt;
+	atomic_t sys_enable_cnt;
 	struct configfs_subsystem cfgfs_subsys;
 	u32 sysfs_active_config;
 	int sysfs_active_preset;