Re: Have RESOLVE_* flags superseded AT_* flags for new syscalls?

From: Christian Brauner
Date: Mon Mar 02 2020 - 06:52:49 EST


On Mon, Mar 02, 2020 at 12:30:47PM +0100, Florian Weimer wrote:
> * Christian Brauner:
>
> > [Cc Florian since that ends up on libc's table sooner or later...]
>
> I'm not sure what you are after here â

Exactly what you've commented below. Input on whether any of these
changes would be either problematic if you e.g. were to implement
openat() on top of openat2() in the future or if it would be problematic
if we e.g. were to really deprecate AT_* flags for new syscalls.

>
> > On Fri, Feb 28, 2020 at 02:53:32PM +0000, David Howells wrote:
> >>
> >> I've been told that RESOLVE_* flags, which can be found in linux/openat2.h,
> >> should be used instead of the equivalent AT_* flags for new system calls. Is
> >> this the case?
> >
> > Imho, it would make sense to use RESOLVE_* flags for new system calls
> > and afair this was the original intention.
> > The alternative is that RESOLVE_* flags are special to openat2(). But
> > that seems strange, imho. The semantics openat2() has might be very
> > useful for new system calls as well which might also want to support
> > parts of AT_* flags (see fsinfo()). So we either end up adding new AT_*
> > flags mirroring the new RESOLVE_* flags or we end up adding new
> > RESOLVE_* flags mirroring parts of AT_* flags. And if that's a
> > possibility I vote for RESOLVE_* flags going forward. The have better
> > naming too imho.
> >
> > An argument against this could be that we might end up causing more
> > confusion for userspace due to yet another set of flags. But maybe this
> > isn't an issue as long as we restrict RESOLVE_* flags to new syscalls.
> > When we introduce a new syscall userspace will have to add support for
> > it anyway.
>
> I missed the start of the dicussion and what this is about, sorry.
>
> Regarding open flags, I think the key point for future APIs is to avoid
> using the set of flags for both control of the operation itself
> (O_NOFOLLOW/AT_SYMLINK_NOFOLLOW, O_NOCTTY) and properaties of the
> resulting descriptor (O_RDWR, O_SYNC). I expect that doing that would
> help code that has to re-create an equivalent descriptor. The operation
> flags are largely irrelevant to that if you can get the descriptor by
> other means.
>
> >> (*) It has been suggested that AT_SYMLINK_NOFOLLOW should be the default, but
> >> only RESOLVE_NO_SYMLINKS exists.
> >
> > I'd be very much in favor of not following symlinks being the default.
> > That's usually a source of a lot of security issues.
>
> But that's inconsistent with the rest of the system. And for example,
> if you make /etc/resolv.conf a symbolic link, a program which uses a new
> I/O library (with the new interfaces) will not be able to read it.

Fair, but I expect that e.g. a C library would simply implement openat()
on top of openat2() if the latter is available and thus could simply
pass RESOLVE_SYMLINKS so any new I/O library not making use of the
syscall directly would simply get the old behavior. For anyone using the
syscall directly they need to know about its exact semantics anyway. But
again, maybe just having it opt-in is fine.

>
> AT_SYMLINK_NOFOLLOW only applies to the last pathname component anyway,
> so it's relatively little protection.

So this is partially why I think it's at least worth considerings: the
new RESOLVE_NO_SYMLINKS flag does block all symlink resolution, not just
for the last component in contrast to AT_SYMLINK_NOFOLLOW. This is
278121417a72d87fb29dd8c48801f80821e8f75a

Christian