fix: validate D-Bus method inputs server-side #49
Loading…
Reference in a new issue
No description provided.
Delete branch "mysticalsoap/fix/service-input-validation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The second half of #18: polkit (#47) settled who may call the root service, but the methods still trusted whatever an authorized caller sent — caller-controlled names reached
setattr/getattron the service object, path-shaped values were joined underROOTDIRwithout containment (an escaping openvpn config path is a root-exec primitive viaupscripts),change_ovpn_configpointed root at an arbitrary caller directory,import_threadroot-wrote into a directory named in the dict, andcfgupdate/fwupdatewrote raw caller bytes to root-owned files.Fix
New helpers
utils.valid_name()(single path segment: nonempty, no/, not./..) andutils.inside_rootdir()(realpath containment — catches.., absolute paths, and symlink escapes), applied server-side:connect_to_server/set_hop: server dicts validated (name/provideras names,pathmust resolve underROOTDIR); tunnel threads live in atunnel_threadsdict instead ofsetattr(self, "<name>_dict"), killing the arbitrary-attribute writestart_import_thread/cancel_import: same dict-registry treatment (import_threads);cancel_importno-ops on unknown providers instead ofAttributeErrorimport_thread: provider name validated; the download directory is now derived from the D-Bus caller (GetConnectionUnixUser→pwd) instead of trusting ahomedirvalue in the dict — root no longer writes to a caller-chosen path. Per-provider storage also fixes concurrent imports clobbering each other's targetchange_ovpn_config: signature changedss→sa{ss}— the GUI reads its own files with its own privileges and sends contents; the service writes only to fixed per-provider locations with validated filenames. Root never reads a caller-named pathdelete_provider: provider validated before it reachesshutil.rmtreereturn_tun_device: whitelisted totun/tun_hop/tun_bypass(wasgetattrwith any string)log_level_change: whitelisted to real log levels (wasgetattr(logging, ...))cfgupdate/fwupdate: must parse as a JSON object; the parsed object is re-serialized, so arbitrary bytes can't land in root-owned filesbypass: interface names must exist pernetifacesorg.aqomui.service.InvalidInputRelated fixes (found along the way, technically out of scope)
apply_editassigned the temp filename but never wrote it, then told the service to copy the temp dir (stale or empty). Sending contents directly fixes it structurally."config.HOMEDIR"instead of"homedir", soimport_threadraisedKeyErrorevery time the 5-day refresh fired. Deriving the directory server-side removes the key entirely; both GUI dicts dropped it.Verification
python -W error::SyntaxWarning -m compileall aqomui/clean; CI runs pytest/rufftests/test_utils.pycovers both helpers (traversal, absolute paths, symlink escape, the root itself); all cases verified locally before pushingchange_ovpn_configGUI flow is worth one manual modify-server pass whenever a package is next installedCloses #18
Assisted-by: claude-fable-5