On Thu, 11 Apr 2024 at 11:13, Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote: > > So while I understand your motivation, I actually think it's actively > wrong to special-case __O_TMPFILE, because it encourages a pattern > that is bad. Just to clarify: I think the ns_capable() change is a good idea and makes sense. The whole "limited to global root" makes no sense if the file was opened within a namespace, and I think it always just came from the better check not being obvious at the point where AT_EMPTY_PATH was checked for. Similarly, while the FMODE_PATH test _looks_ very similar to an O_TMPFILE check, I think it's fundamentally different in a conceptual sense: not only is FMODE_PATH filesystem-agnostic, a FMODE_PATH file is *only* useful as a pathname (ie no read/write semantics). And so if a FMODE_PATH file descriptor is passed in from the outside, I feel like the "you cannot use this to create a path" is kind of a fundamentally nonsensical rule. IOW, whoever is passing that FMODE_PATH file descriptor around must have actually thought about it, and must have opened it with O_PATH, and it isn't useful for anything else than as a starting point for a path lookup. So while I don't think the __O_TMPFILE exception would necessarily be wrong per se, I am afraid that it would result in people writing convenient code that "appears to work" in testing, but then fails when run in an environment where the directory is mounted over NFS (or any other filesystem that doesn't do ->tmpfile()). I am certainly open to be convinced otherwise, but I really think that the real pattern to aim for should just be "look, I opened the file myself, then filled in the detail, and now I'm doing a linkat() to expose it" and that the real protection issue should be that "my credentials are the same for open and linkat". The other rules (ie the capability check or the FMODE_PATH case) would be literally about situations where you *want* to pass things around between protection domains. In that context, the ns_capable() and the FMODE_PATH check make sense to me. In contrast, the __O_TMPFILE check just feels like a random detail. Hmm? Anyway, end result of that is that this is what that part of the patch looks like for me right now: + if (flags & LOOKUP_DFD_MATCH_CREDS) { + const struct cred *cred = f.file->f_cred; + if (!(f.file->f_mode & FMODE_PATH) && + cred != current_cred() && + !ns_capable(cred->user_ns, CAP_DAC_READ_SEARCH)) { + fdput(f); + return ERR_PTR(-ENOENT); + } + } and that _seems_ sensible to me. But yes, this all has been something that we have failed to do right for at least a quarter of a century so far, so this needs a *lot* of thought, even if the patch itself is rather small and looks relatively obvious. Linus