Re: chflags -RL and symlinks pointing outside the traversal: preserve behavior or add a Capsicum guardrail?
Vadim Goncharov <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.hackers |
|---|---|
| Message-ID | <[email protected]> |
On Wed, 19 Aug 2026 10:46:47 -0600 Alan Somers <[email protected]> wrote: > On Wed, Aug 19, 2026 at 10:11 AM Mark Johnston <[email protected]> wrote: > > > > On Wed, Aug 19, 2026 at 09:40:35AM -0600, Alan Somers wrote: > > > On Wed, Aug 19, 2026 at 8:37 AM Jitendra Bhati > > > <[email protected]> wrote: > > > > > > > Hi all, > > > > > > > > As part of GSoC 2026 I'm capsicumizing chflags(1), using the new > > > > fts_openat(3) API: > > > > > > > > https://github.com/freebsd/freebsd-src/pull/2375 > > > > > > > > This raises a backward-compatibility question that Alan Somers and I > > > > think warrants wider input. > > > > > > > > In physical modes (-P, -h, and the default without -L) the traversal > > > > now runs inside Capsicum capability mode: chflags pre-opens a directory > > > > descriptor per argument, calls cap_enter(), and operates via: > > > > > > > > chflagsat(fts_parent->fts_dirfd, fts_name, ...); > > > > > > > > This confines chflags to the hierarchies named on the command line. > > > > > > > > The complication is -L (FTS_LOGICAL), where chflags follows symlinks. A > > > > followed symlink can point outside the traversal root, e.g.: > > > > > > > > file > > > > foo/bar/baz/link -> ../../../file > > > > > > > > Running: > > > > > > > > chflags -RL <flags> foo/bar > > > > > > > > today follows link and changes the flags on file, which lives outside > > > > foo/bar. Capability mode would block that access, because file isn't > > > > reachable from the descriptor opened for foo/bar. > > > > > > > > For now the PR preserves existing behavior: when -L is in effect it > > > > skips cap_enter() and keeps the historical path-based call: > > > > > > > > chflagsat(AT_FDCWD, p->fts_accpath, ...); > > > > > > > > So -L is not capsicumized, but nothing regresses. > > > > > > > > The open question: is "following a symlink out of the named hierarchy" > > > > behavior worth preserving, or is it exactly the kind of thing a > > > > Capsicum-ized chflags should refuse? A tree that redirects chflags at > > > > arbitrary files via a crafted symlink is arguably a threat we'd want to > > > > guard against. But it's also a long-standing, documented -L semantic, > > > > and changing it would be a POLA violation for anyone relying on it. > > > > > > > > Options: > > > > > > > > Keep -L as-is (path-based, not confined) - current PR behavior. > > > > Capsicumize -L too, and treat out-of-hierarchy symlink targets as an > > > > error. Capsicumize -L but keep out-of-hierarchy targets working by > > > > opening a descriptor for the resolved target's parent (loses most of > > > > the confinement benefit for -L). > > > > > > > > I lean toward (1) for this PR and revisiting -L separately, but I'd > > > > appreciate opinions on whether the stricter behavior is worth the > > > > compatibility break. > > > > > > > > Thanks, > > > > Jitendra Bhati > > > > > > > > > > I vote for #2. Capsicumize the utility, and treat out-of-hierarchy > > > symlinks as an error. I think that real users will almost never want to > > > follow out of hierarchy symlinks. Also, even if this is a POLA > > > violation, it's extremely rare. With grep, I couldn't find any example > > > of chflags -RL in the base system. Github code search turned up a few. > > > Some were MacOS Homebrew recipes that invoke chflags right after > > > installing the package. Those uses surely would prefer not to follow > > > out-of--hierarchy symlinks. The most interesting use I found was from > > > quBSD, a jail/bhyve manager. I don't know if that project really > > > intends to follow out-of-hierarchy symlinks or not, but I've notified > > > him. > > > > If we go this route, I think there does need to be a chicken switch for > > any users that are legitimately impacted and want an easy workaround. > > I'm not sure what that would look like: an environment variable, sysctl, > > new command-line option? Should any such chicken switch be global, > > i.e., should it apply to all capsicumized utilities which use fts? I > > presume you are planning to extend this to work with other fts-using > > utilities which might benefit more from running in a sandbox, like grep. > > As a chicken switch, I think that an environment variable would be too > easy to set by accident (and could even be set by an attacker). A > sysctl would be annoyingly difficult to implement, because it would > need to be checked from userspace, not from kernelspace. So a > command-line option would be best. However, I couldn't find any > examples of other existing tools that have such options. > > As for other utilities, there isn't enough time remaining in GSoC to > adapt any others. The original motivation for this project was > net/openrsync , which could really benefit. pax could really benefit > too, since malformed archive files are a classic attack vector (unless > pax only uses fts_open in create mode, not extract mode; I haven't > checked). But we chose to convert chflags first because it would be > easiest. I've scrolled via login.conf(5) to see what can be (ab)used for this instead, and my eye fall on "priority" - as user can't increase it's own priority level (decrease niceness), only decrease, this somewhat shields from environment variables changes by attacker. It's probably not better to implement than sysctl except absence of TOCTOU window when sysctl changes on the fly. Some arbitrary inherited process flags should exist here as a best solution, don't know if extended attributes in filesystem can provide this. -- WBR, @nuclight