CVE-2021-32629: Cranelift codegen Memory Access Due To Code Vulnerability

HIGH
Advisory Identifier: GHSA-hpqh-2wqx-7qp5
CVSS 7.2
CWE-125 CWE-788
Published
Advisory Summary

CVE-2021-32629 is a HIGH (CVSS 7.2) memory access due to code vulnerability (CWE-125: Out-of-bounds Read) affecting Cranelift codegen libraries in the crates.io ecosystem. The issue involves memory access due to code generation flaw in cranelift module. Remediation is available by upgrading affected packages to version 0.73.1, 0.27.0.

CVE-2021-32629 at a Glance

CVE Identifier CVE-2021-32629
GHSA Identifier GHSA-hpqh-2wqx-7qp5
Severity HIGH
CVSS v3.1 Base Score 7.2
CWE Classification CWE-125: Out-of-bounds Read
Affected Product Cranelift codegen
Package Ecosystem crates.io
Published Date
Last Updated

Security Impact

CVSS: 7.2

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N).

Attack Vector Local (AV:L)
Attack Complexity High (AC:H)
Privileges Required Low (PR:L)
User Interaction Required (UI:R)
Scope Changed (S:C)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2021-32629

To remediate this vulnerability, upgrade all affected Cranelift codegen dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

cranelift-codegen fixed: 0.73.1
Upgrade cranelift-codegen to 0.73.1
wasmtime fixed: 0.27.0
pip install wasmtime>=0.27.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for cranelift-codegen

How to Check if You Are Affected

To determine whether your application is affected by CVE-2021-32629, inspect your project dependencies for Cranelift codegen:

inspect dependencies for cranelift-codegen

Analyze the terminal output to locate any version of Cranelift codegen in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.73.1), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-125: Out-of-bounds Read, where the product reads data past the end, or before the beginning, of the intended buffer. In Cranelift codegen, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

There is a bug in 0.73.0 of the Cranelift x64 backend that can create a scenario that could result in a potential sandbox escape in a WebAssembly module. Users of versions 0.73.0 of Cranelift should upgrade to either 0.73.1 or 0.74 to remediate this vulnerability. Users of Cranelift prior to 0.73.0 should update to 0.73.1 or 0.74 if they were not using the old default backend. ### Description This bug was introduced in the new backend on 2020-09-08 and first included in a release on 2020-09-30, but the new backend was not the default prior to 0.73.0. The recently-released version 0.73.0 with default settings, and prior versions with an explicit build flag to select the new backend, are vulnerable. The bug in question performs a sign-extend instead of a zero-extend on a value loaded from the stack, under a specific set of circumstances. If those circumstances occur, the bug could allow access to memory addresses up to 2GiB before the start of the heap allocated for the WebAssembly module. If the heap bound is larger than 2GiB, then it would be possible to read memory from a computable range dependent on the size of the heap's bound. The impact of this bug is highly dependent on heap implementation; specifically: * if the heap has bounds checks, and * does not rely exclusively on guard pages, and * the heap bound is 2GiB or smaller then this bug cannot be used to reach memory from another WebAssembly module heap. The impact of the vulnerability is mitigated if there is no memory mapped in the range accessible using this bug, for example, if there is a 2 GiB guard region before the WebAssembly module heap. The bug in question performs a sign-extend instead of a zero-extend on a value loaded from the stack when the register allocator reloads a spilled integer value narrower than 64 bits. This interacts poorly with another optimization: the instruction selector elides a 32-to-64-bit zero-extend operator when we know that an instruction producing a 32-bit value actually zeros the upper 32 bits of its destination register. Hence, we rely on these zeroed bits, but the type of the value is still i32, and the spill/reload reconstitutes those bits as the sign extension of the i32’s MSB. The issue would thus occur when: * An i32 value is greater than or equal to 0x8000_0000; * The value is spilled and reloaded by the register allocator due to high register pressure in the program between the value’s definition and its use; * The value is produced by an instruction that we know to be "special" in that it zeroes the upper 32 bits of its destination: add, sub, mul, and, or; * The value is then zero-extended to 64 bits; * The resulting 64-bit value is used. Under these circumstances there is a potential sandbox escape when the i32 value is a pointer. The usual code emitted for heap accesses zero-extends the WebAssembly heap address, adds it to a 64-bit heap base, and accesses the resulting address. If the zero-extend becomes a sign-extend, the module could reach backward and access memory up to 2GiB before the start of its heap. This bug was identified by developers at Fastly following a report from Javier Cabrera Arteaga, KTH Royal Institute of Technology, with support from project Trustful of Stiftelsen för Strategisk Forskning. In addition to supporting the analysis and remediation of this vulnerability, Fastly will publish a related Fastly Security Advisory at [https://www.fastly.com/security-advisories](https://www.fastly.com/security-advisories). In addition to assessing the nature of the code generation bug in Cranelift, we have also determined that under specific circumstances, both Lucet and Wasmtime using this version of Cranelift may be exploitable. ### General Impact to Lucet Lucet inherits the heap address computation and bounds-checks of Cranelift, which it uses as its backend code generator. Of particular importance specifically is the address-space layout used by Lucet. In the default configuration for Lucet, only a single module is running, and therefore it is not possible to access memory from another module. By default, the open source implementation of Lucet uses a maximum heap size of 4 GiB, and an instance slot size of 8 GiB, when invoking an instance from the lucet-wasi command-line tool. These settings are within the range of vulnerability described above, but only a single instance is running, so there is no other instance to read. When embedding the runtime (for example, in a long-running daemon), the default for the heap size as described in the source is 1MB; with this setting, the runtime is not vulnerable. Lucet allocates its WebAssembly module instances into "instance slots", which are contiguous zones of virtual address space that contain the VM context at the bottom, the WebAssembly heap in the next page after that, a guard region in the middle, and other data at the top: the stack and the globals. If the instance slot size is less than (max heap) + 2GiB, then the lowest accessible address using the bug will overlap with the prior instance’s heap. If the size of VM context + stack + globals is greater than (4GiB - heap limit), then the highest accessible address using the bug will overlap with this critical data. If neither of these conditions are true, the bug should only result in an access to the prior instance’s guard region. Generally, if the limit is between 2GiB and 4GiB - ~1MB (depending on stack/global size) and the instance slot size is less than 6GiB, the configuration is vulnerable. If the limit is greater than 4GiB - ~1MB, the configuration is vulnerable regardless of instance slot size. Otherwise, the configuration is not vulnerable. ### General Impact on Wasmtime In Wasmtime, the same Cranelift heap address computations and heap types are used as above. The memory layout, however, is slightly different, with different outcomes: * With the mmap implementation impact is mitigated probabilistically if ASLR is enabled. * With the pooling allocator, the vulnerability only exists if a memory reservation size lower than the default of 6GB is used. With the default mmap-based instance memory implementation, Wasmtime uses mmap() to allocate a block of memory large enough for the heap and guard region, as specified in its configuration. If the underlying OS implements ASLR (modern Linux, macOS and Windows do) then this address will be randomized, and the region below it will (probabilistically) be free. Hence, the bug is mitigated probabilistically in the default configuration if ASLR is enabled. If using the pooling allocator, the vulnerability exists if instance memory size (`memory_reservation_size` in InstanceLimit) is strictly less than 6GiB (4 GiB + 2 GiB of guard pages). The default is 6GiB, so the vulnerability is masked in the default pooling allocator configuration.

CVE-2021-32629 Affected Cranelift codegen Versions

2 component(s)
Fixed Versions:
0.73.10.27.0
Product / Package Ecosystem Affected Versions Fixed Version
cranelift-codegen
crates.io
< 0.73.1
0.73.1
wasmtime
PyPI
< 0.27.0
0.27.0

References

Frequently Asked Questions

What is CVE-2021-32629?
CVE-2021-32629 is a security vulnerability in Cranelift codegen involving Memory access due to code generation flaw in Cranelift module under CWE-125: Out-of-bounds Read.
Which Cranelift codegen versions are affected?
Affected versions include releases prior to 0.73.1, 0.27.0 across affected packages: cranelift-codegen, wasmtime.
What version fixes CVE-2021-32629?
Upgrading to 0.73.1, 0.27.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is cranelift-codegen affected?
Yes, cranelift-codegen is affected in releases prior to 0.73.1. Upgrade your dependency to 0.73.1 or later.
Is wasmtime affected?
Yes, wasmtime is affected in releases prior to 0.27.0. Upgrade your dependency to 0.27.0 or later.
What is the CVSS score of CVE-2021-32629?
CVE-2021-32629 has a CVSS v3.1 base score of 7.2 (HIGH) with vector string CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N.
What CWE is associated with CVE-2021-32629?
CVE-2021-32629 is classified under CWE-125: Out-of-bounds Read (The product reads data past the end, or before the beginning, of the intended buffer.).
How can I check crates.io dependencies for CVE-2021-32629?
Run the dependency tree command: 'inspect dependencies for cranelift-codegen'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-hpqh-2wqx-7qp5",
  "modified" : "2024-11-19T19:18:55Z",
  "published" : "2021-08-25T21:01:55Z",
  "aliases" : [ "CVE-2021-32629" ],
  "summary" : "Memory access due to code generation flaw in Cranelift module",
  "details" : "There is a bug in 0.73.0 of the Cranelift x64 backend that can create a scenario that could result in a potential sandbox escape in a WebAssembly module.  Users of versions 0.73.0 of Cranelift should upgrade to either 0.73.1 or 0.74 to remediate this vulnerability.  Users of Cranelift prior to 0.73.0 should update to 0.73.1 or 0.74 if they were not using the old default backend.\n\n### Description\n\nThis bug was introduced in the new backend on 2020-09-08 and first included in a release on 2020-09-30, but the new backend was not the default prior to 0.73.0. The recently-released version 0.73.0 with default settings, and prior versions with an explicit build flag to select the new backend, are vulnerable.  The bug in question performs a sign-extend instead of a zero-extend on a value loaded from the stack, under a specific set of circumstances.  If those circumstances occur, the bug could allow access to memory addresses up to 2GiB before the start of the heap allocated for the WebAssembly module.\n\nIf the heap bound is larger than 2GiB, then it would be possible to read memory from a computable range dependent on the size of the heap's bound.  \n\nThe impact of this bug is highly dependent on heap implementation; specifically:\n* if the heap has bounds checks, and\n* does not rely exclusively on guard pages, and \n* the heap bound is 2GiB or smaller \n\nthen this bug cannot be used to reach memory from another WebAssembly module heap.\n\nThe impact of the vulnerability is mitigated if there is no memory mapped in the range accessible using this bug, for example, if there is a 2 GiB guard region before the WebAssembly module heap.\n\nThe bug in question performs a sign-extend instead of a zero-extend on a value loaded from the stack when the register allocator reloads a spilled integer value narrower than 64 bits. This interacts poorly with another optimization: the instruction selector elides a 32-to-64-bit zero-extend operator when we know that an instruction producing a 32-bit value actually zeros the upper 32 bits of its destination register. Hence, we rely on these zeroed bits, but the type of the value is still i32, and the spill/reload reconstitutes those bits as the sign extension of the i32’s MSB.\n\nThe issue would thus occur when:\n* An i32 value is greater than or equal to 0x8000_0000;\n* The value is spilled and reloaded by the register allocator due to high register pressure in the program between the value’s definition and its use;\n* The value is produced by an instruction that we know to be \"special\" in that it zeroes the upper 32 bits of its destination: add, sub, mul, and, or;\n* The value is then zero-extended to 64 bits;\n* The resulting 64-bit value is used.\n\nUnder these circumstances there is a potential sandbox escape when the i32 value is a pointer. The usual code emitted for heap accesses zero-extends the WebAssembly heap address, adds it to a 64-bit heap base, and accesses the resulting address. If the zero-extend becomes a sign-extend, the module could reach backward and access memory up to 2GiB before the start of its heap.\n\nThis bug was identified by developers at Fastly following a report from Javier Cabrera Arteaga, KTH Royal Institute of Technology, with support from project Trustful of Stiftelsen för Strategisk Forskning.  In addition to supporting the analysis and remediation of this vulnerability, Fastly will publish a related Fastly Security Advisory at [https://www.fastly.com/security-advisories](https://www.fastly.com/security-advisories).\n\nIn addition to assessing the nature of the code generation bug in Cranelift, we have also determined that under specific circumstances, both Lucet and Wasmtime using this version of Cranelift may be exploitable.\n\n### General Impact to Lucet\n\nLucet inherits the heap address computation and bounds-checks of Cranelift, which it uses as its backend code generator. Of particular importance specifically is the address-space layout used by Lucet. In the default configuration for Lucet, only a single module is running, and therefore it is not possible to access memory from another module.\n\nBy default, the open source implementation of Lucet uses a maximum heap size of 4 GiB, and an instance slot size of 8 GiB, when invoking an instance from the lucet-wasi command-line tool. These settings are within the range of vulnerability described above, but only a single instance is running, so there is no other instance to read. When embedding the runtime (for example, in a long-running daemon), the default for the heap size as described in the source is 1MB; with this setting, the runtime is not vulnerable.\n\nLucet allocates its WebAssembly module instances into \"instance slots\", which are contiguous zones of virtual address space that contain the VM context at the bottom, the WebAssembly heap in the next page after that, a guard region in the middle, and other data at the top: the stack and the globals.\n\nIf the instance slot size is less than (max heap) + 2GiB, then the lowest accessible address using the bug will overlap with the prior instance’s heap. If the size of VM context + stack + globals is greater than (4GiB - heap limit), then the highest accessible address using the bug will overlap with this critical data. If neither of these conditions are true, the bug should only result in an access to the prior instance’s guard region.\n\nGenerally, if the limit is between 2GiB and 4GiB - ~1MB (depending on stack/global size) and the instance slot size is less than 6GiB, the configuration is vulnerable. If the limit is greater than 4GiB - ~1MB, the configuration is vulnerable regardless of instance slot size. Otherwise, the configuration is not vulnerable.\n\n### General Impact on Wasmtime\n\nIn Wasmtime, the same Cranelift heap address computations and heap types are used as above. The memory layout, however, is slightly different, with different outcomes:\n* With the mmap implementation impact is mitigated probabilistically if ASLR is enabled.\n* With the pooling allocator, the vulnerability only exists if a memory reservation size lower than the default of 6GB is used.\n\nWith the default mmap-based instance memory implementation, Wasmtime uses mmap() to allocate a block of memory large enough for the heap and guard region, as specified in its configuration. If the underlying OS implements ASLR (modern Linux, macOS and Windows do) then this address will be randomized, and the region below it will (probabilistically) be free. Hence, the bug is mitigated probabilistically in the default configuration if ASLR is enabled.\n\nIf using the pooling allocator, the vulnerability exists if instance memory size (`memory_reservation_size` in InstanceLimit) is strictly less than 6GiB (4 GiB + 2 GiB of guard pages). The default is 6GiB, so the vulnerability is masked in the default pooling allocator configuration.\n",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "cranelift-codegen"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.73.1"
      } ]
    } ]
  }, {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "wasmtime"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "0.27.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-hpqh-2wqx-7qp5"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2021-32629"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/bytecodealliance/wasmtime/commit/95559c01aaa7c061088a433040f31e8291fb09d0"
  }, {
    "type" : "WEB",
    "url" : "https://crates.io/crates/cranelift-codegen"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/RustSec/advisory-db/blob/main/crates/cranelift-codegen/RUSTSEC-2021-0067.md"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/bytecodealliance/wasmtime/tree/main/cranelift"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/pypa/advisory-database/tree/main/vulns/wasmtime/PYSEC-2021-87.yaml"
  }, {
    "type" : "WEB",
    "url" : "https://rustsec.org/advisories/RUSTSEC-2021-0067.html"
  }, {
    "type" : "WEB",
    "url" : "https://www.fastly.com/security-advisories/memory-access-due-to-code-generation-flaw-in-cranelift-module"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-125", "CWE-788" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2021-05-25T20:51:32Z",
    "nvd_published_at" : "2021-05-24T16:15:00Z"
  }
}