update.php fixes#2684
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughIn ChangesCommand Path Confinement
Estimated code review effort🎯 2 (Simple) | ⏱️ ~5 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
🔧 PR Test Plugin AvailableA test plugin has been generated for this PR that includes the modified files. Version: 📥 Installation Instructions:Install via Unraid Web UI:
Alternative: Direct Download
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@emhttp/plugins/dynamix/agents/tests/update_php_file_confinement_test.sh`:
- Around line 27-32: The confinement test is swallowing real `update.php`
execution failures by discarding all output and forcing success with `|| true`.
Update `update_php_file_confinement_test.sh` so the PHP probe around `include
"update.php"` still treats denied writes as passing, but surfaces non-zero PHP
exits when PHP is missing, `update.php` fatals, or the include setup breaks;
keep the `update.php` invocation path intact and remove the unconditional
success masking.
- Around line 35-50: The traversal assertion in assert_blocked is checking the
literal escaped path string instead of the normalized destination, so it can
miss files created after path resolution. Update assert_blocked to accept a
separate path to verify, and use that for the relative '..' traversal case while
keeping run_update pointed at the original traversal input. Make sure the check
in update_php_file_confinement_test.sh validates the actual resolved target
created by update.php, not the unnormalized literal.
In `@emhttp/update.php`:
- Line 70: The path resolution in update.php only falls back to the parent and
grandparent, so it can reject valid targets that are deeper under an allowed
root. Update the ancestor lookup around the $resolved_dir assignment to walk
upward from dirname($file) until the nearest existing directory is found, rather
than stopping after two checks. Keep the logic localized to the existing
resolution flow in update.php so the allowed-root validation continues to use
the resolved ancestor.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 473a14b1-dc08-4c48-b066-d95f59e65103
📒 Files selected for processing (4)
emhttp/plugins/dynamix/agents/tests/update_php_file_confinement_test.shemhttp/plugins/dynamix/include/FileUpload.phpemhttp/plugins/dynamix/include/Wrappers.phpemhttp/update.php
8b3ceda to
dd727fd
Compare
Verifying this change (not committed)One-line hardening of Offline check from the repo root — should print php -d short_open_tag=On -r '
error_reporting(0);
$_SERVER["DOCUMENT_ROOT"] = getcwd()."/emhttp";
$_POST = ["#command" => "../../../../../../bin/echo", "#arg" => ["PWNED"]];
chdir("emhttp"); include "update.php";
' | grep -q PWNED && echo "NOT contained" || echo "blocked"On a running server: an authenticated POST with |
dd727fd to
81ee6ac
Compare
Re-check the resolved #command path stays inside the document root before executing it, so an authenticated request cannot use realpath() traversal (e.g. starting at $docroot then '../') to run a binary outside the webgui. Refs: OS-488
81ee6ac to
a0a37dc
Compare
Restrict
update.php#filewrites to the expected configuration roots (/boot/config,/etc/wireguard) so a write cannot land outside config storage via an absolute path or...realpath()(collapsing../symlinks) and range-check it with a sharedin_safe_path()helper.in_safe_path()intoWrappers.phpsoupdate.phpandFileUpload.phpshare one implementation (drops the duplicate copy inFileUpload.php).update.phpand asserts out-of-root targets are refused while legitimate/boot/configwrites still succeed.Relative
#filepaths are unaffected (still placed under/boot/config/plugins/).Summary by CodeRabbit