From 23b99eea78d234ae2a50690476f280768ead1a3d Mon Sep 17 00:00:00 2001 From: kbhetrr Date: Sat, 13 Jun 2026 10:35:14 +0900 Subject: [PATCH 1/2] Add advisories: use-after-free via leaked async transfer future (5 embedded HAL crates) --- crates/axi-uart16550/RUSTSEC-0000-0000.md | 49 +++++++++++++++ crates/axi-uartlite/RUSTSEC-0000-0000.md | 49 +++++++++++++++ crates/vorago-shared-hal/RUSTSEC-0000-0000.md | 56 +++++++++++++++++ .../RUSTSEC-0000-0000.md | 46 ++++++++++++++ crates/zynq7000-hal/RUSTSEC-0000-0000.md | 61 +++++++++++++++++++ 5 files changed, 261 insertions(+) create mode 100644 crates/axi-uart16550/RUSTSEC-0000-0000.md create mode 100644 crates/axi-uartlite/RUSTSEC-0000-0000.md create mode 100644 crates/vorago-shared-hal/RUSTSEC-0000-0000.md create mode 100644 crates/vorago-shared-periphs/RUSTSEC-0000-0000.md create mode 100644 crates/zynq7000-hal/RUSTSEC-0000-0000.md diff --git a/crates/axi-uart16550/RUSTSEC-0000-0000.md b/crates/axi-uart16550/RUSTSEC-0000-0000.md new file mode 100644 index 000000000..a9ab79a83 --- /dev/null +++ b/crates/axi-uart16550/RUSTSEC-0000-0000.md @@ -0,0 +1,49 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "axi-uart16550" +date = "2026-06-13" +informational = "unsound" +references = [ + "https://egit.irs.uni-stuttgart.de/rust/axi-uart16550", + "https://crates.io/crates/axi-uart16550", +] +keywords = ["async", "use-after-free", "soundness", "embedded", "uart"] + +[versions] +patched = [">=0.2.0"] +``` + +# axi-uart16550: information disclosure via leaking an in-flight async UART TX future + +`axi-uart16550` before 0.2.0 exposes a **safe** asynchronous UART transmit API +(`impl embedded_io_async::Write for TxAsync`, `src/tx_async.rs`) that accepts a **non-`'static` +borrowed buffer** and erases its lifetime (via `raw-slice`/`raw-buffer`) to hand a bare pointer to +the TX interrupt. Cancellation safety relies **entirely** on the returned future's `Drop` to disable +the interrupt, laundered through the safe `Write` trait impl. + +Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/arena reference +cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transmit future +(polled at least once, so the TX interrupt is armed) while the borrow of the user buffer ends and +its storage is freed or reused. The TX interrupt then keeps **reading the freed buffer and +transmitting its bytes on the wire** — an **information disclosure** of adjacent freed memory, +reachable with no `unsafe` in the caller. + +Neither the borrow checker nor Miri flags it (the interrupt access is outside the abstract machine +and the lifetime is erased). Normal cancellation (dropping the future) runs `Drop` and is handled; +only *leaking* an in-flight future triggers it. Severity is application-dependent, but the API is +**unsound** (safe code can cause UB). + +## Remediation + +Version 0.2.0 marks the `TxFuture` constructor `unsafe` and requires the future to borrow the +buffer for its lifetime, addressing the inherent API path. The `embedded_io_async::Write` trait +implementation retains a theoretical gap (the trait mandates borrowed buffers that cannot be +lifetime-constrained in the return type), which is documented in the crate. The underlying +`raw-buffer` crate's safety notes were also updated to document this obligation for HAL authors. + +Upgrade to `axi-uart16550 >= 0.2.0`. + +--- +Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the +maintainer prior to publication. diff --git a/crates/axi-uartlite/RUSTSEC-0000-0000.md b/crates/axi-uartlite/RUSTSEC-0000-0000.md new file mode 100644 index 000000000..8f32af611 --- /dev/null +++ b/crates/axi-uartlite/RUSTSEC-0000-0000.md @@ -0,0 +1,49 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "axi-uartlite" +date = "2026-06-13" +informational = "unsound" +references = [ + "https://egit.irs.uni-stuttgart.de/rust/axi-uartlite", + "https://crates.io/crates/axi-uartlite", +] +keywords = ["async", "use-after-free", "soundness", "embedded", "uart"] + +[versions] +patched = [">=0.2.0"] +``` + +# axi-uartlite: information disclosure via leaking an in-flight async UART TX future + +`axi-uartlite` before 0.2.0 exposes a **safe** asynchronous UART transmit API +(`impl embedded_io_async::Write for TxAsync`, `src/tx_async.rs`) that accepts a **non-`'static` +borrowed buffer** and erases its lifetime (via `raw-slice`/`raw-buffer`) to hand a bare pointer to +the TX interrupt. Cancellation safety relies on the returned future's `Drop`, laundered through the +safe `Write` trait impl. In this crate `TxFuture::drop` additionally **cannot disable the +interrupt** (commented "We can not disable interrupts, might be active for RX as well"), so even +ordinary cancellation is weaker here. + +Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/arena reference +cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transmit future +while the borrow of the user buffer ends and its storage is freed or reused. The TX interrupt then +keeps **reading the freed buffer and transmitting its bytes on the wire** — an **information +disclosure** of adjacent freed memory, reachable with no `unsafe` in the caller. + +Neither the borrow checker nor Miri flags it (the interrupt access is outside the abstract machine +and the lifetime is erased). Severity is application-dependent, but the API is **unsound** (safe +code can cause UB). + +## Remediation + +Version 0.2.0 marks the `TxFuture` constructor `unsafe` and requires the future to borrow the +buffer for its lifetime, addressing the inherent API path. The `embedded_io_async::Write` trait +implementation retains a theoretical gap (the trait mandates borrowed buffers that cannot be +lifetime-constrained in the return type), which is documented in the crate. The underlying +`raw-buffer` crate's safety notes were also updated to document this obligation for HAL authors. + +Upgrade to `axi-uartlite >= 0.2.0`. + +--- +Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the +maintainer prior to publication. diff --git a/crates/vorago-shared-hal/RUSTSEC-0000-0000.md b/crates/vorago-shared-hal/RUSTSEC-0000-0000.md new file mode 100644 index 000000000..260d08b57 --- /dev/null +++ b/crates/vorago-shared-hal/RUSTSEC-0000-0000.md @@ -0,0 +1,56 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "vorago-shared-hal" +date = "2026-06-13" +informational = "unsound" +references = [ + "https://egit.irs.uni-stuttgart.de/rust/vorago-rs", + "https://egit.irs.uni-stuttgart.de/rust/vorago-rs/pulls/43", + "https://crates.io/crates/vorago-shared-hal", +] +keywords = ["dma", "async", "use-after-free", "soundness", "embedded"] + +[versions] +patched = [] +``` + +# vorago-shared-hal: use-after-free of a borrowed buffer via leaking an in-flight async transfer + +`vorago-shared-hal` 0.4.0 exposes **safe** asynchronous I/O that accepts a **non-`'static` borrowed +buffer** and erases its lifetime to hand a bare pointer to a peripheral interrupt / engine: + +- `impl embedded_io_async::Write for TxAsync` (`src/uart/tx_async.rs`) — UART TX (the TX interrupt + **reads** the buffer). +- the async SPI path (`src/spi/asynch.rs`) (RX: the SPI controller **writes** the buffer). + +Internally the buffer pointer is lifetime-erased (via `raw-slice`/`raw-buffer` `RawSlice`/ +`RawSliceMut`, e.g. `context.slice.get()` in `on_interrupt_tx`) and stored in a `static`; +cancellation safety relies **entirely** on the returned future's `Drop` to disable the interrupt. +Although `TxFuture::new` is `unsafe`, the obligation is **laundered through the safe +`embedded_io_async::Write` trait impl**, so a caller reaches the lifetime-erased store with no +`unsafe`. + +Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/arena reference +cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transfer future +while the borrow of the user buffer ends and its storage is freed or reused, after which: + +- **UART TX**: the interrupt reads freed storage and transmits it — **information disclosure**. +- **SPI RX**: the controller writes received bytes into freed storage — **memory corruption**. + +Reachable from safe code; neither the borrow checker nor Miri observes the peripheral access (it is +outside the abstract machine, and the lifetime is erased). Normal cancellation (dropping the future) +runs `Drop` and is handled; only *leaking* an in-flight future triggers it. Severity is +application-dependent, but the APIs are **unsound** (safe code can cause UB). + +## Remediation + +A fix marking the async TX write API `unsafe` was merged on the development branch (`vorago-rs` +PR #43, "TX async writes are unsafe now"), but **has not yet been published to crates.io** (0.4.0 +is the latest release and remains affected). Upgrade once a release `> 0.4.0` is available. Until +then, guarantee the buffer outlives any in-flight transfer and never leak an in-flight future. The +underlying `raw-buffer` crate's safety notes were also updated to document this obligation. + +--- +Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the +maintainer prior to publication. diff --git a/crates/vorago-shared-periphs/RUSTSEC-0000-0000.md b/crates/vorago-shared-periphs/RUSTSEC-0000-0000.md new file mode 100644 index 000000000..f97b7dc0c --- /dev/null +++ b/crates/vorago-shared-periphs/RUSTSEC-0000-0000.md @@ -0,0 +1,46 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "vorago-shared-periphs" +date = "2026-06-13" +informational = "unsound" +references = [ + "https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs", + "https://crates.io/crates/vorago-shared-periphs", +] +keywords = ["async", "use-after-free", "soundness", "embedded", "uart"] + +[versions] +patched = [] +``` + +# vorago-shared-periphs: information disclosure via leaking an in-flight async UART TX future + +`vorago-shared-periphs` 0.1.0 exposes a **safe** asynchronous UART transmit API +(`impl embedded_io_async::Write for TxAsync`, `src/uart/tx_asynch.rs`) that accepts a **non-`'static` +borrowed buffer** and erases its lifetime (via `raw-slice`/`raw-buffer` `RawSlice`) to hand a bare +pointer to the TX interrupt. Cancellation safety relies **entirely** on the returned future's `Drop` +to disable the interrupt, and the obligation is **laundered through the safe `Write` trait impl**. + +Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/arena reference +cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transmit future +(polled at least once, so the TX interrupt is armed) while the borrow of the user buffer ends and +its storage is freed or reused. The TX interrupt then keeps **reading the freed buffer and +transmitting its bytes on the wire** — an **information disclosure** of adjacent freed memory, +reachable with no `unsafe` in the caller. + +Neither the borrow checker nor Miri flags it (the interrupt access is outside the abstract machine +and the lifetime is erased). Normal cancellation (dropping the future) runs `Drop` and is handled; +only *leaking* an in-flight future triggers it. Severity is application-dependent, but the API is +**unsound** (safe code can cause UB). + +## Remediation + +Require `'static`/owned buffers (the `embedded-dma` convention), or otherwise guarantee the buffer +outlives any in-flight transfer; at minimum document on the safe method that leaking an in-flight +transfer future is a soundness hazard. The underlying `raw-buffer` crate's safety notes were updated +to document this obligation. + +--- +Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the +maintainer prior to publication. diff --git a/crates/zynq7000-hal/RUSTSEC-0000-0000.md b/crates/zynq7000-hal/RUSTSEC-0000-0000.md new file mode 100644 index 000000000..8d6c1b591 --- /dev/null +++ b/crates/zynq7000-hal/RUSTSEC-0000-0000.md @@ -0,0 +1,61 @@ +```toml +[advisory] +id = "RUSTSEC-0000-0000" +package = "zynq7000-hal" +date = "2026-06-13" +informational = "unsound" +references = [ + "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs", + "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/pulls/89", + "https://crates.io/crates/zynq7000-hal", +] +keywords = ["dma", "async", "use-after-free", "soundness", "embedded"] + +[versions] +patched = [] +``` + +# zynq7000-hal: use-after-free of a borrowed buffer via leaking an in-flight async SPI/UART transfer + +`zynq7000-hal` 0.1.1 exposes **safe** asynchronous I/O that accepts a **non-`'static` borrowed +buffer** and erases its lifetime to hand a bare pointer to the SPI controller / UART interrupt: + +- `impl embedded_hal_async::spi::SpiBus for SpiAsync` — `read`, `transfer`, `transfer_in_place` + (RX path: the SPI controller **writes** the buffer). +- the async UART TX path (`embedded_io_async`) (the TX interrupt **reads** the buffer). + +Internally the buffer pointer is lifetime-erased (via the `raw-slice`/`raw-buffer` `RawSlice`/ +`RawSliceMut` types) and stored in a `static`; cancellation safety relies **entirely** on the +returned future's `Drop` (`SpiFuture::drop` → `reset_and_reconfigure`) to stop the peripheral. The +`SpiFuture` constructors (`new_for_read`, `new_for_transfer`, …) are **not `unsafe fn`**, so the +entire path from the safe `SpiBus` trait to the lifetime-erased store contains no `unsafe`. + +Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/`RefCell`/arena +reference cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transfer +future (one polled at least once, so the peripheral is armed) while the borrow of the user buffer +ends and its storage is freed or reused. The peripheral then: + +- **SPI RX (`read`/`transfer`/`transfer_in_place`)**: writes received bytes into freed storage — + **memory corruption**, reachable from safe code with no `unsafe` in the caller. +- **UART TX**: the interrupt reads freed storage and transmits it on the wire — **information + disclosure** of adjacent freed memory. + +Normal cancellation (dropping the future) runs `Drop` and is handled; only *leaking* an in-flight +future triggers the issue. Neither the borrow checker nor Miri flags it: the peripheral access is +outside the Rust abstract machine, and the lifetime is erased. The trigger is not necessarily +attacker-controlled, so severity is application-dependent, but the APIs are **unsound** by Rust's +definition (safe code can cause UB). + +## Remediation + +A fix marking the async `TxAsync`/`SpiAsync` constructors `unsafe` and adding explicit buffer +lifetimes (`TxFuture<'uart, 'buf>`, `SpiFuture<'spi, 'read, 'write>`) was merged on the development +branch (`zynq7000-rs` PR #89, "Safety updates"), but **has not yet been published to crates.io** +(0.1.1 is the latest release and remains affected). Upgrade once a release `> 0.1.1` is available. +Until then, guarantee the buffer outlives any in-flight transfer and never leak an in-flight future. +The underlying `raw-buffer` crate's safety notes were also updated to document this obligation for +HAL/firmware authors. + +--- +Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the +maintainer prior to publication. From 8751766a58787a118d7f382a7632f4721df7fb4e Mon Sep 17 00:00:00 2001 From: kbhetrr Date: Sat, 13 Jun 2026 16:01:06 +0900 Subject: [PATCH 2/2] Drop unreleased crates; keep axi-uartlite/axi-uart16550 (fixed in 0.2.0) --- crates/vorago-shared-hal/RUSTSEC-0000-0000.md | 56 ----------------- .../RUSTSEC-0000-0000.md | 46 -------------- crates/zynq7000-hal/RUSTSEC-0000-0000.md | 61 ------------------- 3 files changed, 163 deletions(-) delete mode 100644 crates/vorago-shared-hal/RUSTSEC-0000-0000.md delete mode 100644 crates/vorago-shared-periphs/RUSTSEC-0000-0000.md delete mode 100644 crates/zynq7000-hal/RUSTSEC-0000-0000.md diff --git a/crates/vorago-shared-hal/RUSTSEC-0000-0000.md b/crates/vorago-shared-hal/RUSTSEC-0000-0000.md deleted file mode 100644 index 260d08b57..000000000 --- a/crates/vorago-shared-hal/RUSTSEC-0000-0000.md +++ /dev/null @@ -1,56 +0,0 @@ -```toml -[advisory] -id = "RUSTSEC-0000-0000" -package = "vorago-shared-hal" -date = "2026-06-13" -informational = "unsound" -references = [ - "https://egit.irs.uni-stuttgart.de/rust/vorago-rs", - "https://egit.irs.uni-stuttgart.de/rust/vorago-rs/pulls/43", - "https://crates.io/crates/vorago-shared-hal", -] -keywords = ["dma", "async", "use-after-free", "soundness", "embedded"] - -[versions] -patched = [] -``` - -# vorago-shared-hal: use-after-free of a borrowed buffer via leaking an in-flight async transfer - -`vorago-shared-hal` 0.4.0 exposes **safe** asynchronous I/O that accepts a **non-`'static` borrowed -buffer** and erases its lifetime to hand a bare pointer to a peripheral interrupt / engine: - -- `impl embedded_io_async::Write for TxAsync` (`src/uart/tx_async.rs`) — UART TX (the TX interrupt - **reads** the buffer). -- the async SPI path (`src/spi/asynch.rs`) (RX: the SPI controller **writes** the buffer). - -Internally the buffer pointer is lifetime-erased (via `raw-slice`/`raw-buffer` `RawSlice`/ -`RawSliceMut`, e.g. `context.slice.get()` in `on_interrupt_tx`) and stored in a `static`; -cancellation safety relies **entirely** on the returned future's `Drop` to disable the interrupt. -Although `TxFuture::new` is `unsafe`, the obligation is **laundered through the safe -`embedded_io_async::Write` trait impl**, so a caller reaches the lifetime-erased store with no -`unsafe`. - -Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/arena reference -cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transfer future -while the borrow of the user buffer ends and its storage is freed or reused, after which: - -- **UART TX**: the interrupt reads freed storage and transmits it — **information disclosure**. -- **SPI RX**: the controller writes received bytes into freed storage — **memory corruption**. - -Reachable from safe code; neither the borrow checker nor Miri observes the peripheral access (it is -outside the abstract machine, and the lifetime is erased). Normal cancellation (dropping the future) -runs `Drop` and is handled; only *leaking* an in-flight future triggers it. Severity is -application-dependent, but the APIs are **unsound** (safe code can cause UB). - -## Remediation - -A fix marking the async TX write API `unsafe` was merged on the development branch (`vorago-rs` -PR #43, "TX async writes are unsafe now"), but **has not yet been published to crates.io** (0.4.0 -is the latest release and remains affected). Upgrade once a release `> 0.4.0` is available. Until -then, guarantee the buffer outlives any in-flight transfer and never leak an in-flight future. The -underlying `raw-buffer` crate's safety notes were also updated to document this obligation. - ---- -Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the -maintainer prior to publication. diff --git a/crates/vorago-shared-periphs/RUSTSEC-0000-0000.md b/crates/vorago-shared-periphs/RUSTSEC-0000-0000.md deleted file mode 100644 index f97b7dc0c..000000000 --- a/crates/vorago-shared-periphs/RUSTSEC-0000-0000.md +++ /dev/null @@ -1,46 +0,0 @@ -```toml -[advisory] -id = "RUSTSEC-0000-0000" -package = "vorago-shared-periphs" -date = "2026-06-13" -informational = "unsound" -references = [ - "https://egit.irs.uni-stuttgart.de/rust/vorago-shared-periphs", - "https://crates.io/crates/vorago-shared-periphs", -] -keywords = ["async", "use-after-free", "soundness", "embedded", "uart"] - -[versions] -patched = [] -``` - -# vorago-shared-periphs: information disclosure via leaking an in-flight async UART TX future - -`vorago-shared-periphs` 0.1.0 exposes a **safe** asynchronous UART transmit API -(`impl embedded_io_async::Write for TxAsync`, `src/uart/tx_asynch.rs`) that accepts a **non-`'static` -borrowed buffer** and erases its lifetime (via `raw-slice`/`raw-buffer` `RawSlice`) to hand a bare -pointer to the TX interrupt. Cancellation safety relies **entirely** on the returned future's `Drop` -to disable the interrupt, and the obligation is **laundered through the safe `Write` trait impl**. - -Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/arena reference -cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transmit future -(polled at least once, so the TX interrupt is armed) while the borrow of the user buffer ends and -its storage is freed or reused. The TX interrupt then keeps **reading the freed buffer and -transmitting its bytes on the wire** — an **information disclosure** of adjacent freed memory, -reachable with no `unsafe` in the caller. - -Neither the borrow checker nor Miri flags it (the interrupt access is outside the abstract machine -and the lifetime is erased). Normal cancellation (dropping the future) runs `Drop` and is handled; -only *leaking* an in-flight future triggers it. Severity is application-dependent, but the API is -**unsound** (safe code can cause UB). - -## Remediation - -Require `'static`/owned buffers (the `embedded-dma` convention), or otherwise guarantee the buffer -outlives any in-flight transfer; at minimum document on the safe method that leaking an in-flight -transfer future is a soundness hazard. The underlying `raw-buffer` crate's safety notes were updated -to document this obligation. - ---- -Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the -maintainer prior to publication. diff --git a/crates/zynq7000-hal/RUSTSEC-0000-0000.md b/crates/zynq7000-hal/RUSTSEC-0000-0000.md deleted file mode 100644 index 8d6c1b591..000000000 --- a/crates/zynq7000-hal/RUSTSEC-0000-0000.md +++ /dev/null @@ -1,61 +0,0 @@ -```toml -[advisory] -id = "RUSTSEC-0000-0000" -package = "zynq7000-hal" -date = "2026-06-13" -informational = "unsound" -references = [ - "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs", - "https://egit.irs.uni-stuttgart.de/rust/zynq7000-rs/pulls/89", - "https://crates.io/crates/zynq7000-hal", -] -keywords = ["dma", "async", "use-after-free", "soundness", "embedded"] - -[versions] -patched = [] -``` - -# zynq7000-hal: use-after-free of a borrowed buffer via leaking an in-flight async SPI/UART transfer - -`zynq7000-hal` 0.1.1 exposes **safe** asynchronous I/O that accepts a **non-`'static` borrowed -buffer** and erases its lifetime to hand a bare pointer to the SPI controller / UART interrupt: - -- `impl embedded_hal_async::spi::SpiBus for SpiAsync` — `read`, `transfer`, `transfer_in_place` - (RX path: the SPI controller **writes** the buffer). -- the async UART TX path (`embedded_io_async`) (the TX interrupt **reads** the buffer). - -Internally the buffer pointer is lifetime-erased (via the `raw-slice`/`raw-buffer` `RawSlice`/ -`RawSliceMut` types) and stored in a `static`; cancellation safety relies **entirely** on the -returned future's `Drop` (`SpiFuture::drop` → `reset_and_reconfigure`) to stop the peripheral. The -`SpiFuture` constructors (`new_for_read`, `new_for_transfer`, …) are **not `unsafe fn`**, so the -entire path from the safe `SpiBus` trait to the lifetime-erased store contains no `unsafe`. - -Because `core::mem::forget` is **safe** and skips `Drop` — as are other leaks (`Rc`/`RefCell`/arena -reference cycles, a leaked/aborted task, `Box::leak`) — safe code can leak an **in-flight** transfer -future (one polled at least once, so the peripheral is armed) while the borrow of the user buffer -ends and its storage is freed or reused. The peripheral then: - -- **SPI RX (`read`/`transfer`/`transfer_in_place`)**: writes received bytes into freed storage — - **memory corruption**, reachable from safe code with no `unsafe` in the caller. -- **UART TX**: the interrupt reads freed storage and transmits it on the wire — **information - disclosure** of adjacent freed memory. - -Normal cancellation (dropping the future) runs `Drop` and is handled; only *leaking* an in-flight -future triggers the issue. Neither the borrow checker nor Miri flags it: the peripheral access is -outside the Rust abstract machine, and the lifetime is erased. The trigger is not necessarily -attacker-controlled, so severity is application-dependent, but the APIs are **unsound** by Rust's -definition (safe code can cause UB). - -## Remediation - -A fix marking the async `TxAsync`/`SpiAsync` constructors `unsafe` and adding explicit buffer -lifetimes (`TxFuture<'uart, 'buf>`, `SpiFuture<'spi, 'read, 'write>`) was merged on the development -branch (`zynq7000-rs` PR #89, "Safety updates"), but **has not yet been published to crates.io** -(0.1.1 is the latest release and remains affected). Upgrade once a release `> 0.1.1` is available. -Until then, guarantee the buffer outlives any in-flight transfer and never leak an in-flight future. -The underlying `raw-buffer` crate's safety notes were also updated to document this obligation for -HAL/firmware authors. - ---- -Reported by Kyounghwan Kim (Pusan National University, kbhetrr@gmail.com); coordinated with the -maintainer prior to publication.