Skip to content

Commit 749c8db

Browse files
author
kalibera
committed
Add path component filtering.
git-svn-id: https://svn.r-project.org/R/trunk@88296 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 4a3aa15 commit 749c8db

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

src/main/dounzip.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* R : A Computer Language for Statistical Data Analysis
33
* file dounzip.c
4-
* first part Copyright (C) 2002-2023 The R Core Team
4+
* first part Copyright (C) 2002-2025 The R Core Team
55
* second part Copyright (C) 1998-2010 Gilles Vollant
66
*
77
* This program is free software; you can redistribute it and/or modify
@@ -33,6 +33,7 @@
3333
#endif
3434
#include <errno.h>
3535
#include <stdlib.h>
36+
#include <string.h>
3637

3738
#ifdef Win32
3839
#include <io.h> /* for mkdir */
@@ -149,17 +150,28 @@ extract_one(unzFile uf, const char *const dest, const char * const filename,
149150
R_fixslash(outname); /* ensure path separator is / */
150151
#endif
151152
p = outname + strlen(outname) - 1;
153+
bool warned = FALSE;
152154
if (*p == '/') { /* Directories are stored with trailing slash */
153155
if (!junk) {
154156
*p = '\0';
155157
if (!R_FileExists(outname)) {
156158
/* make parents as required: have already checked dest exists */
157159
pp = outname + strlen(dest) + 1;
158160
while((p = Rf_strchr(pp, '/'))) {
159-
strcpy(dirs, outname);
160-
dirs[p - outname] = '\0';
161-
if (!R_FileExists(dirs)) R_mkdir(dirs);
162-
pp = p + 1;
161+
if (p - pp == 2 && !strncmp(pp, "..", 2)) {
162+
if (!warned) {
163+
warning(
164+
_("skipped \"../\" path component(s) in '%s'"),
165+
fn);
166+
warned = true;
167+
}
168+
memmove(pp, p + 1, strlen(p + 1) + 1);
169+
} else {
170+
strcpy(dirs, outname);
171+
dirs[p - outname] = '\0';
172+
if (!R_FileExists(dirs)) R_mkdir(dirs);
173+
pp = p + 1;
174+
}
163175
}
164176
err = R_mkdir(outname);
165177
}
@@ -168,11 +180,21 @@ extract_one(unzFile uf, const char *const dest, const char * const filename,
168180
/* make parents as required: have already checked dest exists */
169181
pp = outname + strlen(dest) + 1;
170182
while((p = Rf_strchr(pp, '/'))) {
171-
strcpy(dirs, outname);
172-
dirs[p - outname] = '\0';
173-
/* Rprintf("dirs is %s\n", dirs); */
174-
if (!R_FileExists(dirs)) R_mkdir(dirs);
175-
pp = p + 1;
183+
if (p - pp == 2 && !strncmp(pp, "..", 2)) {
184+
if (!warned) {
185+
warning(
186+
_("skipped \"../\" path component(s) in '%s'"),
187+
fn);
188+
warned = true;
189+
}
190+
memmove(pp, p + 1, strlen(p + 1) + 1);
191+
} else {
192+
strcpy(dirs, outname);
193+
dirs[p - outname] = '\0';
194+
/* Rprintf("dirs is %s\n", dirs); */
195+
if (!R_FileExists(dirs)) R_mkdir(dirs);
196+
pp = p + 1;
197+
}
176198
}
177199
/* Rprintf("extracting %s\n", outname); */
178200
if (!overwrite && R_FileExists(outname)) {

0 commit comments

Comments
 (0)