<feed xmlns='http://www.w3.org/2005/Atom'>
<title>procd, branch master</title>
<subtitle>OpenWrt service / process manager</subtitle>
<id>https://git-03.infra.openwrt.org/project/procd/atom?h=master</id>
<link rel='self' href='https://git-03.infra.openwrt.org/project/procd/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/'/>
<updated>2026-10-07T14:29:53Z</updated>
<entry>
<title>service: add per-instance 'vrf' option</title>
<updated>2026-10-07T14:29:53Z</updated>
<author>
<name>Nick Hainke</name>
</author>
<published>2026-10-03T22:29:33Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=6a22d3964822f6d58fba4c4686e385ddb7e7fcb1'/>
<id>urn:sha1:6a22d3964822f6d58fba4c4686e385ddb7e7fcb1</id>
<content type='text'>
Add a 'vrf' instance attribute which binds all AF_INET/AF_INET6 sockets
of a service to a Linux VRF device, like 'ip vrf exec &lt;vrf&gt;' does,
without depending on iproute2, libbpf or libnl.

Before executing the service, procd attaches a BPF_PROG_TYPE_CGROUP_SOCK
program at BPF_CGROUP_INET_SOCK_CREATE to the cgroup of the instance,
which sets sk_bound_dev_if of every new socket to the ifindex of the
VRF. This is the mechanism iproute2 uses. The VRF is resolved with an
RTM_GETLINK request, which also checks that the device is a VRF.

Running the service outside of the VRF could expose it to, or let it
talk to, the wrong network. The service is therefore not executed if
the process can't be moved into the cgroup or the program can't be
attached, and the instance is rejected if 'vrf' is combined with a
bundle or a jail with its own or a joined network namespace, where the
cgroup or the ifindex wouldn't match.

The cgroup of an instance without a jail outlives the process, so a
program attached by an earlier run is detached if the instance has no
VRF anymore.

The sockets are bound to the ifindex of the VRF. Like for 'netdev',
restart the instance if the ifindex changed when the service is set
again, e.g. after the VRF device was recreated.

Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Nick Hainke &lt;vincent@systemli.org&gt;
</content>
</entry>
<entry>
<title>uxc: report every failure with one exit status</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:15:44Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=5670ff93498d57657377d9a06fa08f7919fa0389'/>
<id>urn:sha1:5670ff93498d57657377d9a06fa08f7919fa0389</id>
<content type='text'>
main() returns the negative errno its verb handler produced, so the
shell sees the low eight bits of it: 245 for EAGAIN, 254 for ENOENT,
234 for EINVAL and so on. ETIMEDOUT lands on 146, which a consumer
applying procd's signalled-death convention reads as SIGCONT, while
runc and crun answer 1 for any failure. Keep the errno for the
message and exit EXIT_FAILURE, covering the early returns that never
reach that tail, the detached console attach, and the raw ubus
statuses that start, boot and delete hand back. A failed autostart in
boot and a failed purge in reconcile become that same status, enable
and disable answer 0 once the config is written, and uxc-stack treats
a kill of an already stopped member as the normal case.

Fixes: bb4a4467b1d5 ("uxc: add container management CLI tool")
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: drop all capabilities for a bundle that names none</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:14:20Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=fa1f24c84ce70738e0445cb244e33492875a032e'/>
<id>urn:sha1:fa1f24c84ce70738e0445cb244e33492875a032e</id>
<content type='text'>
process.capabilities is parsed only when the bundle provides it, and
applyOCIcapabilities() returns early unless a set was parsed, so an
OCI container whose config.json omits the block keeps every
capability the runtime had. runc and crun pass the absent block
through as an empty set, and a container holding CAP_SYS_ADMIN can
undo its own maskedPaths and readonlyPaths, so the omission removes
the protection those depend on. Apply an empty set by default for a
bundle; a jail invoked directly with no -C is unchanged and still
keeps everything.

Fixes: ea7a790f210c ("jail: add support for running OCI bundle")
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: log a failing mask mount</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:13:10Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=4021843627a4a2f2c29446107bea56faa85a050a'/>
<id>urn:sha1:4021843627a4a2f2c29446107bea56faa85a050a</id>
<content type='text'>
The mask branch of do_mount() returns the caller's error code without
a message, so a failure to mask a critical path such as /proc/kcore
or /sys/firmware surfaces only as "mount_all() failed", and an
optional one leaves no trace at all even though the path it was meant
to hide stays visible. Report both, with the path and the errno.

Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: mount sysfs in the parent when the jail lacks a netns</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Joshua Covington</name>
</author>
<published>2026-09-27T19:07:46Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=8c9df2b8ae3216c2c7339f4e0603c1abbe608216'/>
<id>urn:sha1:8c9df2b8ae3216c2c7339f4e0603c1abbe608216</id>
<content type='text'>
Mounting sysfs needs CAP_SYS_ADMIN in the userns owning the netns. A
jail with a userns from clone() and no netns of its own gets EPERM for
-s or an OCI sysfs mount and does not start. fsmount() sysfs in the
parent before clone() with the queued flags and leave the fd for
do_mount_fd() to move_mount().

The mount is not MNT_LOCK_READONLY: only lock_mnt_tree() on a copy into
a less privileged userns sets it, and a clone-time userns makes no such
copy. A jail keeping CAP_SYS_ADMIN can remount /sys read-write.

Fixes: 6aa23a8b197e ("jail: give the container's namespaces to its own user namespace")
Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: factor out the MS_* to MOUNT_ATTR_* translation</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Joshua Covington</name>
</author>
<published>2026-09-27T19:06:54Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=56e1a2032e0d4accab6c591d05333598b3c16b88'/>
<id>urn:sha1:56e1a2032e0d4accab6c591d05333598b3c16b88</id>
<content type='text'>
Move the mount flag translation of idmap_tree_fd() into
mountflags_to_attr().

No functional change: MOUNT_ATTR_RELATIME is 0 and __ATIME is only
cleared when an atime flag is requested, so a clone with MNT_LOCK_ATIME
keeps its atime mode.

Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
</content>
</entry>
<entry>
<title>jail: let a joined namespace replace the created one</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:12:50Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=638c2ecfaf8a6f1a64614feadd550922ccef12b2'/>
<id>urn:sha1:638c2ecfaf8a6f1a64614feadd550922ccef12b2</id>
<content type='text'>
Every non-OCI jail has CLONE_NEWPID and CLONE_NEWIPC added to its
namespace set, and a join refused any namespace that set already
named. procd appends -j after the flags that populate it, so a jail
combining procfs, sysfs or netns with a -j entry for the same
namespace was rejected, and clone(CLONE_NEWPID) after
setns(CLONE_NEWPID) is EINVAL, so "-j &lt;pid&gt;:pid" never got past
clone() either. Clear the create bit of every joined namespace once
both the options and the bundle have been read, and fail when the pid
namespace cannot be entered.

A jail root has to be built in a mount namespace ujail owns, so an
entry naming one is refused where a jail filesystem was asked for,
and linux.namespaces entries keep their per-type uniqueness.

Fixes: c482c5de77f4 ("jail: add support for referencing existing namespaces")
Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: fail on an unresolvable -j specification</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:11:36Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=88fe395b2cd5e368f7b67770eeb82a0dadcf1d6b'/>
<id>urn:sha1:88fe395b2cd5e368f7b67770eeb82a0dadcf1d6b</id>
<content type='text'>
jail_join_ns() reports a stale pid or an unknown namespace type, but
the return value is discarded, so the jail starts with none of the
requested namespaces and one that asked for a user namespace runs as
host root in the initial one. Report the error and refuse to start.
Two of the names it accepts never resolved: "mount" and "network"
were used verbatim in /proc/&lt;pid&gt;/ns/&lt;name&gt;, where the links are
"mnt" and "net", and "mnt" was not accepted at all, so the mount
namespace could not be joined under any spelling. Keep the accepted
names and their links in one table.

Fixes: c482c5de77f4 ("jail: add support for referencing existing namespaces")
Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: join an external userns after build_jail_fs()</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:09:47Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=7f1b26ce3759c11cbdf78bb5cf2a9e7cd3f25c2b'/>
<id>urn:sha1:7f1b26ce3759c11cbdf78bb5cf2a9e7cd3f25c2b</id>
<content type='text'>
Mounting procfs needs CAP_SYS_ADMIN in the user namespace owning the
pid namespace. A jail joining a user namespace by -j entered it at
the top of exec_jail(), before any mount, while its pid namespace
comes from clone() in the parent and belongs to the initial user
namespace, so such a jail with -p failed with EPERM on its own /proc.
Build the jail fs privileged and join in enter_userns(), where a
deferred user namespace is created, so the join takes the same
phase-2 path.

That path applied its masks without looking at the result, so make
remask_after_unshare() report them and keep the critical ones fatal,
as mask_default_paths() does in phase 1. The /proc/sys read-only
self-bind follows it into phase 2 on the same terms: fatal, and left
alone when the bundle defines /proc/sys itself.

Fixes: c482c5de77f4 ("jail: add support for referencing existing namespaces")
Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
<entry>
<title>jail: apply root_map_uid to a joined user namespace</title>
<updated>2026-09-28T10:49:43Z</updated>
<author>
<name>Daniel Golle</name>
</author>
<published>2026-09-28T10:08:48Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/procd/commit/?id=ac855770e3b2b0043447e83c87bbcbe52bc7daef'/>
<id>urn:sha1:ac855770e3b2b0043447e83c87bbcbe52bc7daef</id>
<content type='text'>
The euid taken before clone(), the owner of the staged device nodes,
the overlay upper chown, the console hand-over and the devpts gid all
key on CLONE_NEWUSER, which -j does not set, and root_map_uid is never
derived for a joined namespace. The jail's root then finds the files
prepared for it owned by nobody. Derive the mapping by reading
/proc/&lt;pid&gt;/uid_map of the pid -j named: uid_m_show() renders the
outside column through the reader's user namespace, so reading it from
here yields a host uid at any nesting depth. The namespace fd pins the
namespace but not that pid, so the map counts only while
/proc/&lt;pid&gt;/ns/user still names the namespace ujail holds.

Those checks key on jail_has_userns(), false for a namespace given as
a path, where the map cannot be read and the ownership decisions would
act on a guess. The securebits restore instead keys on the namespace
being present, so one invocation always gets one securebits set.

Fixes: acf36f2777ae ("jail: seteuid before clone(CLONE_NEWUSER)")
Signed-off-by: Joshua Covington &lt;joshuacov@gmail.com&gt;
Signed-off-by: Daniel Golle &lt;daniel@makrotopia.org&gt;
</content>
</entry>
</feed>
