[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