[Toybox] Poking at mountpoint.c

Rob Landley rob at landley.net
Sun Nov 30 09:46:51 PST 2014


I agree this is reproducing the logic of ubuntu's mountpoint command, but
that's not the same as being _right_.

  mkdir -p sub/{sub2,sub3}
  mount --bind sub/sub2 sub/sub3
  mountpoint sub/sub3

It misses --bind mounts on the same device. Then again so does the other
one, and in the absence of a spec I guess copying its bugs is the expected
behavior?

My attention got attracted back to this command because it's got one of the
strncat() instances I'm cleaning out, but limiting the input to sizeof(toybuf)
seems kind of gratuitous? Yes PATH_MAX is 4k but does the kernel actually
enforce that? You can make an arbitrarily long path on any posix
system via "mkdir -p ~/big/long/path; cd another/long/path; mv ~/big .",
rinse repeat. As for rules lawyering, you could have a legal path right
up against that and then add /.. at the end and go over. (Except you must
_add_ .. instead of truncating the path because "ls path/to/symlink/.." is
not the same as "ls path/to". Ok, we could realpath() and then truncate...)

Anyway, I lean towards using *toys.optargs directly up until we need to
modify it, then just xmprintf() to malloc a new one. Common case is under 4k,
pathological case is max environment size (128k). Presumably if we
feed more than PATH_MAX to the kernel _and_ it cares, it'll give us an errno.

Apparently the -d flag should suppress the "this is a mountpoint output",
and just give the major:minor.

I'm worried about not checking the return value of the second stat(), something
fortify apparently isn't bothering to warn us about despite that being switched
back on (there are _reasons_ I'm not a fan of that "feature"), although I guess
it would take an rm -r race to trigger it (and thus make us check uninitialized
memory).

The other stat("valid/..") failure case I was worried about was that it's
possible to have a directory that's readable when its parent isn't, once again
through bind mounts, but it turns out the .. goes back to the parent of the
bind mount not the parent of the directory bound to. (Long ago .. was an entry
that lived in the filesystem, and now it's handled at the vfs level so it can
vary for those sort of things.)

The test I just ran was:

  $ mkdir -p test/one/two
  $ mkdir test/two
  $ sudo mount --bind test/one/two test/two
  $ chmod 000 test/one
  $ touch test/two/walrus
  $ ls -l test/two
  total 0
  -rw-rw-r-- 1 landley landley 0 Nov 30 10:30 walrus
  $ ls -l test/two/..
  total 8
  d--------- 3 landley landley 4096 Nov 30 10:30 one
  drwxrwxr-x 2 landley landley 4096 Nov 30 10:30 two

And then sudo umount test/two to clean it up. Hmmm, did I ever implement
"umount -a dirname" to unmount everything under this directory? Basically a
built-in version of my zapchroot script:

  http://landley.net/hg/aboriginal/file/tip/sources/root-filesystem/sbin/zapchroot

So many todo list items. Like a "kill -r" that does this:

  # Kill a process and all its decendants

  killtree()
  {
    local KIDS=""

    while [ $# -ne 0 ]
    do
      KIDS="$KIDS $(pgrep -P$1)"
      shift
    done

    KIDS="$(echo -n $KIDS)"
    if [ ! -z "$KIDS" ]
    then
      # Depth first kill avoids reparent_to_init hiding stuff.
      killtree $KIDS
      kill $KIDS 2>/dev/null
    fi
  }

Or adjusting timeout.c to have an option to reset the kill timer every time
the child produces output (so it's a _hang_ timeout instead of just a
deadline). And yes, I have a script in aboriginal linux that's doing THAT
too:

  http://landley.net/hg/aboriginal/file/tip/more/timeout.sh

That one was outright _awkward_ to implement in bash...

Aha, you CAN have a directory that's readable but its parent isn't, the
current directory. Just "chmod 000 .." and you can still read the directory
you're _in_ but not the one above it. (Another process can chmod 000 your
parent too, and . is still readable because the kernel isn't rechecking the
path to it.)

So yeah, that stat() should be xstat() in mountpoint.c.

mountpoint -d -x /proc

Last one wins?

mountpoint -x -d /proc

No, it doesn't, -x always wins. This is a badly implemented command. I'm
going with "last one wins"...

Rob

P.S. Yeah, a bit scatterbrained today. I should probably... SQUIRREL!


More information about the Toybox mailing list