Skip to content

stack-encrypt: dispatch moves its key-request futures into a Box with leftover plaintext from the caller's stack, and frees it unwiped #1644

Open

Description

@yujiyokoo

Background

stack-encrypt is the Rust engine every CipherStash SDK encrypts through. It wipes plaintext from memory it frees, and two heap-hygiene tests check that. One is in stack-encrypt, tests/heap_hygiene.rs. The other is in the Python SDK, languages/python/crates/engine/src/heap_hygiene.rs. Each installs a spy allocator that fails when a freed heap block still contains a marker carried by the test's plaintext.

Problem

f6ffc3861 ("feat(stack-encrypt): load keysets beside the key retrieval, failing only the documents that need one") changed dispatch in packages/stack-encrypt/src/target/pending.rs (lines 696-697). It now builds the key-retrieval and keyset-load futures on the stack, then moves them into a Box. The move copies every byte of each future, including bytes the future never uses. Those bytes can still hold plaintext that the caller left on the stack.

The Python SDK builds its input frame from Python values, which leaves plaintext bytes on the stack, and then calls encrypt_with. After rebasing onto next, its encrypt and query heap tests each find one block of 696 bytes, freed with the plaintext marker in it. The free is in drop_in_place<Box<dispatch::{closure}::{closure}>>. With the stack wiped between building the frame and calling encrypt_with, the encrypt test passes. That shows the plaintext is leftover stack bytes, not data the future holds.

stack-encrypt's own heap test passes (26 tests), because none of its tests leave plaintext on the stack before calling dispatch. So nothing in stack-encrypt's CI catches this. Any caller can hit it, and the Go guest is one.

Proposal

  1. Add a case to stack-encrypt's tests/heap_hygiene.rs that leaves the marker on the stack before encrypt and query, and see it fail.
  2. Wipe the boxed futures' memory before it is freed, or build them without copying leftover stack bytes.
  3. Then turn the Python SDK's two heap tests back on. They are marked as known failures with a link to this issue.

Relationship to other work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    SDKneeds-triageMaintainer needs to evaluate the issuerustPull requests that update Rust code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions