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:
1 parent
3e38adf102
commit
31c306d809
5 files changed
+52
-1
No files matched your search
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
Reference in new issue
Block a user