Skip to content

nut: improve rpcd acl / luci-app-acl effectiveness - #30055

Draft
danielfdickinson wants to merge 4 commits into
openwrt:masterfrom
danielfdickinson:pr-nut-improve-acl-effectiveness
Draft

nut: improve rpcd acl / luci-app-acl effectiveness#30055
danielfdickinson wants to merge 4 commits into
openwrt:masterfrom
danielfdickinson:pr-nut-improve-acl-effectiveness

Conversation

@danielfdickinson

@danielfdickinson danielfdickinson commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

📦 Package Details

Maintainer: @danielfdickinson

Description:
Reduce opportunities for an untrusted user with UCI write access to escalate privileges or write arbitrary configurations (i.e. config not part of their ACL).

  • Introduces config_get_single which only allows accepts 7-bit ASCII characters from UCI configuration settings
  • Splits UCI configuration files into main for each service, and a _root config. The _root configuration holds any configuration which is or could lead to root-equivalence (such as setting RUNAS user, and defining executable notification commands).
  • Uses config_load in a subshell where needed, so that the _root configurations do not get mixed in with the non-_root configurations.
  • More validation of inputs

Hotplug scripts only use the non-root upsd configs, and have a separate variable context, so isolating their config_load in a subshell is not necessary.

We do however improve hotplug behavior for remove
and add logic to prevent thrashing on boot or hotplug

On boot, hotplug events were causing excessive start and stop action
for the upsd daemon and driver daemons. We fix that with two primary
actions:

  1. Don't restart service daemons on hotplug until after first boot
    has completed.
  2. Use more robust handling of procd instance starts by ensuring
    that the first start starts the nut-server service and all
    others add to the nut-server service (rather than replacing it).

Also introduce some a 'sleep' in hotplug to reduce bouncing, and
ignore hotplug events without a DEVNAME.

In addition clean up some logging and fix custom notification message config generation.

Corresponding LuCI PR is openwrt/luci#8851


🧪 Run Testing Details

Lightly tested

  • OpenWrt Version: OpenWrt SNAPSHOT r35431-4f2dc5cc64
  • OpenWrt Target/Subtarget: bcm27xx/bcm2709
  • OpenWrt Device: Raspberry Pi 2 Model B Rev 1.1

Re-tested on

  • OpenWrt Version: OpenWrt SNAPSHOT r35906-3d1645ee26
  • OpenWrt Target/Subtarget: bcm27xx/bcm2709
  • OpenWrt Device: Raspberry Pi 2 Model B Rev 1.1

TODO: Re-test SSL (using a second device).


✅ Formalities

  • I have reviewed the CONTRIBUTING.md file for detailed contributing guidelines.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 new commit; the commit message accurately describes the changes.


Generated by Claude Code

Comment thread net/nut/files/nut-monitor.init Outdated
Comment thread net/nut/files/nut-common.sh.functions Outdated
Comment thread net/nut/files/nut-server.init Outdated
Comment thread net/nut/files/nut-monitor-config.sh.functions Outdated
@danielfdickinson
danielfdickinson force-pushed the pr-nut-improve-acl-effectiveness branch from 4846a40 to 19955db Compare July 21, 2026 07:06
@danielfdickinson
danielfdickinson marked this pull request as ready for review July 21, 2026 07:08

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 1 new commit; no new issues found.

The changes since the last review are all correct fixes: removing the duplicate check_safe_hostname_or_ip definition, correcting the log_config_load_error label to nut_monitor_root, fixing the interface_reload_delay validation (the value is now assigned from val before the check), and switching exit 1 to return 1 in loop_through_drivers for consistency with its callers.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Strengthens NUT’s UCI→runtime configuration pipeline to reduce privilege-escalation and config-injection opportunities when an untrusted user has UCI write access, primarily by separating “root-equivalent” settings into dedicated *_root UCI configs and tightening how UCI values are retrieved.

Changes:

  • Added config_get_single helper to sanitize UCI-sourced values (printable 7-bit ASCII) and migrated many call sites to use it.
  • Split configurations into service configs vs. new *_root configs, and adjusted init/config-generation scripts to load them in subshells to avoid mixed UCI contexts.
  • Updated init scripts and triggers to account for the new *_root configs (install + conffiles + reload triggers), plus related hotplug adjustments.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
net/nut/Makefile Bumps release; installs and marks new *_root UCI config templates as conffiles.
net/nut/files/nut-service.sh.functions Switches triggerlist retrieval to config_get_single.
net/nut/files/nut-server.init Uses config_get_single broadly; isolates root config loads via subshells; adds reload trigger for nut_server_root.
net/nut/files/nut-server-service.sh.functions Adds helper to fetch sanitized UPS option values from nut_server in an isolated subshell.
net/nut/files/nut-server-config.sh.functions Migrates UCI reads to config_get_single; separates user/root bits into nut_server_root loading.
net/nut/files/nut-serial.hotplug Uses config_get_single for port to reduce unsafe UCI value handling.
net/nut/files/nut-monitor.init Moves RUNAS lookup into nut_monitor_root via subshell; adds reload trigger for nut_monitor_root.
net/nut/files/nut-monitor-config.sh.functions Splits non-root vs root options (e.g., NOTIFYCMD/SHUTDOWNCMD) into nut_monitor_root; uses isolated config_load subshells.
net/nut/files/nut-common.sh.functions Introduces config_get_single and config_get_single_unsafe.
net/nut/files/nut-cgi.init Splits nut_cgi vs nut_cgi_root loads into subshells; adds reload trigger for nut_cgi_root.
net/nut/files/nut_server_root New root-only UCI template for upsd_root and user sections.
net/nut/files/nut_server Removes user/runas/statepath examples from non-root config template.
net/nut/files/nut_monitor_root New root-only UCI template for RUNAS/notify/shutdown and monitor credentials/notifications.
net/nut/files/nut_monitor Removes root-equivalent examples from non-root config template.
net/nut/files/nut_cgi_root New root-only UCI template for upsset enable flag.
net/nut/files/nut_cgi Removes upsset section from non-root config template.
net/nut/files/libhid-ups.hotplug Uses config_get_single for vendor/product IDs when matching USB devices.
Suppressed comments (1)

net/nut/files/nut-monitor-config.sh.functions:266

  • This block runs inside a subshell (...). Using return 1 here can behave unexpectedly (or return from the outer function rather than failing the subshell). Use exit 1 so the subshell reliably fails and the outer ) || return 1 handles it.
		for event in $event_notify_flags_not_found; do
			if ! printf "NOTIFYFLAG %s %s\n" "$event" "$defaultnotify" >>"$config_file"; then
				log_error "upsmon section '$cfg' failed to write 'NOTIFYFLAG' for '$event'" nut-monitor-config.sh nut-monitor-config
				return 1
			fi

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread net/nut/files/nut-monitor.init Outdated
Comment thread net/nut/files/nut-monitor.init
Comment thread net/nut/files/nut-monitor-config.sh.functions
Comment thread net/nut/files/nut-monitor-config.sh.functions Outdated
@danielfdickinson
danielfdickinson force-pushed the pr-nut-improve-acl-effectiveness branch from 19955db to 41a0fc7 Compare August 3, 2026 06:01

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the rebased commit. The four changes since the last review (comment typo, dead SHUTDOWNCMD case removal, returnexit inside the notify-flag subshell, exitreturn in service_preconditions) all look correct: SHUTDOWNCMD is no longer in NUT_UPSMON_OPTIONS so the removed case really was unreachable, and exit 1 at nut-monitor-config.sh.functions:250 now matches the other bail-outs in that same subshell.

While re-reading the surrounding blocks I found two find_* call sites in nut-server.init that still pass the pre-split package name, which makes the new nut_server_root settings inert — details inline. Nothing here blocks a merge decision beyond that; the rest is one nit.


Generated by Claude Code

Comment thread net/nut/files/nut-server.init Outdated
Comment thread net/nut/files/nut-server.init Outdated
Comment thread net/nut/files/nut-monitor.init Outdated
Comment thread net/nut/files/nut-server-config.sh.functions Outdated
@danielfdickinson
danielfdickinson force-pushed the pr-nut-improve-acl-effectiveness branch 3 times, most recently from 8095f4b to e5addb4 Compare August 3, 2026 07:24

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes since the last review (rebase onto master plus three fixes). All three are correct: the find_statepath/find_runas call sites in nut-server.init now pass nut_server_root and drop the dead printf, and nut-monitor.init now captures find_runas's stdout instead of testing an unset RUNAS. The commit message still matches the diff.

One question on the new nut-monitor.init fallback, and — from re-reading the config split as a whole — one thing that looks like it could bite on upgrade: the sections that moved to the *_root configs have no migration path, so an existing install keeps them in the old conffile where nothing reads them any more. Details inline; the rest is two nits.


Generated by Claude Code

Comment thread net/nut/files/nut-server-config.sh.functions
Comment thread net/nut/files/nut-monitor.init
Comment thread net/nut/files/nut_monitor_root Outdated
Comment thread net/nut/files/nut_server_root
@danielfdickinson
danielfdickinson marked this pull request as draft August 5, 2026 04:35
@danielfdickinson
danielfdickinson force-pushed the pr-nut-improve-acl-effectiveness branch from e5addb4 to c969dbe Compare August 24, 2026 03:54

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the 3 new commits since the last review (1a8141f hotplug-remove short-circuits, fd0037d NOTIFYMSG quoting, c969dbe service-thrashing refactor). Commit messages match their diffs. One inline issue on the c969dbe boot-sentinel gate in nut-serial.hotplug.


Generated by Claude Code

Comment thread net/nut/files/nut-serial.hotplug Outdated
Reduce opportunities for an untrusted user with UCI write access to
escalate privileges or write arbitrary configurations (i.e. config not
part of their ACL).

* Introduces config_get_single which only allows accepts 7-bit ASCII
  characters from UCI configuration settings
* Splits UCI configuration files into main for each service, and a
  [service]_root config. The _root configuration holds any configuration
	which is or could lead to root-equivalence (such as setting RUNAS
	user, and defining executable notification commands).
* Uses config_load in a subshell where needed, so that the _root
  configurations do not get mixed in with the non-_root configurations.
* More validation of inputs

Hotplug scripts do not require changes, as they only use the non-root
upsd configs, and have a separate variable context, so isolating their
config_load in a subshell is not necessary.

Signed-off-by: Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>
Short-circuit parts of the hotplug script on remove, and only do
some parts for ACTION='add'.

Signed-off-by: Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>
Messages with spaces must be enclosed in double-quotes.

Signed-off-by: Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>
On boot, hotplug events were causing excessive start and stop action
for the upsd daemon and driver daemons. We fix that with two primary
actions:
  1. Don't restart service daemons on hotplug until after first boot
     has completed.
  2. Use more robust handling of procd instance starts by ensuring
     that the first start starts the nut-server service and all
     others add to the nut-server service (rather than replacing it).

Also introduce some a 'sleep' in hotplug to reduce bouncing, and
ignore hotplug events without a DEVNAME.

In addition clean up some logging.

Signed-off-by: Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>
@danielfdickinson
danielfdickinson force-pushed the pr-nut-improve-acl-effectiveness branch from c969dbe to 1fccc74 Compare August 24, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants