file: allow exec to return stdout as a file descriptor - #40
Open
JuliusBairaktaris wants to merge 1 commit into
Open
file: allow exec to return stdout as a file descriptor#40JuliusBairaktaris wants to merge 1 commit into
JuliusBairaktaris wants to merge 1 commit into
Conversation
rpc_file_exec captures stdout and stderr into ustreams capped at RPC_FILE_MAX_SIZE (256 KB); exceeding the cap fails the request with UBUS_STATUS_NOT_SUPPORTED and no output at all. That cap makes the method unusable for carrying a config backup archive. A non-root uhttpd cannot build a LuCI config backup because cgi-io forks /sbin/sysupgrade --create-backup as a CGI child inheriting uhttpd's uid, which cannot read /etc/shadow or 0600 configs. Letting rpcd run the command and hand the output back as a file descriptor keeps those reads in the root daemon. The new optional "stream" field (default false) writes the child's stdout to an anonymous memfd instead of a ustream buffer. When stream is false or absent the behaviour is byte-identical to before; stderr is still returned inline and capped as today. The memfd is attached to the deferred reply and carried to the caller via ubus fd passing; it is the same open file description opened by root, so the receiver needs no DAC bypass. The memfd is capped at 16 MB; the kernel enforces the cap via RLIMIT_FSIZE, killing a child that writes past the limit with SIGXFSZ at exactly the cap. Exit codes follow the shell convention: a signal-killed child reports 128 plus the signal number, so this surfaces as 153 (128 + SIGXFSZ) rather than the misleading 0 that WEXITSTATUS() yields for a signal death or a silently truncated stream. Assisted-by: Claude:claude-opus-5 Signed-off-by: Julius Bairaktaris <julius@bairaktaris.de>
JuliusBairaktaris
force-pushed
the
file-exec-stream-fd
branch
from
August 15, 2026 08:05
80053df to
1e12158
Compare
This was referenced Aug 7, 2026
Author
|
Adds This is the primitive that lets cgi-io hand back a |
This was referenced Aug 15, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Extend the
fileexecmethod with an optionalstreamfield. When set, the child's stdout is written to an anonymousmemfd_create()file instead of a ustream buffer, and the fd is handed back to the caller via ubus SCM_RIGHTS fd passing. This lifts the 256 KBRPC_FILE_MAX_SIZEcap that currently applies to captured command output and makes the method usable for carrying a config backup archive.A non-root uhttpd cannot build a LuCI config backup:
cgi-ioforks/sbin/sysupgrade --create-backupas a CGI child inheriting uhttpd's uid, which cannot read/etc/shadowor 0600 configs. With this change rpcd runs the command and returns the output as a file descriptor opened by root, so the receiver needs no DAC bypass. The caller is expected to checkcodefirst; the fd is attached whenever the fork succeeded so partial output can be inspected.When
streamis false or absent, behaviour is byte-identical to before. stderr is still returned inline and capped as today.The memfd is capped at 16 MB; a child exceeding it is killed and the request fails with
UBUS_STATUS_NOT_SUPPORTEDrather than silently truncating.Prerequisite for openwrt/openwrt#24558; pairs with #38.