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/mounts → self/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.
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/mountsthrough rpcd, and that read is now being denied.AI-generated root-cause analysis
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 therealpath()-resolved target./proc/mountsis a procfs magic symlink —/proc/mounts→self/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/mountspasses 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):
Both are granted
readin the same ACL group./proc/mtd(not a symlink) succeeds;/proc/mounts(magic symlink) is denied.Verified by live-patching the device ACL:
/proc/self/mounts→ still denied (realpath resolvesselfto the PID)/proc/[0-9]*/mounts→ read succeeds (matches/proc/<pid>/mounts)So the
selfspelling 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"". Itshas_rootfs_datagate then falls back to looking for arootfs_dataentry in/proc/mtd. Squashfs+jffs2 devices have that partition, so the button still renders; UBI devices keeprootfs_dataas a UBI *volume* (not in/proc/mtd`), so both signals are gone and the button is droppeThe broken
/proc/mountsread also affects other callers, e.g. `luci-app-statisPossible 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.