Skip to content

file: reading /proc/mounts via ubus denied, breaks LuCI factory-reset button #37

Description

@naseef

What was noticed

On a UBI-rootfs device running current OpenWrt main, the LuCI System → Backup / Flash Firmware page no longer shows the "Perform reset" (factory reset) button.
Tracing it down, the button is gated on LuCI reading /proc/mounts through rpcd, and that read is now being denied.


AI-generated root-cause analysis

The analysis below was produced by an AI agent with SSH access to the live affected device. The commands and their outputs are from that device.

Root cause: rpcd commit e37ed9d ("file: re-authorize ACL against resolved path to close symlink bypass", 2026-07-19, Fixes GHSA-q5gr-86pq-vvwr) re-checks the ACL against the realpath()-resolved target. /proc/mounts is a procfs magic symlink — /proc/mountsself/mounts/proc/<pid>/mounts — so the resolved path carries the runtime PID and can never match a static ACL entry, even though the granted textual path /proc/mounts passes the first check.

This appears to be an unintended side effect of an otherwise correct security fix; it is the current rpcd HEAD, with no follow-up.

Reproducer (on the live device, via a real ubus/LuCI session):

ubus call file read '{"path":"/proc/mtd"}'      -> OK
ubus call file read '{"path":"/proc/mounts"}'   -> Permission denied  (status 6)

Both are granted read in the same ACL group. /proc/mtd (not a symlink) succeeds; /proc/mounts (magic symlink) is denied.

readlink /proc/mounts   -> self/mounts
readlink /proc/self     -> <pid>
# realpath(/proc/mounts) = /proc/<pid>/mounts

Verified by live-patching the device ACL:

  • add /proc/self/mounts → still denied (realpath resolves self to the PID)
  • add /proc/[0-9]*/mounts → read succeeds (matches /proc/<pid>/mounts)

So the self spelling cannot fix it, and the PID-glob is only an ugly workaround.

Why the button disappears (and why only on some devices): LuCI's flash.js .trimmed(), which swallows the denial and returns "". Its has_rootfs_datagate then falls back to looking for a rootfs_dataentry in/proc/mtd. Squashfs+jffs2 devices have that partition, so the button still renders; UBI devices keep rootfs_dataas a UBI *volume* (not in/proc/mtd`), so both signals are gone and the button is droppe

The broken /proc/mounts read also affects other callers, e.g. `luci-app-statis

Possible fix (rpcd side): don't apply the resolved-path re-authorization to ranted textual path already passed — e.g. skip when realpath() only differs by a /proc/self/proc/<pid> substitution, or re-authorize against the granted textual prefix rather than requiring an exact ACL entry for the resolved target.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions