Re: chflags -RL and symlinks pointing outside the traversal: preserve behavior or add a Capsicum guardrail?
Alan Somers <[email protected]>
| Newsgroups | gmane.os.freebsd.devel.hackers |
|---|---|
| Message-ID | <CAOtMX2gW=N=gFyS69pniqnFQFnQ8rAGcuvQ2COPsWYF9EhHsXg@mail.gmail.com> |
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.