[Toybox] [BUG] tar cannot handle files in non-writable dirs
Rob Landley
rob at landley.net
Mon Sep 15 09:59:06 PDT 2025
I composed this forever ago and never clicked "send", but lkml.iu.edu
came back and I got less depressed about the state of the linux
community, so...
On 8/26/25 03:47, Jesse Rosenstock wrote:
> It appears that toybox tar can't untar archives with files inside
> non-writable directories. GNU and BSD tar handle this.
Huh, for some reason I thought the dirflush() plumbing was deferring
chmod() as well as utimensat(). I thought I already had a test for that,
but I guess I was thinking of cp -a.
Which works differently: in cp we do a mkdirat() with | 0200 then an
openat() of the writeable directory, and then chmod the directory
afterwards which doesn't affect the status of existing filehandles. It
can even create new files in there after the chmod because openat() and
symlinkat() and friends use the filehandle permissions, not the dentry
permission.
The problem with tar is there's no direct relationship between different
entries in the archive, it's all just a bunch of "put something at this
path" nodes saved in order so creating a directory is unrelated to
putting something in that directory, so it doesn't cache directory
credentials. Each path is resolved separately for each node.
Changing the timestamp on files at paths didn't seem to have significant
security concerns. Changing permissions kind of does. (The classic race
condition where an inotify process does a mv of a file/directory out
from under tar and swaps in something else. That's hard to test for
cheaply, even the --restrict logic is just doing an xabspath and a
string comparison, there's no obvious "I atomically opened a filehandle
and then verify the filehandle goes to what I think" way to _eliminate_
the race window, or at least I can't think of it right now without
grubbing around in /proc. (I can read the filehandle's symlink in
/proc/self/fd to get an abspath for a filehandle, but is there a syscall
or fcntl() or something for it? Of course not...)
Sigh, I suppose I could make it safe if we have /proc and just skip the
test if not, but that smells like the hole THERE is to somehow hide
/proc from a process so it does an unsafe thing? (Hmmm, replacing /proc
with something else is security nightmare city and very much Not
Allowed, but _blocking_ proc seems like it might be more possible?)
Or I could have an abspath variant that does an
xreadlink("/proc/self/fd/%d") and then fall back to the expensive one if
it's not there...
Rob
More information about the Toybox
mailing list