feat(scheduler-core): implement recording directory provisioning and path validation (task 9.1)

Adds --record-dir CLI flag and sched_validate_record_filename() with
canonical-path containment (realpath()-based, not textual-prefix) plus
separator/".." rejection before any filesystem access.

Adversarial review found and this task fixed two CWE-59 inode-aliasing
bypasses: a direct hard link inside record_dir aliasing an outside file,
and a compound variant where a symlink pointed at an in-directory file
itself hard-linked outside record_dir. Both closed via st_nlink checks
on the direct entry and the fully-resolved symlink target respectively,
each verified with a live RED->GREEN reproduction. TOCTOU residual risk
documented and deferred to task 9.2 (O_NOFOLLOW + fstat() re-check).

18/18 recording subtests, 24/24 scheduler suite, clang-format clean.
This commit is contained in:
Rongsong Shen 2026-08-05 05:39:22 +00:00
parent 31ef5d7093
commit 4e5547ee55
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk
8 changed files with 889 additions and 30 deletions

View file

@ -393,6 +393,25 @@ sched_snapshot_save_load_test = executable(
dependencies: [scheduler_test_deps],
install: false)
# White-box test for the recording-directory path-validation function
# (scheduler-core spec, task 9.1, Req 5 AC 10 "Record file path
# validation"): rejects a recordFile containing a path separator or a ".."
# segment BEFORE any filesystem access, and confirms containment beneath
# record_dir via a genuine canonical-path (realpath()) comparison rather
# than a textual prefix match -- including a symlink-escape case and the
# "record_dir vs record_dir-evil sibling" prefix-match trap named in this
# task's own security brief. Same white-box #include pattern as
# test_job_update.c/test_handlers.c (pulls the real
# ../src/recording.c into this TU) -- the function under test has no
# scheduler-struct fixture dependency at all, so this is the simplest
# white-box test in this directory.
sched_recording_path_validation_test = executable(
'sched_recording_path_validation_test',
['test_recording_path_validation.c'],
include_directories:[incdir],
dependencies: [scheduler_test_deps],
install: false)
# Register as meson tests so `meson test --suite scheduler` runs them all.
# detect_leaks=0 matches the suite convention (fixtures are not torn down).
test('scheduler test', scheduler_test, suite: 'scheduler',
@ -453,3 +472,6 @@ test('scheduler driver session ordering test',
test('scheduler snapshot save load test',
sched_snapshot_save_load_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
test('scheduler recording path validation test',
sched_recording_path_validation_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])