[Toybox] [PATCH] Support diff --no-dereference

Rob Landley rob at landley.net
Fri Aug 23 00:46:26 PDT 2024


On 8/22/24 08:23, enh via Toybox wrote:
> +  int s = sizeof(toybuf)/2;
> +
> +  TT.is_symlink = 1;
> +  for (i = 0; i < 2; i++) {
> +    TT.link[i].name = toybuf + i * s;
> +    TT.link[i].len = readlink0(files[i], TT.link[i].name, s);
> 
> should probably use xreadlink() and free() instead? toybuf is big
> enough to be safe for _one_ path on linux, but not two.

Eh, no arbitrary buffer is "enough". PATH_MAX is slowly getting phased out, and
even posix-2008 requires arbitrary depth for "rm" because:

$ for ((i=0;i<10000;i++)); do mv a b; mkdir a; mv b a/a; done

And rm -rf has to be able to cope with that. (Note that's _in_ a long path when
it does a mkdir, it's extending from the TOP. Plus "mount" could always splice
PATH_MAX to PATH_MAX...)

Meanwhile, symlinks are inherently problematic because the kernel's recursion
counter resolving them is per-link so if your $PWD has a few links in it and
then you go into another /path/from/root that also has symlinks in it you can
run out of dereferences without ever hitting anything _like_ recursion.

What we really need is loop detection, which is tricksy because dereferencing
"ln -s . potato" isn't a loop. Loops only happen when you follow a symlink to an
absolute path...

Anyway, a 256 byte buffer would handle 99% of the cases, and this is likely to
handle all the ones we'd ever actually hit. If we want a proper fix what we need
is to teach readlink0() to dynamically allocate a buffer, and THAT has the
problem that the kernel API returns "error" for buffer not big enough without
telling us how big a buffer we NEED, so you have to iteratively guess...

Rob


More information about the Toybox mailing list