Skip to content

ateapi: validate system-info projection paths at template creation - #1439

Merged
Taahir Ahmed (ahmedtd) merged 3 commits into
agent-substrate:mainfrom
thompsonmax:fix/system-info-path-validation
Sep 4, 2026
Merged

Taahir Ahmed (ahmedtd) merged 3 commits into
agent-substrate:mainfrom
thompsonmax:fix/system-info-path-validation

Conversation

@thompsonmax

@thompsonmax Max Thompson (thompsonmax) commented Sep 3, 2026 •

Copy link
Copy Markdown
Collaborator

CreateActorTemplate accepted ../escape and /escaped in ActorMetadataItem.path and TrustBundleDataSource.path, and accepted several data sources projecting to the same path. atelet only rejects the traversal at actor start, so the template is created but the golden actor sits in RESUMING. atelet never rejects duplicate paths at all: it writes the files in order and the last one wins.

This PR moves both checks to template validation.

  • The path rule lives in a new internal/volumepath package that both ateapi and atelet call, so the two cannot drift. It splits on / and rejects any segment that is empty, ., or .., caps depth at 16 segments, and rejects NUL bytes. Any other byte is allowed, so Unicode paths pass. ActorMetadataItem.path and TrustBundleDataSource.path apply it through a +k8s:customValidation hook, and atelet's writeSystemInfoFile applies it again before touching the host filesystem.
  • SystemInfoVolumeSource.data_sources gets a hook that tracks projected paths in a set and reports a duplicate on repeats, in the same shape as the Kubernetes projected-volume validation.

The proto doc comment on data_sources also says at most one actor_metadata entry may appear. Nothing enforces that, and this PR leaves it alone.

New cases in TestValidateSystemInfoVolumeSource and TestValidateTrustBundleDataSource cover the rejected shapes, and internal/volumepath has its own table test. hack/verify/codegen.sh and hack/verify/golangci-lint.sh pass.

#1231 moves writeSystemInfoFile into systeminfovolume.go and onto os.Root. Whichever PR lands second points that copy at the shared rule.

Fixes #1436
Fixes #1438

@ahmedtd

Copy link
Copy Markdown
Collaborator

ActorMetadataItem.path and TrustBundleDataSource.path get a +k8s:customValidation hook requiring a clean relative Unix path: no leading /, no empty, . or .. segments, and no control characters. That is the same segment rule as atelet's writeSystemInfoFile, plus the control-character rule mount_path already has.

This is good validation, but, just so I understand, did our use of os.Root already block any escapes using this?

@thompsonmax

Max Thompson (thompsonmax) commented Sep 4, 2026 •

Copy link
Copy Markdown
Collaborator Author

ActorMetadataItem.path and TrustBundleDataSource.path get a +k8s:customValidation hook requiring a clean relative Unix path: no leading /, no empty, . or .. segments, and no control characters. That is the same segment rule as atelet's writeSystemInfoFile, plus the control-character rule mount_path already has.

This is good validation, but, just so I understand, did our use of os.Root already block any escapes using this?

Yeah I believe the use of os.Root in #1231 should prevent escaping outside the systemInfoVolume root at actor run/restore in the common write function. The validation in this PR should catch this sooner during template creation.

@thompsonmax
Max Thompson (thompsonmax) force-pushed the fix/system-info-path-validation branch from 01a7b9b to 90a43d7 Compare September 4, 2026 18:23
@thompsonmax
Max Thompson (thompsonmax) force-pushed the fix/system-info-path-validation branch 2 times, most recently from e34d997 to 850bfde Compare September 4, 2026 22:05
CreateActorTemplate accepted path traversal ("../escape") and absolute
paths ("/escaped") in ActorMetadataItem.path and TrustBundleDataSource.path,
and accepted several data sources projecting to the same path. atelet
rejects the former only when the actor starts, leaving it stuck in
RESUMING, and silently clobbers the latter.

Both path fields now require a clean relative Unix path, and the
data_sources list rejects any path that repeats or names a directory of
another projected path.

Fixes agent-substrate#1436
Fixes agent-substrate#1438
…ate check

Move the system-info path rule into internal/volumepath so ateapi's template
validation and atelet's pre-write check call one implementation instead of
two that can drift. The rule splits on '/' and rejects empty, '.' and '..'
segments, caps depth at 16 segments, and scans bytes rather than runes,
rejecting only NUL so Unicode paths in any encoding pass.

Track projected paths in a set for the cross-data-source duplicate check,
mirroring the Kubernetes projected-volume validation, and drop the
directory-prefix check.
@thompsonmax
Max Thompson (thompsonmax) force-pushed the fix/system-info-path-validation branch from 850bfde to a05ebf1 Compare September 4, 2026 22:19
@ahmedtd
Taahir Ahmed (ahmedtd) merged commit 72e7906 into agent-substrate:main Sep 4, 2026
9 checks passed
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.

Duplicate projection paths accepted in SystemInfoVolumeSource SystemInfoVolumeSource accepts path traversal (e.g. ../)

2 participants