[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <70137930-fea1-4d45-b453-e6ae984c4b2b@gmail.com>
Date: Fri, 19 Jul 2024 21:02:01 +0200
From: Mirsad Todorovac <mtodorovac69@...il.com>
To: Sean Christopherson <seanjc@...gle.com>
Cc: kvm@...r.kernel.org, Paolo Bonzini <pbonzini@...hat.com>,
Thomas Gleixner <tglx@...utronix.de>, Ingo Molnar <mingo@...hat.com>,
Borislav Petkov <bp@...en8.de>, Dave Hansen <dave.hansen@...ux.intel.com>,
x86@...nel.org, "H. Peter Anvin" <hpa@...or.com>,
linux-kernel@...r.kernel.org, Like Xu <likexu@...cent.com>
Subject: Re: [BUG] arch/x86/kvm/vmx/pmu_intel.c:54: error: dereference of NULL ‘pmc’ [CWE-476]
On 7/19/24 19:21, Sean Christopherson wrote:
> On Fri, Jul 19, 2024, Mirsad Todorovac wrote:
>> Hi,
>>
>> In the build of 6.10.0 from stable tree, the following error was detected.
>>
>> You see that the function get_fixed_pmc() can return NULL pointer as a result
>> if msr is outside of [base, base + pmu->nr_arch_fixed_counters) interval.
>>
>> kvm_pmu_request_counter_reprogram(pmc) is then called with that NULL pointer
>> as the argument, which expands to .../pmu.h
>>
>> #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
>>
>> which is a NULL pointer dereference in that speculative case.
>
> I'm somewhat confused. Did you actually hit a BUG() due to a NULL-pointer
> dereference, are you speculating that there's a bug, or did you find some speculation
> issue with the CPU?
>
> It should be impossible for get_fixed_pmc() to return NULL in this case. The
> loop iteration is fully controlled by KVM, i.e. 'i' is guaranteed to be in the
> ranage [0..pmu->nr_arch_fixed_counters).
>
> And the input @msr is "MSR_CORE_PERF_FIXED_CTR0 +i", so the if-statement expands to:
>
> if (MSR_CORE_PERF_FIXED_CTR0 + [0..pmu->nr_arch_fixed_counters) >= MSR_CORE_PERF_FIXED_CTR0 &&
> MSR_CORE_PERF_FIXED_CTR0 + [0..pmu->nr_arch_fixed_counters) < MSR_CORE_PERF_FIXED_CTR0 + pmu->nr_arch_fixed_counters)
>
> i.e. is guaranteed to evaluate true.
>
> Am I missing something?
Hi Sean,
Thank you for replying promptly.
Perhaps I should have provided the GCC error report in the first place. It seems that GCC 12.3.0
cannot track dependencies that deep, so it assumes that code
157 if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
158 u32 index = array_index_nospec(msr - base,
159 pmu->nr_arch_fixed_counters);
160
161 return &pmu->fixed_counters[index];
162 }
163
164 return NULL;
can end up returning NULL, resulting in NULL pointer dereference.
The analyzer sees pmu->nr_arch_fixed_counters, but I am not sure that GCC can search
changes that deep.
Maybe if clause in arch/x86/kvm/vmx/../pmu.h:157 is always true, but GCC cannot see that?
Best regards,
Mirsad Todorovac
---------------------------------------------------------------------------------------
In file included from arch/x86/kvm/vmx/capabilities.h:9,
from arch/x86/kvm/vmx/vmcs.h:12,
from arch/x86/kvm/vmx/vmcs12.h:7,
from arch/x86/kvm/vmx/hyperv.h:6,
from arch/x86/kvm/vmx/nested.h:6,
from arch/x86/kvm/vmx/pmu_intel.c:20:
arch/x86/kvm/vmx/../pmu.h: In function ‘kvm_pmu_request_counter_reprogram’:
arch/x86/kvm/vmx/../pmu.h:11:34: error: dereference of NULL ‘pmc’ [CWE-476] [-Werror=analyzer-null-dereference]
11 | #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
| ~~~~~^~~~~~
arch/x86/kvm/vmx/../pmu.h:230:27: note: in expansion of macro ‘pmc_to_pmu’
230 | set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi);
| ^~~~~~~~~~
‘reprogram_fixed_counters’: events 1-4
|
|arch/x86/kvm/vmx/pmu_intel.c:37:13:
| 37 | static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
| | ^~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (1) entry to ‘reprogram_fixed_counters’
|......
| 44 | for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) following ‘true’ branch...
| 45 | u8 new_ctrl = fixed_ctrl_field(data, i);
| | ~~ ~~~~~~~~
| | | |
| | | (4) following ‘false’ branch...
| | (3) ...to here
|
‘reprogram_fixed_counters’: event 5
|
|arch/x86/kvm/vmx/../pmu.h:17:54:
| 17 | #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
| | ^~
| | |
| | (5) ...to here
arch/x86/kvm/vmx/pmu_intel.c:45:31: note: in expansion of macro ‘fixed_ctrl_field’
| 45 | u8 new_ctrl = fixed_ctrl_field(data, i);
| | ^~~~~~~~~~~~~~~~
|
‘reprogram_fixed_counters’: event 6
|
| 46 | u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
| | ^~~~~~~~
| | |
| | (6) following ‘false’ branch...
|
‘reprogram_fixed_counters’: event 7
|
|arch/x86/kvm/vmx/../pmu.h:17:54:
| 17 | #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf)
| | ^~
| | |
| | (7) ...to here
arch/x86/kvm/vmx/pmu_intel.c:46:31: note: in expansion of macro ‘fixed_ctrl_field’
| 46 | u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
| | ^~~~~~~~~~~~~~~~
|
‘reprogram_fixed_counters’: events 8-9
|
| 48 | if (old_ctrl == new_ctrl)
| | ^
| | |
| | (8) following ‘false’ branch...
|......
| 51 | pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i);
| | ~~~
| | |
| | (9) ...to here
|
‘reprogram_fixed_counters’: events 10-12
|
|arch/x86/kvm/vmx/../pmu.h:157:12:
| 157 | if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | | | |
| | | | (11) ...to here
| | | (12) following ‘false’ branch...
| | (10) following ‘true’ branch...
|
‘reprogram_fixed_counters’: events 13-14
|
|arch/x86/kvm/vmx/pmu_intel.c:51:23:
| 51 | pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i);
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (13) ...to here
|......
| 54 | kvm_pmu_request_counter_reprogram(pmc);
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (14) calling ‘kvm_pmu_request_counter_reprogram’ from ‘reprogram_fixed_counters’
|
+--> ‘kvm_pmu_request_counter_reprogram’: event 15
|
|arch/x86/kvm/vmx/../pmu.h:228:20:
| 228 | static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc)
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (15) entry to ‘kvm_pmu_request_counter_reprogram’
|
‘kvm_pmu_request_counter_reprogram’: event 16
|
| 11 | #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
| | ~~~~~^~~~~~
| | |
| | (16) dereference of NULL ‘pmc’
arch/x86/kvm/vmx/../pmu.h:230:27: note: in expansion of macro ‘pmc_to_pmu’
| 230 | set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi);
| | ^~~~~~~~~~
|
cc1: all warnings being treated as errors
>> arch/x86/kvm/vmx/pmu_intel.c
>> ----------------------------
>> 37 static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
>> 38 {
>> 39 struct kvm_pmc *pmc;
>> 40 u64 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl;
>> 41 int i;
>> 42
>> 43 pmu->fixed_ctr_ctrl = data;
>> 44 for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
>> 45 u8 new_ctrl = fixed_ctrl_field(data, i);
>> 46 u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);
>> 47
>> 48 if (old_ctrl == new_ctrl)
>> 49 continue;
>> 50
>> 51 → pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i);
>> 52
>> 53 __set_bit(KVM_FIXED_PMC_BASE_IDX + i, pmu->pmc_in_use);
>> 54 → kvm_pmu_request_counter_reprogram(pmc);
>> 55 }
>> 56 }
>> ----------------------------
>>
>> arch/x86/kvm/vmx/../pmu.h
>> -------------------------
>> 11 #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
>> .
>> .
>> .
>> 152 /* returns fixed PMC with the specified MSR */
>> 153 static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
>> 154 {
>> 155 int base = MSR_CORE_PERF_FIXED_CTR0;
>> 156
>> 157 if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
>> 158 u32 index = array_index_nospec(msr - base,
>> 159 pmu->nr_arch_fixed_counters);
>> 160
>> 161 return &pmu->fixed_counters[index];
>> 162 }
>> 163
>> 164 return NULL;
>> 165 }
>> .
>> .
>> .
>> 228 static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc)
>> 229 {
>> 230 set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi);
>> 231 kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
>> 232 }
>> .
>> .
>> .
>> -------------------------
>> 76d287b2342e1
>> Offending commits are: 76d287b2342e1 and 4fa5843d81fdc.
>>
>> I am not familiar with this subset of code, so I do not know the right code to implement
>> for the case get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i) returns NULL.
>>
>> Hope this helps.
>>
>> Best regards,
>> Mirsad Todorovac
Powered by blists - more mailing lists