Skip to content

sec: restore stack protection on the credential path - #130

Merged
douglasmun merged 1 commit into
mainfrom
sec/restore-stack-protector-credpath
Aug 23, 2026
Merged

sec: restore stack protection on the credential path#130
douglasmun merged 1 commit into
mainfrom
sec/restore-stack-protector-credpath

Conversation

@douglasmun

Copy link
Copy Markdown
Owner

The three files that parse attacker-supplied passwords (src/user.c, src/shell_user.c, src/shell.c) were the only part of the kernel built without -fstack-protector-strong, via per-file Makefile recipes that also set -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -O1. The exception was documented nowhere — not in CLAUDE.md, not in any doc/.

Why it is safe to remove

The stated reason was "PBKDF2 has deep call stacks that cause stack overflow with stack protection." That is obsolete: the kernel task stack was later raised 64 KB → 128 KB (KERNEL_TASK_STACK_PAGES = 32).

Measuring the two variables separately shows the protector was never the cost — max frame per file:

file O1 / noSSP O1 / SSP O2 / SSP (new)
src/user.c 40 40 836
src/shell.c 56 56 3308
src/shell_user.c 296 312 312

The protector costs 0–16 bytes. The larger frames under the restored recipe come from -O1-O2 (wider stack slots in one large function — the function count is unchanged, so nothing was inlined), and 3,308 bytes is negligible against 128 KB.

The three recipes now collapse to exactly the generic %.o rule, so they are deleted and replaced by a comment recording why the exception is gone.

Verification

  • warning-clean -Werror build
  • all three objects carry __stack_chk refs (i686-elf-nm), matching tcp.o as control
  • verify/verify-ring3-cred.sh PASS, with the typist trace showing a full passwd cycle reaching password updated successfully — PBKDF2 actually ran on the protected build and the session survived

Also in this PR

  • Two stale comments corrected. scheduler_ticks header and the IRQ0 block in interrupts.c both claimed context switches cannot happen from interrupts / that the interrupt frame is rewritten. Neither is true — interrupts.c:537 preempts, and the preempted task is suspended mid-ISR via context_switch(), resuming through iret, exactly as scheduler_schedule_from_interrupts own comment already documented.
  • doc/ARCHITECTURAL_SECURITY_ISSUES.md marked historical. All four issues are superseded by shipped code (copy_user.c + handle_copy_user_fault, preemption, wait_queue.c, VFS file_operations_t), each verified present.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CEkhAhgTxbE5TgifyYf8v4

src/user.o, src/shell_user.o and src/shell.o were built with
-fno-stack-protector -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -O1, so the three
files that parse attacker-supplied passwords were the only part of the kernel
without -fstack-protector-strong. That was recorded nowhere -- neither
CLAUDE.md nor any doc/ mentioned it.

The stated reason ("PBKDF2 has deep call stacks that cause stack overflow with
stack protection") is obsolete: the kernel task stack was later raised from
64 KB to 128 KB (KERNEL_TASK_STACK_PAGES = 32). Measuring the two variables
separately shows the protector was never the cost anyway -- max frame per file,
O1/noSSP vs O1/SSP: user.c 40->40, shell.c 56->56, shell_user.c 296->312. The
larger frames under the restored recipe (shell.c parse_and_execute 3308 bytes)
come from -O1 -> -O2 widening stack slots in one big function, not from the
protector, and are negligible against a 128 KB stack.

The three recipes now collapse to exactly the generic %.o rule, so they are
deleted and replaced by a comment recording why the exception is gone.

Verified: warning-clean -Werror build; all three objects carry __stack_chk
references (i686-elf-nm), matching tcp.o as a control; verify-ring3-cred.sh
PASSes, with the typist trace showing a full `passwd` cycle reaching
"password updated successfully" -- i.e. PBKDF2 actually ran, on the protected
build, and the session survived.

Also corrects two stale comments that asserted the opposite of the shipped
design: scheduler_tick's header and the IRQ0 block in interrupts.c both claimed
context switches cannot happen from interrupts / that the interrupt frame is
rewritten. Neither is true -- interrupts.c:537 preempts, and the preempted task
is suspended mid-ISR via context_switch() and resumes through iret, as
scheduler_schedule_from_interrupt's own comment already documented.

And marks doc/ARCHITECTURAL_SECURITY_ISSUES.md historical: all four issues are
superseded by shipped code (copy_user.c + handle_copy_user_fault, preemption,
wait_queue.c, VFS file_operations_t), each verified present in the tree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEkhAhgTxbE5TgifyYf8v4
@douglasmun
douglasmun merged commit 69798ff into main Aug 23, 2026
2 checks passed
@douglasmun
douglasmun deleted the sec/restore-stack-protector-credpath branch August 23, 2026 14:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant