fix(rgp): reject traversal components and drop raw-path fallback#33
fix(rgp): reject traversal components and drop raw-path fallback#33bl4ckr0ss3 wants to merge 2 commits into
Conversation
The RGP `r` (register) sequence accepts a filesystem path from the terminal stream. `object_asset_path` was meant to sanitize it, but `load_object_source` also retried with the raw original `path` on the first error, so the sanitization was bypassed for any input the sanitizer rewrote into a non-existent location. The sanitizer itself also did not filter `..` components in the no-`assets`-anchor branch. Result: any process that can write to the terminal (`cat poisoned.log`, SSH banner, etc.) could make ratty load an arbitrary .obj/.glb from the user's filesystem. Fix: 1. Drop the `.or_else(|_| load_obj_meshes_from_path(path))` fallback in `load_object_source` so only the sanitized candidate is ever opened. 2. Reject any `ParentDir` / `RootDir` / `CurDir` component in `object_asset_path`, in both the `assets`-anchor and no-anchor branches. Legitimate inputs (bare filenames, `assets/...` paths) keep working unchanged. Closes orhun#32.
|
Thanks for the detailed issue and the PR! This looks good mostly, but I wasn't able to run the widget examples. Especially Can you adjust the widget examples based on the new asset loading changes as well? |
The widget examples were sending absolute paths (workspace-rooted `widget/assets/<obj>` and `target/live_draw.obj`) and relying on the `.or_else(|_| load_obj_meshes_from_path(path))` fallback in `load_object_source` to open them directly. That fallback was the traversal primitive removed in the previous commit, so the examples now fail to load any object. Move the widget OBJ assets into the project's asset root (`assets/widget/<name>`) and have each example send the sanitizer- friendly relative path `widget/<name>`. Ratty resolves that to `assets/widget/<name>` via the same logic that already handles bare asset filenames. `draw` writes its live-drawn preview to `assets/widget/.live_draw.obj` (gitignored) and sends `widget/.live_draw.obj`. `document` discovers and sends OBJ assets from the new location. `TempleOS.jpg` stays under `widget/assets/` because it is loaded directly by the widget process, not by Ratty. Per @orhun feedback on orhun#33.
|
thanks for testing! pushed a follow-up commit that updates the widget examples to work with the new restricted loader. changes:
verified lmk if you want big_rat updated too for consistency (it sends an absolute path to |
|
Moving widget assets to the root assets folder is not a good solution. It means that we will start embedding those assets into the Ratty binary which is unnecessary. |
|
rust_embed only globs |
|
oh got it, you're right! |
|
but then those assets won't be a part of the widget's crates.io release (which only includes the widget directory) which is still problematic :/ I think we should have those widgets assets in the widget folder respectively |
closes #32
what
two changes in
src/model.rs:.or_else(|_| load_obj_meshes_from_path(path))fallback inload_object_source. it retried with the raw, unsanitized attacker path on any error from the sanitized lookup, which defeatedobject_asset_pathfor any input the sanitizer rewrote into a non-existent location.ParentDir/RootDir/CurDircomponents in both branches ofobject_asset_path(theassets-anchor branch and the no-anchor fallback). legitimate inputs are unchanged.verified
added five unit tests in
src/model.rs::testscovering:../traversal -> rejectedassets/anchor -> rejectedobjects/<file>assets/objects/<file>-> still resolves toobjects/<file>also ran a standalone repro (no bevy/tobj, plain rustc) that mirrors the full
load_object_sourceresolution chain against both attack and legitimate inputs - all attacks now rejected, all legitimate paths unchanged. output:standalone repro source: https://gist.github.com/bl4ckr0ss3/35afe3ed0a29a42345f1e8f2a67be371 (i'll push the fixed version there too if useful).
not in this PR
there are a few smaller adjacent things i noticed while auditing (APC parser memory DoS via incomplete sequences in
inline.rs, kitty PNG decode without size limits inkitty.rs::finalize, kitty multipart byte buffer unbounded growth). i'll open separate issues for those, keeping this PR focused on the traversal fix.