Skip to content

LUKS header TOCTOU between validation and luksOpen #555

Closed as not planned
Closed as not planned

Description

@pbeza

The disk setup logic in dstack/dstack-util/src/system_setup.rs checks whether a LUKS header exists and then separately opens the device, creating a TOCTOU window where the header state could change between the check and the open.

Root Cause

The LUKS2 disk encryption setup follows a validate-then-use pattern with a time gap between the two operations:

  1. The LUKS header is backed up to tmpfs
  2. The header is validated (checking for null cipher — CVE-2025-59054 mitigation)
  3. cryptsetup luksOpen is called on the original device (not the validated copy)

Between steps 2 and 3, the on-disk header could be modified by a malicious host operator (who has direct access to the block device), replacing the validated header with a malicious one (e.g., null cipher).

Attack Path

  1. CVM starts disk encryption setup
  2. dstack backs up the LUKS header and validates it (no null cipher)
  3. Malicious host operator modifies the on-disk LUKS header between validation and luksOpen
  4. cryptsetup luksOpen uses the modified (malicious) header
  5. The attacker could set a null cipher, causing data to be written unencrypted despite passing validation

Impact

Potential bypass of the CVE-2025-59054 null cipher check. A sophisticated host operator with precise timing could substitute a malicious LUKS header after validation but before use. The practical exploitability depends on the timing window and the host's ability to modify the block device while the CVM is accessing it.

Suggested Fix

Use the validated header copy for luksOpen instead of the original device:

// Use --header flag to specify the validated header
cryptsetup luksOpen --header /tmp/validated-header.bin /dev/vdb encrypted

Or perform validation and open atomically using the backed-up header.


Note: This issue was created automatically. The vulnerability report was generated by Claude and has not been verified by a human.

Activity

  1. kvinwang commented on Mar 26, 2026

    @kvinwang
    Collaborator

    Thanks for the detailed report.

    We double-checked the current implementation in dstack-util/src/system_setup.rs. The flow today is:

    1. cryptsetup luksHeaderBackup copies the LUKS2 header into a file on a private tmpfs mount (/tmp/dstack-luks-header/luks-header).
    2. validate_luks2_headers reads and validates that tmpfs copy.
    3. cryptsetup luksOpen is invoked with --header $in_mem_hdr, so the validated header copy (not the on-disk header) is used.

    Because both validation and luksOpen operate on the same tmpfs-backed header file, there is no window where a modified on-disk header would be used after validation. In other words, the TOCTOU described in this issue does not apply to the current code.

    There is still a single point where we trust cryptsetup luksHeaderBackup to faithfully copy the header into tmpfs, but that is the same trust boundary we already rely on for the rest of the LUKS workflow.

    Given the above, we are going to leave the current implementation as-is. If you see a different practical attack path in the existing code, we are happy to take another look.

  2. h4x3rotab commented on Jun 30, 2026

    @h4x3rotab
    Contributor

    Maintainer triage update: this is recorded in the public security report table: https://github.com/Dstack-TEE/dstack/blob/master/docs/security/public-security-reports.md#public-reports-and-findings

    Disposition: not a production vulnerability. The setup code validates and opens the same in-memory LUKS header. No code fix is planned for this report under the documented production threat model.

    Closing as not planned.

  3. added
    securitySecurity-related issue, report, or hardening work
    security: reportPublic security report or already-public security finding
    security: not-production-vulnDoes not compromise supported production deployments under the documented threat model
    on Jun 30, 2026
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

    securitySecurity-related issue, report, or hardening worksecurity: not-production-vulnDoes not compromise supported production deployments under the documented threat modelsecurity: reportPublic security report or already-public security finding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions