VYPR
Moderate severityNVD Advisory· Published Jan 29, 2021· Updated Aug 3, 2024

CVE-2021-26307

CVE-2021-26307

Description

An issue was discovered in the raw-cpuid crate before 9.0.0 for Rust. It allows __cpuid_count() calls even if the processor does not support the CPUID instruction, which is unsound and causes a deterministic crash.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The raw-cpuid crate before 9.0.0 allows __cpuid_count() calls on processors without CPUID support, causing a deterministic crash.

The raw-cpuid crate for Rust provides access to the CPUID instruction. Before version 9.0.0, it allowed calling __cpuid_count() even when the processor does not support the CPUID instruction. This is unsound because executing CPUID on such processors triggers an illegal instruction exception, leading to a deterministic crash [1][2][4].

The vulnerability is triggered by any code using the raw-cpuid crate to query CPU features on a processor lacking CPUID support. No special privileges are required; the crash occurs at runtime when __cpuid_count() is invoked. The attack surface is limited to systems where the crate is used and the processor does not support CPUID, which is rare for modern x86/x86_64 systems but possible in emulated or legacy environments [2][4].

An attacker who can cause the vulnerable code to run on such a processor can achieve a denial-of-service (DoS) via a crash. The RustSec advisory also notes additional soundness issues in the crate (e.g., undefined behavior in as_string() methods), but the primary issue for this CVE is the unsound CPUID call [4].

The issue is fixed in version 9.0.0 of the raw-cpuid crate. Users should update to the latest version. The fix ensures that __cpuid_count() is only called when the processor supports CPUID, and also addresses other soundness issues by making structs #[repr(C)] and using safe slice construction [1][3][4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
raw-cpuidcrates.io
< 9.0.09.0.0

Affected products

2

Patches

1
91b676eecd01

Fix unsound transmutes (fixes #40)

https://github.com/gz/rust-cpuidNiklas FiekasJan 17, 2021via ghsa
1 file changed · +22 21
  • src/lib.rs+22 21 modified
    @@ -60,7 +60,7 @@ pub mod native_cpuid {
     
     use core::cmp::min;
     use core::fmt;
    -use core::mem::transmute;
    +use core::mem::size_of;
     use core::slice;
     use core::str;
     
    @@ -137,6 +137,7 @@ pub struct CpuId {
     /// Low-level data-structure to store result of cpuid instruction.
     #[derive(Copy, Clone, Debug, Default)]
     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
    +#[repr(C)]
     pub struct CpuIdResult {
         /// Return value EAX register
         pub eax: u32,
    @@ -585,6 +586,7 @@ impl CpuId {
     
     #[derive(Debug, Default)]
     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
    +#[repr(C)]
     pub struct VendorInfo {
         ebx: u32,
         edx: u32,
    @@ -594,11 +596,12 @@ pub struct VendorInfo {
     impl VendorInfo {
         /// Return vendor identification as human readable string.
         pub fn as_string<'a>(&'a self) -> &'a str {
    +        let brand_string_start = self as *const VendorInfo as *const u8;
             unsafe {
    -            let brand_string_start = self as *const VendorInfo as *const u8;
    -            let slice = slice::from_raw_parts(brand_string_start, 3 * 4);
    -            let byte_array: &'a [u8] = transmute(slice);
    -            str::from_utf8_unchecked(byte_array)
    +            // Safety: VendorInfo is laid out with repr(C).
    +            let slice: &'a [u8] = slice::from_raw_parts(brand_string_start, size_of::<VendorInfo>());
    +            // Safety: The field is specified to be ASCII.
    +            str::from_utf8_unchecked(slice)
             }
         }
     }
    @@ -4027,19 +4030,19 @@ impl Iterator for SoCVendorAttributesIter {
     
     #[derive(Debug, Default)]
     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
    +#[repr(C)]
     pub struct SoCVendorBrand {
    -    #[allow(dead_code)]
         data: [CpuIdResult; 3],
     }
     
     impl SoCVendorBrand {
         pub fn as_string<'a>(&'a self) -> &'a str {
    +        let brand_string_start = self as *const SoCVendorBrand as *const u8;
             unsafe {
    -            let brand_string_start = self as *const SoCVendorBrand as *const u8;
    -            let slice =
    -                slice::from_raw_parts(brand_string_start, core::mem::size_of::<SoCVendorBrand>());
    -            let byte_array: &'a [u8] = transmute(slice);
    -            str::from_utf8_unchecked(byte_array)
    +            // Safety: SoCVendorBrand is laid out with repr(C).
    +            let slice: &'a [u8] = slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>());
    +            // Safety: The field is specified to be ASCII.
    +            str::from_utf8_unchecked(slice)
             }
         }
     }
    @@ -4152,18 +4155,16 @@ impl ExtendedFunctionInfo {
         /// Retrieve processor brand string.
         pub fn processor_brand_string<'a>(&'a self) -> Option<&'a str> {
             if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING) {
    -            Some(unsafe {
    -                let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8;
    -                let mut slice = slice::from_raw_parts(brand_string_start, 3 * 4 * 4);
    +            let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8;
    +            // Safety: CpuIdResult is laid out with repr(C), and the array
    +            // self.data contains 9 continguous elements.
    +            let slice: &'a [u8] = unsafe { slice::from_raw_parts(brand_string_start, 3 * size_of::<CpuIdResult>()) };
     
    -                match slice.iter().position(|&x| x == 0) {
    -                    Some(index) => slice = slice::from_raw_parts(brand_string_start, index),
    -                    None => (),
    -                }
    +            // Brand terminated at nul byte or end, whichever comes first.
    +            let slice = slice.split(|&x| x == 0).next().unwrap();
     
    -                let byte_array: &'a [u8] = transmute(slice);
    -                str::from_utf8_unchecked(byte_array)
    -            })
    +            // Safety: Field is specified to be ASCII.
    +            Some(unsafe { str::from_utf8_unchecked(slice) })
             } else {
                 None
             }
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.