Re: [PATCH v2 06/54] perf: Support get/put passthrough PMU interfaces

Zhang, Xiong Y
2024-05-08T04:54:40Z

On 5/7/2024 4:41 PM, Peter Zijlstra wrote:
> On Mon, May 06, 2024 at 05:29:31AM +0000, Mingwei Zhang wrote:
>
>> +int perf_get_mediated_pmu(void)
>> +{
>> + int ret = 0;
>> +
>> + mutex_lock(&perf_mediated_pmu_mutex);
>> + if (refcount_inc_not_zero(&nr_mediated_pmu_vms))
>> + goto end;
>> +
>> + if (atomic_read(&nr_include_guest_events)) {
>> + ret = -EBUSY;
>> + goto end;
>> + }
>> + refcount_set(&nr_mediated_pmu_vms, 1);
>> +end:
>> + mutex_unlock(&perf_mediated_pmu_mutex);
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(perf_get_mediated_pmu);
>> +
>> +void perf_put_mediated_pmu(void)
>> +{
>> + if (!refcount_dec_not_one(&nr_mediated_pmu_vms))
>> + refcount_set(&nr_mediated_pmu_vms, 0);
>
> I'm sorry, but this made the WTF'o'meter go 'ding'.
>
> Isn't that simply refcount_dec() ?
when nr_mediated_pmu_vms is 1, refcount_dec(&nr_mediated_pmu_vms) has an
error and call trace: refcount_t: decrement hit 0; leaking memory.

Similar when nr_mediated_pmu_vms is 0, refcount_inc(&nr_mediated_pmu_vms)
has an error and call trace also: refcount_t: addition on 0; use_after_free.

it seems refcount_set() should be used to set 1 or 0 to refcount_t.
>
>> +}
>> +EXPORT_SYMBOL_GPL(perf_put_mediated_pmu);
>> +
>> /*
>> * Holding the top-level event's child_mutex means that any
>> * descendant process that has inherited this event will block
>> @@ -12086,11 +12140,24 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
>> if (err)
>> goto err_callchain_buffer;
>>
>> + if (is_include_guest_event(event)) {
>> + mutex_lock(&perf_mediated_pmu_mutex);
>> + if (refcount_read(&nr_mediated_pmu_vms)) {
>> + mutex_unlock(&perf_mediated_pmu_mutex);
>> + err = -EACCES;
>> + goto err_security_alloc;
>> + }
>> + atomic_inc(&nr_include_guest_events);
>> + mutex_unlock(&perf_mediated_pmu_mutex);
>> + }
>
> Wouldn't all that be nicer with a helper function?
yes, it is nicer.

thanks
>
> if (is_include_guest_event() && !perf_get_guest_event())
> goto err_security_alloc;
>
>> +
>> /* symmetric to unaccount_event() in _free_event() */
>> account_event(event);
>>
>> return event;
>>
>> +err_security_alloc:
>> + security_perf_event_free(event);
>> err_callchain_buffer:
>> if (!event->parent) {
>> if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
>> --
>> 2.45.0.rc1.225.g2a3ae87e7f-goog
>>
>