[Toybox] [PATCH] cpio: Use chown pathname versiong
Vincent Donnefort
vdonnefort at google.com
Thu Mar 9 07:21:18 PST 2023
On Wed, Mar 08, 2023 at 07:01:53PM -0600, Rob Landley wrote:
> On 3/8/23 11:05, Vincent Donnefort via Toybox wrote:
> > CPIOs archives might contain dev nodes which could also point to
> > unavailable drivers. In that case, fopen would simply fail, making it
> > impossible for cpio to change the ownership.
>
> Did you have this issue, or are you fixing a theoretical?
I do have this issue. Although after further investigation, it is due to the
"nodev" attribute of the mount point. The scenario described in the commit
description is nonetheless still a problem.
>
> > Switch to the pathname version for chown and stat to circumvent this
> > limitation.
> >
> > Change-Id: I5f7202bf19f4c3d4f750cdd72ed0c467f9166da6
> >
> > diff --git a/toys/posix/cpio.c b/toys/posix/cpio.c
> > index 282a39b1..b1a20203 100644
> > --- a/toys/posix/cpio.c
> > +++ b/toys/posix/cpio.c
> > @@ -226,14 +226,11 @@ void cpio_main(void)
> > if (!S_ISREG(mode) && !S_ISLNK(mode) && !geteuid()
> > && !FLAG(no_preserve_owner))
> > {
> > - int fd = open(name, O_RDONLY|O_NOFOLLOW);
> > struct stat st;
> >
> > - if (fd != -1 && !fstat(fd, &st) && (st.st_mode&S_IFMT) == (mode&S_IFMT))
> > - err = fchown(fd, uid, gid);
> > + if (!stat(name, &st) && (st.st_mode&S_IFMT) == (mode&S_IFMT))
> > + err = chown(name, uid, gid);
>
> The race that stat() tries to defend against is making that the object we're
> doing the fchown() on is at least the same _kind_ of object we placed there, so
> it's not vulnerable to inotify/symlink attacks where you stick your own file
> there and suddenly it belongs to somebody else. (I'd also like to compare the
> timestamps but that's unfortunately fraught...) Your change has a race window
> between the stat() and the chown() where there's no guarantee they're operating
> on the same filesystem object.
I see. But I don't think, we can really open a dev node without expecting
anything on the driver side. e.g. a watchdog node, might point to a driver with
NO_WAY_OUT (and then reset the system), which sounds more risky than what the
open is protecting against. Maybe instead I could relax that test only for the
device node case?
>
> In theory the open should use O_PATH, and I think I tried that at one point, but
> in practice the granularity is wrong: neither "can operate on the file
> descriptor" and "can operate on the contents" are "only operate on the
> metadata". (And then there's the fun of "does MacOS or FreeBSD even have that
> flag", but I've handwaved past that before, it's what portability.h is for...)
Sadly O_PATH doesn't work for fchown. (returns -EBADFD)
>
> That said there's more options: the reason eject.c has open(O_NONBLOCK) is so it
> doesn't try to spin up the CD in the drive before the open returns, and in
> theory I could do similar kinds of tricks here... but not without a test case to
> see what specifically I'm trying to fix.
You should be able to reproduce the issue quite easily with `mknod c 1 3` in a
cpio archive and to extract it on a mount point with nodev.
Thanks for your prompt reply to this patch!
--
Vincent
>
> Rob
>
> P.S. Nope, O_DIRECTORY isn't the right granularity either. You'd think "can do
> metadata but not data" would be an obvious level since that's what half the
> existing syscalls that then got an openat() version already do, but so far...
> _______________________________________________
> Toybox mailing list
> Toybox at lists.landley.net
> http://lists.landley.net/listinfo.cgi/toybox-landley.net
More information about the Toybox
mailing list