lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ