Merge pull request #3178 from uchiha-bug-hunter/unzip-pathname-dotdot

unzip: reject bare '..' and trailing '/..' in pathname_is_insecure
(cherry picked from commit 94daafd6fb)
This commit is contained in:
Tim Kientzle authored and Martin Matuska committed 2026-07-26 20:08:44 +02:00
1 parent 3e38adf102
commit 31c306d809
5 files changed
+52 -1

No files matched your search

+2
View File
@@ -1723,6 +1723,7 @@ bsdunzip_test_SOURCES= \
unzip/test/test_o.c \
unzip/test/test_q.c \
unzip/test/test_symlink.c \
unzip/test/test_symlink_dotdot.c \
unzip/test/test_t.c \
unzip/test/test_t_bad.c \
unzip/test/test_u.c \
@@ -1761,6 +1762,7 @@ bsdunzip_test_EXTRA_DIST= \
unzip/test/test_singlefile.zip.uu \
unzip/test/test_symlink_1.zip.uu \
unzip/test/test_symlink_2.zip.uu \
unzip/test/test_symlink_dotdot.zip.uu \
unzip/test/test_t_bad.zip.uu \
unzip/test/test_u_new.zip.uu \
unzip/test/test_u_old.zip.uu \
+4 -1
View File
@@ -741,9 +741,12 @@ recheck:
static int
pathname_is_insecure(const char* pathname)
{
size_t len = strlen(pathname);
return (pathname[0] == '/' ||
strcmp(pathname, "..") == 0 ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL);
strstr(pathname, "/../") != NULL ||
(len >= 3 && strcmp(pathname + len - 3, "/..") == 0));
}
/*
+1
View File
@@ -16,6 +16,7 @@ IF(ENABLE_UNZIP AND ENABLE_TEST)
test_not_exist.c
test_singlefile.c
test_symlink.c
test_symlink_dotdot.c
test_C.c
test_p.c
test_d.c
+35
View File
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2026 Kaif Khan
* All rights reserved.
*/
#include "test.h"
/*
* A symlink whose target is a bare ".." (or a path ending in "/..")
* escapes the extraction directory just like "../" and "/../" do, so it
* must be rejected as insecure.
*/
DEFINE_TEST(test_symlink_dotdot)
{
const char *reffile = "test_symlink_dotdot.zip";
int r;
if (!canSymlink()) {
skipping("System cannot create symlinks.");
return;
}
extract_reference_file(reffile);
r = systemf("%s %s >test.out 2>test.err", testprog, reffile);
assertEqualInt(0, r);
/* The two insecure symlinks must be skipped, not created. */
assertFileNotExists("dotdot");
assertFileNotExists("traildot");
/* A regular entry in the same archive is still extracted. */
assertIsReg("safe.txt", 0644);
}
+10
View File
@@ -0,0 +1,10 @@
begin 644 test_symlink_dotdot.zip
M4$L#!!0`````````(0`<%@B6`@````(````&````9&]T9&]T+BY02P,$%```
M```````A`,6+J7@&````!@````@```!T<F%I;&1O='-U8B\N+E!+`P04````
M`````"$`?0X6V@,````#````"````'-A9F4N='AT;VL*4$L!`A0#%```````
M```A`!P6")8"`````@````8``````````````/^A`````&1O=&1O=%!+`0(4
M`Q0`````````(0#%BZEX!@````8````(``````````````#_H28```!T<F%I
M;&1O=%!+`0(4`Q0`````````(0!]#A;:`P````,````(``````````````"D
C@5(```!S869E+G1X=%!+!08``````P`#`*````![````````
`
end