PT-2026-41490 · Crates.Io · Diesel-Async

Publicado

2026-05-07

·

Atualizado

2026-05-07

CVSS v4.0

2.0

Baixa

VetorAV:L/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:L/SC:N/SI:N/SA:N/E:P

Summary

diesel-async exposes uninitialized stack padding to safe code on every read of a MySQL DATE, TIME, DATETIME, or TIMESTAMP column. Reading that buffer is undefined behavior, and the leaked bytes can contain stale heap/stack contents, so this is both a soundness bug and a potential information-disclosure vector.

Details

In diesel-async/src/mysql/row.rs (lines 65-103), MysqlRow::get builds a MysqlTime from the parsed mysql async::Value and then fabricates the byte buffer that downstream FromSql impls expect like this:
rust
let date = MysqlTime::new(/* fields from Value::Date / Value::Time */);
let buffer = unsafe {
  let ptr = &date as *const MysqlTime as *const u8;
  let slice = std::slice::from raw parts(ptr, std::mem::size of::<MysqlTime>());
  slice.to vec()
};
MysqlTime is #[repr(C)] with 3 bytes of padding after bool neg (Linux x86 64, offsets 0x21..0x23). The literal construction leaves that padding uninitialized, and to vec() carries it into a Vec<u8> that becomes the MysqlValue's backing buffer, reachable from safe code via MysqlValue::as bytes() -> &[u8].
diesel itself avoids this by going through MaybeUninit::<MysqlTime>::zeroed() + ptr::copy nonoverlapping (see diesel/src/mysql/value.rs:43-94); the same pattern would fix this. Alternatively, write the bytes diesel's FromSql reads without round-tripping through a MysqlTime value.

PoC

Cargo.toml:
toml
[dependencies]
diesel = { version = "~2.3.0", default-features = false, features = ["mysql backend"] }
diesel-async = { version = "=0.8.0", features = ["mysql"] }
mysql common = { version = "0.35", default-features = false }
src/main.rs:
rust
use diesel::row::{Field, Row};
use diesel async::{AsyncConnectionCore, AsyncMysqlConnection};
use mysql common::{constants::ColumnType, packets::Column, prelude::FromRow, value::Value};

type MysqlRow = <AsyncMysqlConnection as AsyncConnectionCore>::Row<'static, 'static>;

fn main() {
  let cols = std::sync::Arc::from([Column::new(ColumnType::MYSQL TYPE DATE)]);
  let raw = mysql common::row::new row(vec![Value::Date(2024, 1, 1, 0, 0, 0, 0)], cols);
  let row: MysqlRow = FromRow::from row(raw);

  let field = row.get(0).unwrap();
  let bytes = field.value().unwrap().as bytes();
  let : u64 = bytes.iter().map(|&b| b as u64).sum(); // UB: hits padding
}
Miri output:
error: Undefined Behavior: reading memory at alloc844[0x21..0x22], but memory is uninitialized at [0x21..0x22], and this operation requires initialized memory
 --> src/main.rs:14:37
  |
14 |   let : u64 = bytes.iter().map(|&b| b as u64).sum(); // UB: hits padding
  |                   ^ Undefined Behavior occurred here
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: stack backtrace:
      0: main::{closure#0}
        at src/main.rs:14:37: 14:38
      1: std::iter::adapters::map::map fold::<&u8, u64, u64, {closure@src/main.rs:14:35: 14:39}, {closure@<u64 as std::iter::Sum>::sum<std::iter::Map<std::slice::Iter<' , u8>, {closure@src/main.rs:14:35: 14:39}>>::{closure#0}}>::{closure#0}
        at /home/paolobarbolini/.rustup/toolchains/nightly-x86 64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:88:28: 88:34
      2: <std::slice::Iter<' , u8> as std::iter::Iterator>::fold::<u64, {closure@std::iter::adapters::map::map fold<&u8, u64, u64, {closure@src/main.rs:14:35: 14:39}, {closure@<u64 as std::iter::Sum>::sum<std::iter::Map<std::slice::Iter<' , u8>, {closure@src/main.rs:14:35: 14:39}>>::{closure#0}}>::{closure#0}}>
        at /home/paolobarbolini/.rustup/toolchains/nightly-x86 64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/iter/macros.rs:279:27: 279:85
      3: <std::iter::Map<std::slice::Iter<' , u8>, {closure@src/main.rs:14:35: 14:39}> as std::iter::Iterator>::fold::<u64, {closure@<u64 as std::iter::Sum>::sum<std::iter::Map<std::slice::Iter<' , u8>, {closure@src/main.rs:14:35: 14:39}>>::{closure#0}}>
        at /home/paolobarbolini/.rustup/toolchains/nightly-x86 64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:128:9: 128:50
      4: <u64 as std::iter::Sum>::sum::<std::iter::Map<std::slice::Iter<' , u8>, {closure@src/main.rs:14:35: 14:39}>>
        at /home/paolobarbolini/.rustup/toolchains/nightly-x86 64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/accum.rs:52:17: 56:18
      5: <std::iter::Map<std::slice::Iter<' , u8>, {closure@src/main.rs:14:35: 14:39}> as std::iter::Iterator>::sum::<u64>
        at /home/paolobarbolini/.rustup/toolchains/nightly-x86 64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:3676:9: 3676:23
      6: main
        at src/main.rs:14:18: 14:55

Uninitialized memory occurred at alloc844[0x21..0x22], in this allocation:
alloc844 (Rust heap, size: 48, align: 1) {
  0x00 │ e8 07 00 00 01 00 00 00 01 00 00 00 00 00 00 00 │ ................
  0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │ ................
  0x20 │ 00     01 00 00 00 00 00 00 00       │ .░░░........░░░░
}

Impact

Soundness bug in safe API surface of diesel-async's MySQL backend. Affects every user of AsyncMysqlConnection whose queries return a temporal column.
AI disclosure: this issue was found via Claude Code running Claude Opus 4.7.

Correção

Buffer Over-read

Encontrou algum problema na descrição? Tem algo a acrescentar? Fique à vontade para nos escrever 👾

Enumeração de Fraquezas

Identificadores relacionados

GHSA-FF9Q-RM55-Q7QR

Produtos afetados

Diesel-Async