mirror of
https://codeberg.org/landley/toybox.git
synced 2026-01-26 14:13:25 +00:00
Tar extract should delete files or symlinks where it's making a directory,
but --restrict checking should run on the path up to the last component before unlinking so tar can't be tricked into deleting random files off the system.
This commit is contained in:
parent
01f18c4c6e
commit
b30fd4cb65
@ -525,7 +525,8 @@ void xstat(char *path, struct stat *st)
|
||||
|
||||
// Canonicalize path, even to file with one or more missing components at end.
|
||||
// Returns allocated string for pathname or NULL if doesn't exist
|
||||
// exact = 1 file must exist, 0 dir must exist, -1 show theoretical location
|
||||
// exact = 1 file must exist, 0 dir must exist, -1 show theoretical location,
|
||||
// -2 don't resolve last file
|
||||
char *xabspath(char *path, int exact)
|
||||
{
|
||||
struct string_list *todo, *done = 0;
|
||||
@ -570,7 +571,8 @@ char *xabspath(char *path, int exact)
|
||||
}
|
||||
|
||||
// Is this a symlink?
|
||||
len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf));
|
||||
if (exact == -2 && !todo) len = 0;
|
||||
else len = readlinkat(dirfd, new->str, libbuf, sizeof(libbuf));
|
||||
if (len>4095) goto error;
|
||||
|
||||
// Not a symlink: add to linked list, move dirfd, fail if error
|
||||
|
||||
@ -386,25 +386,32 @@ static void wsettime(char *s, long long sec)
|
||||
}
|
||||
|
||||
// Do pending directory utimes(), NULL to flush all.
|
||||
static int dirflush(char *name)
|
||||
static int dirflush(char *name, int isdir)
|
||||
{
|
||||
char *s = 0, *ss;
|
||||
|
||||
// Barf if name not in TT.cwd
|
||||
if (name) {
|
||||
ss = s = xabspath(name, -1);
|
||||
if (TT.cwd[1] && (!strstart(&ss, TT.cwd) || *ss!='/')) {
|
||||
error_msg("'%s' not under '%s'", name, TT.cwd);
|
||||
if (!(ss = s = xabspath(name, -1-isdir))) {
|
||||
error_msg("'%s' bad symlink", name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (TT.cwd[1] && (!strstart(&ss, TT.cwd) || (*ss && *ss!='/'))) {
|
||||
error_msg("'%s' %s not under '%s'", name, s, TT.cwd);
|
||||
free(s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// --restrict means first entry extracted is what everything must be under
|
||||
if (FLAG(restrict)) {
|
||||
free(TT.cwd);
|
||||
TT.cwd = strdup(s);
|
||||
toys.optflags ^= FLAG_restrict;
|
||||
}
|
||||
// use resolved name so trailing / is stripped
|
||||
if (isdir) unlink(s);
|
||||
}
|
||||
|
||||
// Set deferred utimes() for directories this file isn't under.
|
||||
@ -467,14 +474,14 @@ static void extract_to_disk(void)
|
||||
char *name = TT.hdr.name;
|
||||
int ala = TT.hdr.mode;
|
||||
|
||||
if (dirflush(name)) {
|
||||
if (dirflush(name, S_ISDIR(ala))) {
|
||||
if (S_ISREG(ala) && !TT.hdr.link_target) skippy(TT.hdr.size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// create path before file if necessary
|
||||
if (strrchr(name, '/') && mkpath(name) && errno !=EEXIST)
|
||||
if (strrchr(name, '/') && mkpath(name) && errno!=EEXIST)
|
||||
return perror_msg(":%s: can't mkdir", name);
|
||||
|
||||
// remove old file, if exists
|
||||
@ -895,7 +902,7 @@ void tar_main(void)
|
||||
}
|
||||
|
||||
unpack_tar(hdr);
|
||||
dirflush(0);
|
||||
dirflush(0, 0);
|
||||
|
||||
// Each time a TT.incl entry is seen it's moved to the end of the list,
|
||||
// with TT.seen pointing to first seen list entry. Anything between
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user