VYPR
Critical severityNVD Advisory· Published Dec 31, 2020· Updated Aug 4, 2024

CVE-2020-35867

CVE-2020-35867

Description

An issue was discovered in the rusqlite crate before 0.23.0 for Rust. Memory safety can be violated via create_module.

AI Insight

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

Memory safety violation in rusqlite before 0.23.0 via create_module, allowing undefined behavior.

Vulnerability

CVE-2020-35867 is a memory safety vulnerability in the rusqlite crate for Rust, affecting versions prior to 0.23.0. The issue arises in the create_module function, which can cause a memory safety violation when used to create virtual table modules. The root cause is related to the lifetime handling and representation of the Module struct, which was initially declared as #[repr(C)] but was changed to #[repr(transparent)] in the fix, along with adjustments to how the sqlite3_module struct is zero-initialized to avoid undefined behavior [2].

Exploitation

To exploit this vulnerability, an attacker would need to craft a virtual table module that triggers the memory safety issue through create_module. The vulnerability is triggered without any special privileges, as it resides in the library's handling of SQLite virtual tables. The attack surface is local, meaning an attacker would need to run code using the affected crate version or convince a user to run such code [1][3].

Impact

Successful exploitation of this memory safety issue could lead to undefined behavior, potentially including memory corruption or crashes. The RustSec advisory lists this as a vulnerability that could compromise memory safety guarantees, which may be leveraged for further attacks or denial of service [3].

Mitigation

The vulnerability was patched in rusqlite version 0.23.0. Users should upgrade to this version or later to mitigate the risk. The fix involved correcting the struct representation and initialization to prevent memory unsafety [2]. This CVE is part of a series of memory safety fixes in the same release, as listed in the RustSec advisory [3].

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
rusqlitecrates.io
< 0.23.00.23.0

Affected products

2

Patches

2
54043c803c83

Prep release 0.23.0

https://github.com/rusqlite/rusqliteThom ChiovoloniApr 23, 2020via osv
1 file changed · +1 1
  • Cargo.toml+1 1 modified
    @@ -1,6 +1,6 @@
     [package]
     name = "rusqlite"
    -version = "0.22.0"
    +version = "0.23.0"
     authors = ["The rusqlite developers"]
     edition = "2018"
     description = "Ergonomic wrapper for SQLite"
    
3c6b57fe1b2c

Fix vtab::Module lifetime

https://github.com/rusqlite/rusqliteThom ChiovoloniApr 14, 2020via ghsa
5 files changed · +87 90
  • src/vtab/array.rs+3 7 modified
    @@ -33,8 +33,8 @@ use std::rc::Rc;
     use crate::ffi;
     use crate::types::{ToSql, ToSqlOutput, Value};
     use crate::vtab::{
    -    eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection,
    -    VTabCursor, Values,
    +    eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConnection, VTabCursor,
    +    Values,
     };
     use crate::{Connection, Result};
     
    @@ -57,11 +57,7 @@ impl ToSql for Array {
     /// `feature = "array"` Register the "rarray" module.
     pub fn load_module(conn: &Connection) -> Result<()> {
         let aux: Option<()> = None;
    -    conn.create_module("rarray", &ARRAY_MODULE, aux)
    -}
    -
    -lazy_static::lazy_static! {
    -    static ref ARRAY_MODULE: Module<ArrayTab> = eponymous_only_module::<ArrayTab>(1);
    +    conn.create_module("rarray", eponymous_only_module::<ArrayTab>(), aux)
     }
     
     // Column numbers
    
  • src/vtab/csvtab.rs+2 6 modified
    @@ -30,7 +30,7 @@ use crate::ffi;
     use crate::types::Null;
     use crate::vtab::{
         dequote, escape_double_quote, parse_boolean, read_only_module, Context, CreateVTab, IndexInfo,
    -    Module, VTab, VTabConnection, VTabCursor, Values,
    +    VTab, VTabConnection, VTabCursor, Values,
     };
     use crate::{Connection, Error, Result};
     
    @@ -47,11 +47,7 @@ use crate::{Connection, Error, Result};
     /// ```
     pub fn load_module(conn: &Connection) -> Result<()> {
         let aux: Option<()> = None;
    -    conn.create_module("csv", &CSV_MODULE, aux)
    -}
    -
    -lazy_static::lazy_static! {
    -    static ref CSV_MODULE: Module<CSVTab> = read_only_module::<CSVTab>(1);
    +    conn.create_module("csv", read_only_module::<CSVTab>(), aux)
     }
     
     /// An instance of the CSV virtual table
    
  • src/vtab/mod.rs+76 67 modified
    @@ -60,7 +60,7 @@ use crate::{str_to_cstring, Connection, Error, InnerConnection, Result};
     /// `feature = "vtab"` Virtual table module
     ///
     /// (See [SQLite doc](https://sqlite.org/c3ref/module.html))
    -#[repr(C)]
    +#[repr(transparent)]
     pub struct Module<T: VTab> {
         base: ffi::sqlite3_module,
         phantom: PhantomData<T>,
    @@ -69,86 +69,94 @@ pub struct Module<T: VTab> {
     unsafe impl<T: VTab> Send for Module<T> {}
     unsafe impl<T: VTab> Sync for Module<T> {}
     
    -// Used as a trailing initializer for sqlite3_module -- this way we avoid having
    -// the build fail if buildtime_bindgen is on
    -fn zeroed_module() -> ffi::sqlite3_module {
    -    // This is safe, as bindgen-generated structs are allowed to be zeroed.
    -    unsafe { std::mem::MaybeUninit::zeroed().assume_init() }
    +union ModuleZeroHack {
    +    bytes: [u8; std::mem::size_of::<ffi::sqlite3_module>()],
    +    module: ffi::sqlite3_module,
     }
     
    +// Used as a trailing initializer for sqlite3_module -- this way we avoid having
    +// the build fail if buildtime_bindgen is on. This is safe, as bindgen-generated
    +// structs are allowed to be zeroed.
    +const ZERO_MODULE: ffi::sqlite3_module = unsafe {
    +    ModuleZeroHack {
    +        bytes: [0u8; std::mem::size_of::<ffi::sqlite3_module>()],
    +    }
    +    .module
    +};
    +
     /// `feature = "vtab"` Create a read-only virtual table implementation.
     ///
     /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
    -pub fn read_only_module<T: CreateVTab>(version: c_int) -> Module<T> {
    +pub fn read_only_module<T: CreateVTab>() -> &'static Module<T> {
         // The xConnect and xCreate methods do the same thing, but they must be
         // different so that the virtual table is not an eponymous virtual table.
    -    let ffi_module = ffi::sqlite3_module {
    -        iVersion: version,
    -        xCreate: Some(rust_create::<T>),
    -        xConnect: Some(rust_connect::<T>),
    -        xBestIndex: Some(rust_best_index::<T>),
    -        xDisconnect: Some(rust_disconnect::<T>),
    -        xDestroy: Some(rust_destroy::<T>),
    -        xOpen: Some(rust_open::<T>),
    -        xClose: Some(rust_close::<T::Cursor>),
    -        xFilter: Some(rust_filter::<T::Cursor>),
    -        xNext: Some(rust_next::<T::Cursor>),
    -        xEof: Some(rust_eof::<T::Cursor>),
    -        xColumn: Some(rust_column::<T::Cursor>),
    -        xRowid: Some(rust_rowid::<T::Cursor>),
    -        xUpdate: None,
    -        xBegin: None,
    -        xSync: None,
    -        xCommit: None,
    -        xRollback: None,
    -        xFindFunction: None,
    -        xRename: None,
    -        xSavepoint: None,
    -        xRelease: None,
    -        xRollbackTo: None,
    -        ..zeroed_module()
    -    };
    -    Module {
    -        base: ffi_module,
    +    &Module {
    +        base: ffi::sqlite3_module {
    +            // We don't use V3
    +            iVersion: 2, // We don't use V2 or V3 features in read_only_module types
    +            xCreate: Some(rust_create::<T>),
    +            xConnect: Some(rust_connect::<T>),
    +            xBestIndex: Some(rust_best_index::<T>),
    +            xDisconnect: Some(rust_disconnect::<T>),
    +            xDestroy: Some(rust_destroy::<T>),
    +            xOpen: Some(rust_open::<T>),
    +            xClose: Some(rust_close::<T::Cursor>),
    +            xFilter: Some(rust_filter::<T::Cursor>),
    +            xNext: Some(rust_next::<T::Cursor>),
    +            xEof: Some(rust_eof::<T::Cursor>),
    +            xColumn: Some(rust_column::<T::Cursor>),
    +            xRowid: Some(rust_rowid::<T::Cursor>),
    +            xUpdate: None,
    +            xBegin: None,
    +            xSync: None,
    +            xCommit: None,
    +            xRollback: None,
    +            xFindFunction: None,
    +            xRename: None,
    +            xSavepoint: None,
    +            xRelease: None,
    +            xRollbackTo: None,
    +            ..ZERO_MODULE
    +        },
             phantom: PhantomData::<T>,
         }
     }
     
     /// `feature = "vtab"` Create an eponymous only virtual table implementation.
     ///
     /// Step 2 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
    -pub fn eponymous_only_module<T: VTab>(version: c_int) -> Module<T> {
    +pub fn eponymous_only_module<T: VTab>() -> &'static Module<T> {
         // A virtual table is eponymous if its xCreate method is the exact same function
         // as the xConnect method For eponymous-only virtual tables, the xCreate
         // method is NULL
    -    let ffi_module = ffi::sqlite3_module {
    -        iVersion: version,
    -        xCreate: None,
    -        xConnect: Some(rust_connect::<T>),
    -        xBestIndex: Some(rust_best_index::<T>),
    -        xDisconnect: Some(rust_disconnect::<T>),
    -        xDestroy: None,
    -        xOpen: Some(rust_open::<T>),
    -        xClose: Some(rust_close::<T::Cursor>),
    -        xFilter: Some(rust_filter::<T::Cursor>),
    -        xNext: Some(rust_next::<T::Cursor>),
    -        xEof: Some(rust_eof::<T::Cursor>),
    -        xColumn: Some(rust_column::<T::Cursor>),
    -        xRowid: Some(rust_rowid::<T::Cursor>),
    -        xUpdate: None,
    -        xBegin: None,
    -        xSync: None,
    -        xCommit: None,
    -        xRollback: None,
    -        xFindFunction: None,
    -        xRename: None,
    -        xSavepoint: None,
    -        xRelease: None,
    -        xRollbackTo: None,
    -        ..zeroed_module()
    -    };
    -    Module {
    -        base: ffi_module,
    +    &Module {
    +        base: ffi::sqlite3_module {
    +            // We don't use V3
    +            iVersion: 2,
    +            xCreate: None,
    +            xConnect: Some(rust_connect::<T>),
    +            xBestIndex: Some(rust_best_index::<T>),
    +            xDisconnect: Some(rust_disconnect::<T>),
    +            xDestroy: None,
    +            xOpen: Some(rust_open::<T>),
    +            xClose: Some(rust_close::<T::Cursor>),
    +            xFilter: Some(rust_filter::<T::Cursor>),
    +            xNext: Some(rust_next::<T::Cursor>),
    +            xEof: Some(rust_eof::<T::Cursor>),
    +            xColumn: Some(rust_column::<T::Cursor>),
    +            xRowid: Some(rust_rowid::<T::Cursor>),
    +            xUpdate: None,
    +            xBegin: None,
    +            xSync: None,
    +            xCommit: None,
    +            xRollback: None,
    +            xFindFunction: None,
    +            xRename: None,
    +            xSavepoint: None,
    +            xRelease: None,
    +            xRollbackTo: None,
    +            ..ZERO_MODULE
    +        },
             phantom: PhantomData::<T>,
         }
     }
    @@ -583,11 +591,12 @@ impl<'a> Iterator for ValueIter<'a> {
     impl Connection {
         /// `feature = "vtab"` Register a virtual table implementation.
         ///
    -    /// Step 3 of [Creating New Virtual Table Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
    +    /// Step 3 of [Creating New Virtual Table
    +    /// Implementations](https://sqlite.org/vtab.html#creating_new_virtual_table_implementations).
         pub fn create_module<T: VTab>(
             &self,
             module_name: &str,
    -        module: &Module<T>,
    +        module: &'static Module<T>,
             aux: Option<T::Aux>,
         ) -> Result<()> {
             self.db.borrow_mut().create_module(module_name, module, aux)
    @@ -598,7 +607,7 @@ impl InnerConnection {
         fn create_module<T: VTab>(
             &mut self,
             module_name: &str,
    -        module: &Module<T>,
    +        module: &'static Module<T>,
             aux: Option<T::Aux>,
         ) -> Result<()> {
             let c_name = str_to_cstring(module_name)?;
    
  • src/vtab/series.rs+3 7 modified
    @@ -9,19 +9,15 @@ use std::os::raw::c_int;
     use crate::ffi;
     use crate::types::Type;
     use crate::vtab::{
    -    eponymous_only_module, Context, IndexConstraintOp, IndexInfo, Module, VTab, VTabConnection,
    -    VTabCursor, Values,
    +    eponymous_only_module, Context, IndexConstraintOp, IndexInfo, VTab, VTabConnection, VTabCursor,
    +    Values,
     };
     use crate::{Connection, Result};
     
     /// `feature = "series"` Register the "generate_series" module.
     pub fn load_module(conn: &Connection) -> Result<()> {
         let aux: Option<()> = None;
    -    conn.create_module("generate_series", &SERIES_MODULE, aux)
    -}
    -
    -lazy_static::lazy_static! {
    -    static ref SERIES_MODULE: Module<SeriesTab> = eponymous_only_module::<SeriesTab>(1);
    +    conn.create_module("generate_series", eponymous_only_module::<SeriesTab>(), aux)
     }
     
     // Column numbers
    
  • tests/vtab.rs+3 3 modified
    @@ -11,15 +11,15 @@ fn test_dummy_module() {
         use rusqlite::{version_number, Connection, Result};
         use std::os::raw::c_int;
     
    -    let module = eponymous_only_module::<DummyTab>(1);
    +    let module = eponymous_only_module::<DummyTab>();
     
         #[repr(C)]
         struct DummyTab {
             /// Base class. Must be first
             base: sqlite3_vtab,
         }
     
    -    impl VTab for DummyTab {
    +    unsafe impl VTab for DummyTab {
             type Aux = ();
             type Cursor = DummyTabCursor;
     
    @@ -53,7 +53,7 @@ fn test_dummy_module() {
             row_id: i64,
         }
     
    -    impl VTabCursor for DummyTabCursor {
    +    unsafe impl VTabCursor for DummyTabCursor {
             fn filter(
                 &mut self,
                 _idx_num: c_int,
    

Vulnerability mechanics

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

References

5

News mentions

0

No linked articles in our index yet.