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 | <CAOtMX2jb86vHegE2Nu8B8pL3=H4z9X=1_wfhpSHBi1bD7um5Ew@mail.gmail.com> |
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. https://github.com/BawdyAnarchist/quBSD/blob/88621ea7693514e4342c81478cd1b883d22b04a5/usr/local/libexec/qubsd/qb-ivpn#L222 > ᐧ >