Merge commit from fork

unzip: reject absolute or traversing symlink targets
(cherry picked from commit 9bd1a06adb)
This commit is contained in:
Tobias Stoeckmann authored and Martin Matuska committed 2026-07-26 20:08:06 +02:00
1 parent d70c3e24e0
commit 3e38adf102
1 file changed
+19 -3
+19 -3
View File
@@ -738,6 +738,14 @@ recheck:
error("close('%s')", *path);
}
static int
pathname_is_insecure(const char* pathname)
{
return (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL);
}
/*
* Extract a zipfile entry: first perform some sanity checks to ensure
* that it is either a directory or a regular file and that the path is
@@ -757,6 +765,7 @@ static void
extract(struct archive *a, struct archive_entry *e)
{
char *pathname, *realpathname;
const char *linktarget;
mode_t filetype;
char *p, *q;
@@ -768,15 +777,22 @@ extract(struct archive *a, struct archive_entry *e)
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL) {
if (pathname_is_insecure(pathname)) {
warningx("skipping insecure entry '%s'", pathname);
ac(archive_read_data_skip(a));
free(pathname);
return;
}
if (S_ISLNK(filetype) &&
((linktarget = archive_entry_symlink(e)) != NULL) &&
pathname_is_insecure(linktarget)) {
warningx("skipping insecure symlink '%s' to '%s'", pathname, linktarget);
ac(archive_read_data_skip(a));
free(pathname);
return;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) {
warningx("skipping non-regular entry '%s'", pathname);