All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mirsad Todorovac <mtodorovac69@gmail.com>
To: Sean Christopherson <seanjc@google.com>
Cc: kvm@vger.kernel.org, Paolo Bonzini <pbonzini@redhat.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
	linux-kernel@vger.kernel.org, Like Xu <likexu@tencent.com>
Subject: Re: [BUG] arch/x86/kvm/vmx/pmu_intel.c:54: error: dereference of NULL ‘pmc’ [CWE-476]
Date: Fri, 19 Jul 2024 21:02:01 +0200	[thread overview]
Message-ID: <70137930-fea1-4d45-b453-e6ae984c4b2b@gmail.com> (raw)
In-Reply-To: <ZpqgfETiBXfBfFqU@google.com>



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

  reply	other threads:[~2024-07-19 19:02 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-19 16:49 [BUG] arch/x86/kvm/vmx/pmu_intel.c:54: error: dereference of NULL ‘pmc’ [CWE-476] Mirsad Todorovac
2024-07-19 17:21 ` Sean Christopherson
2024-07-19 19:02   ` Mirsad Todorovac [this message]
2024-07-19 19:22     ` Sean Christopherson
2024-07-19 19:41       ` Mirsad Todorovac
2024-07-19 20:14         ` Jim Mattson
2024-07-22 13:44           ` Mirsad Todorovac

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=70137930-fea1-4d45-b453-e6ae984c4b2b@gmail.com \
    --to=mtodorovac69@gmail.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=kvm@vger.kernel.org \
    --cc=likexu@tencent.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=tglx@linutronix.de \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.