A secret larger than about half the locked-memory limit crashes secret add, import and generate secret with a panic #145

Open
opened 2026-10-13 00:30:29 +02:00 by clawbot · 0 comments
Collaborator

Severity: major. The command dies with a Go stack trace instead of an error. With the common default ulimit -l of 8 MB (this host), any secret over 4 MB crashes, far below the 100 MB limit the error text and the tests name. Nothing stored is damaged: the crash comes before the lock is taken.

ulimit -l                                        # 8192
head -c 4000000 /dev/zero | secret add big4      # ok
head -c 5000000 /dev/zero | secret add big5
# panic: ... could not acquire lock on 0x..., limit reached? [Err: cannot allocate memory]
secret generate secret huge -l 20000000          # same panic
head -c 104857601 /dev/zero | secret add toobig  # panic, not "secret too large: exceeds 100MB limit"

Where.

buffer := memguard.NewBuffer(currentBufferSize)
and
valueBuffer := memguard.NewBuffer(totalSize)
(the value is held twice, in the read buffers and the combined copy, so the ceiling is half the limit),
secretBuffer := memguard.NewBufferFromBytes([]byte(secretValue))
. memguard panics when mlock fails.

Correct behaviour. A command fails with an error. Recommended: raise RLIMIT_MEMLOCK to its hard limit at startup; check the size against the limit before allocating and fail with a message naming it; avoid the second full copy; state the real limit in the README (the 100 MB number is only reachable with a raised limit).

Definition of done

  • A secret over the locked-memory limit fails with an error naming the limit, exit status 1, no stack trace.
  • A secret over 100 MB gets "secret too large" before any locked allocation.
  • A test with the limit lowered (setrlimit) or a size just over it fails before the fix.

Model: fable-5-1

Severity: major. The command dies with a Go stack trace instead of an error. With the common default `ulimit -l` of 8 MB (this host), any secret over 4 MB crashes, far below the 100 MB limit the error text and the tests name. Nothing stored is damaged: the crash comes before the lock is taken. ``` ulimit -l # 8192 head -c 4000000 /dev/zero | secret add big4 # ok head -c 5000000 /dev/zero | secret add big5 # panic: ... could not acquire lock on 0x..., limit reached? [Err: cannot allocate memory] secret generate secret huge -l 20000000 # same panic head -c 104857601 /dev/zero | secret add toobig # panic, not "secret too large: exceeds 100MB limit" ``` **Where.** https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/secrets.go#L309 and https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/secrets.go#L346 (the value is held twice, in the read buffers and the combined copy, so the ceiling is half the limit), https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/generate.go#L173. memguard panics when `mlock` fails. **Correct behaviour.** A command fails with an error. Recommended: raise `RLIMIT_MEMLOCK` to its hard limit at startup; check the size against the limit before allocating and fail with a message naming it; avoid the second full copy; state the real limit in the README (the 100 MB number is only reachable with a raised limit). **Definition of done** - A secret over the locked-memory limit fails with an error naming the limit, exit status 1, no stack trace. - A secret over 100 MB gets "secret too large" before any locked allocation. - A test with the limit lowered (`setrlimit`) or a size just over it fails before the fix. Model: fable-5-1
sneak was assigned by clawbot 2026-10-13 00:30:30 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/secret#145