VYPR
Critical severityNVD Advisory· Published Aug 8, 2021· Updated Aug 4, 2024

CVE-2021-38190

CVE-2021-38190

Description

The nalgebra crate before 0.27.1 allows out-of-bounds memory access via crafted deserialization of VecStorage due to missing length invariant check.

AI Insight

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

The nalgebra crate before 0.27.1 allows out-of-bounds memory access via crafted deserialization of VecStorage due to missing length invariant check.

Vulnerability

The nalgebra crate for Rust, prior to version 0.27.1, contains a vulnerability in the VecStorage type's Deserialize implementation. The deserialization logic did not enforce the invariant that the number of stored elements must equal the product of the row count and column count (nrows * ncols). This flaw was introduced in version 0.11.0 and persisted through 0.27.0 [4]. The official description confirms that this allows out-of-bounds memory access [3].

Exploitation

An attacker can craft a serialized matrix (e.g., via serde) where the number of elements in the underlying vector does not match the declared dimensions. When the matrix is deserialized, the VecStorage will be constructed with an inconsistent state, leading to out-of-bounds reads or writes when the matrix is subsequently accessed. No special privileges are required; exploitation depends on the application deserializing untrusted data [2][4].

Impact

Successful exploitation can result in out-of-bounds memory access, potentially leading to memory corruption or information disclosure. The RustSec advisory categorizes this as a memory-corruption and memory-exposure vulnerability [4].

Mitigation

The issue is fixed in nalgebra version 0.27.1 [4]. Users should update to at least 0.27.1. Versions prior to 0.11.0 are unaffected. No workaround is available for affected versions; upgrading is the recommended mitigation [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
nalgebracrates.io
>= 0.11.0, < 0.27.10.27.1

Affected products

2

Patches

1
a803271fcce7

Merge pull request #889 from dimforge/dvector_deserialize

https://github.com/dimforge/nalgebraSébastien CrozetMay 9, 2021via ghsa
2 files changed · +76 3
  • src/base/vec_storage.rs+48 1 modified
    @@ -13,6 +13,12 @@ use crate::base::storage::{
     };
     use crate::base::{Scalar, Vector};
     
    +#[cfg(feature = "serde-serialize-no-std")]
    +use serde::{
    +    de::{Deserialize, Deserializer, Error},
    +    ser::{Serialize, Serializer},
    +};
    +
     #[cfg(feature = "abomonation-serialize")]
     use abomonation::Abomonation;
     
    @@ -24,13 +30,54 @@ use abomonation::Abomonation;
     /// A Vec-based matrix data storage. It may be dynamically-sized.
     #[repr(C)]
     #[derive(Eq, Debug, Clone, PartialEq)]
    -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
     pub struct VecStorage<T, R: Dim, C: Dim> {
         data: Vec<T>,
         nrows: R,
         ncols: C,
     }
     
    +#[cfg(feature = "serde-serialize")]
    +impl<T, R: Dim, C: Dim> Serialize for VecStorage<T, R, C>
    +where
    +    T: Serialize,
    +    R: Serialize,
    +    C: Serialize,
    +{
    +    fn serialize<Ser>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>
    +    where
    +        Ser: Serializer,
    +    {
    +        (&self.data, &self.nrows, &self.ncols).serialize(serializer)
    +    }
    +}
    +
    +#[cfg(feature = "serde-serialize")]
    +impl<'a, T, R: Dim, C: Dim> Deserialize<'a> for VecStorage<T, R, C>
    +where
    +    T: Deserialize<'a>,
    +    R: Deserialize<'a>,
    +    C: Deserialize<'a>,
    +{
    +    fn deserialize<Des>(deserializer: Des) -> Result<Self, Des::Error>
    +    where
    +        Des: Deserializer<'a>,
    +    {
    +        let (data, nrows, ncols): (Vec<T>, R, C) = Deserialize::deserialize(deserializer)?;
    +
    +        // SAFETY: make sure the data we deserialize have the
    +        //         correct number of elements.
    +        if nrows.value() * ncols.value() != data.len() {
    +            return Err(Des::Error::custom(format!(
    +                "Expected {} components, found {}",
    +                nrows.value() * ncols.value(),
    +                data.len()
    +            )));
    +        }
    +
    +        Ok(Self { data, nrows, ncols })
    +    }
    +}
    +
     #[deprecated(note = "renamed to `VecStorage`")]
     /// Renamed to [VecStorage].
     pub type MatrixVec<T, R, C> = VecStorage<T, R, C>;
    
  • tests/core/serde.rs+28 2 modified
    @@ -1,8 +1,8 @@
     #![cfg(feature = "serde-serialize")]
     
     use na::{
    -    DMatrix, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix3x4, Point2, Point3,
    -    Quaternion, Rotation2, Rotation3, Similarity2, Similarity3, SimilarityMatrix2,
    +    DMatrix, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix2x3, Matrix3x4, Point2,
    +    Point3, Quaternion, Rotation2, Rotation3, Similarity2, Similarity3, SimilarityMatrix2,
         SimilarityMatrix3, Translation2, Translation3, Unit, Vector2,
     };
     use rand;
    @@ -27,6 +27,32 @@ fn serde_dmatrix() {
         let serialized = serde_json::to_string(&v).unwrap();
         let deserialized: DMatrix<f32> = serde_json::from_str(&serialized).unwrap();
         assert_eq!(v, deserialized);
    +
    +    let m = DMatrix::from_column_slice(2, 3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
    +    let mat_str = "[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0],2,3]";
    +    let deserialized: DMatrix<f32> = serde_json::from_str(&mat_str).unwrap();
    +    assert_eq!(m, deserialized);
    +
    +    let m = Matrix2x3::from_column_slice(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
    +    let mat_str = "[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]";
    +    let deserialized: Matrix2x3<f32> = serde_json::from_str(&mat_str).unwrap();
    +    assert_eq!(m, deserialized);
    +}
    +
    +#[test]
    +#[should_panic]
    +fn serde_dmatrix_invalid_len() {
    +    // This must fail: we attempt to deserialize a 2x3 with only 5 elements.
    +    let mat_str = "[[1.0, 2.0, 3.0, 4.0, 5.0],2,3]";
    +    let _: DMatrix<f32> = serde_json::from_str(&mat_str).unwrap();
    +}
    +
    +#[test]
    +#[should_panic]
    +fn serde_smatrix_invalid_len() {
    +    // This must fail: we attempt to deserialize a 2x3 with only 5 elements.
    +    let mat_str = "[1.0, 2.0, 3.0, 4.0, 5.0]";
    +    let _: Matrix2x3<f32> = serde_json::from_str(&mat_str).unwrap();
     }
     
     test_serde!(
    

Vulnerability mechanics

Root cause

"Missing validation during deserialization allows a `VecStorage` object to be created with a data vector length that is inconsistent with its row and column dimensions."

Attack vector

An attacker can trigger this vulnerability by providing a maliciously crafted serialized input to an application using the `nalgebra` crate for deserialization. By supplying a `VecStorage` object where the number of elements in the data vector does not equal the product of the row and column counts, the attacker can cause out-of-bounds memory access [patch_id=16381]. This typically occurs when an application deserializes untrusted data into a matrix structure.

Affected code

The vulnerability is located in `src/base/vec_storage.rs` within the `VecStorage` struct's deserialization logic. The implementation failed to validate that the length of the deserialized data vector matched the expected dimensions of the matrix [patch_id=16381].

What the fix does

The patch modifies `src/base/vec_storage.rs` to implement a custom `Deserialize` trait for `VecStorage` [patch_id=16381]. This implementation explicitly checks if the product of the row count and column count matches the length of the deserialized data vector. If the lengths do not match, the deserialization process returns an error, preventing the creation of an invalid `VecStorage` instance and subsequent out-of-bounds memory access.

Preconditions

  • inputThe application must use the `nalgebra` crate to deserialize data using `serde`.

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

References

8

News mentions

0

No linked articles in our index yet.