diff options
Diffstat (limited to 'archival')
-rw-r--r-- | archival/libarchive/data_extract_all.c | 28 | ||||
-rw-r--r-- | archival/libarchive/unsafe_symlink_target.c | 59 | ||||
-rw-r--r-- | archival/tar.c | 2 | ||||
-rw-r--r-- | archival/unzip.c | 25 |
4 files changed, 49 insertions, 65 deletions
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index d3a6df5e8..8fa69ffaf 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -107,9 +107,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
107 | } | 107 | } |
108 | } | 108 | } |
109 | else if (existing_sb.st_mtime >= file_header->mtime) { | 109 | else if (existing_sb.st_mtime >= file_header->mtime) { |
110 | if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | 110 | if (!S_ISDIR(file_header->mode)) { |
111 | && !S_ISDIR(file_header->mode) | ||
112 | ) { | ||
113 | bb_error_msg("%s not created: newer or " | 111 | bb_error_msg("%s not created: newer or " |
114 | "same age file exists", dst_name); | 112 | "same age file exists", dst_name); |
115 | } | 113 | } |
@@ -125,7 +123,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
125 | /* Handle hard links separately */ | 123 | /* Handle hard links separately */ |
126 | if (hard_link) { | 124 | if (hard_link) { |
127 | res = link(hard_link, dst_name); | 125 | res = link(hard_link, dst_name); |
128 | if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { | 126 | if (res != 0) { |
129 | /* shared message */ | 127 | /* shared message */ |
130 | bb_perror_msg("can't create %slink '%s' to '%s'", | 128 | bb_perror_msg("can't create %slink '%s' to '%s'", |
131 | "hard", dst_name, hard_link | 129 | "hard", dst_name, hard_link |
@@ -165,10 +163,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
165 | } | 163 | } |
166 | case S_IFDIR: | 164 | case S_IFDIR: |
167 | res = mkdir(dst_name, file_header->mode); | 165 | res = mkdir(dst_name, file_header->mode); |
168 | if ((res == -1) | 166 | if ((res != 0) |
169 | && (errno != EISDIR) /* btw, Linux doesn't return this */ | 167 | && (errno != EISDIR) /* btw, Linux doesn't return this */ |
170 | && (errno != EEXIST) | 168 | && (errno != EEXIST) |
171 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | ||
172 | ) { | 169 | ) { |
173 | bb_perror_msg("can't make dir %s", dst_name); | 170 | bb_perror_msg("can't make dir %s", dst_name); |
174 | } | 171 | } |
@@ -198,27 +195,16 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
198 | * | 195 | * |
199 | * Untarring bug.tar would otherwise place evil.py in '/tmp'. | 196 | * Untarring bug.tar would otherwise place evil.py in '/tmp'. |
200 | */ | 197 | */ |
201 | if (!unsafe_symlink_target(file_header->link_target)) { | 198 | create_or_remember_symlink(&archive_handle->symlink_placeholders, |
202 | res = symlink(file_header->link_target, dst_name); | 199 | file_header->link_target, |
203 | if (res != 0 | 200 | dst_name); |
204 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | ||
205 | ) { | ||
206 | /* shared message */ | ||
207 | bb_perror_msg("can't create %slink '%s' to '%s'", | ||
208 | "sym", | ||
209 | dst_name, file_header->link_target | ||
210 | ); | ||
211 | } | ||
212 | } | ||
213 | break; | 201 | break; |
214 | case S_IFSOCK: | 202 | case S_IFSOCK: |
215 | case S_IFBLK: | 203 | case S_IFBLK: |
216 | case S_IFCHR: | 204 | case S_IFCHR: |
217 | case S_IFIFO: | 205 | case S_IFIFO: |
218 | res = mknod(dst_name, file_header->mode, file_header->device); | 206 | res = mknod(dst_name, file_header->mode, file_header->device); |
219 | if ((res == -1) | 207 | if (res != 0) { |
220 | && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) | ||
221 | ) { | ||
222 | bb_perror_msg("can't create node %s", dst_name); | 208 | bb_perror_msg("can't create node %s", dst_name); |
223 | } | 209 | } |
224 | break; | 210 | break; |
diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c index 441ba8b24..8dcafeaa1 100644 --- a/archival/libarchive/unsafe_symlink_target.c +++ b/archival/libarchive/unsafe_symlink_target.c | |||
@@ -5,44 +5,37 @@ | |||
5 | #include "libbb.h" | 5 | #include "libbb.h" |
6 | #include "bb_archive.h" | 6 | #include "bb_archive.h" |
7 | 7 | ||
8 | int FAST_FUNC unsafe_symlink_target(const char *target) | 8 | void FAST_FUNC create_or_remember_symlink(llist_t **symlink_placeholders, |
9 | const char *target, | ||
10 | const char *linkname) | ||
9 | { | 11 | { |
10 | const char *dot; | 12 | if (target[0] == '/' || strstr(target, "..")) { |
11 | 13 | llist_add_to(symlink_placeholders, | |
12 | if (target[0] == '/') { | 14 | xasprintf("%s%c%s", linkname, '\0', target) |
13 | const char *var; | 15 | ); |
14 | unsafe: | 16 | return; |
15 | var = getenv("EXTRACT_UNSAFE_SYMLINKS"); | 17 | } |
16 | if (var) { | 18 | if (symlink(target, linkname) != 0) { |
17 | if (LONE_CHAR(var, '1')) | 19 | /* shared message */ |
18 | return 0; /* pretend it's safe */ | 20 | bb_perror_msg_and_die("can't create %slink '%s' to '%s'", |
19 | return 1; /* "UNSAFE!" */ | 21 | "sym", linkname, target |
20 | } | ||
21 | bb_error_msg("skipping unsafe symlink to '%s' in archive," | ||
22 | " set %s=1 to extract", | ||
23 | target, | ||
24 | "EXTRACT_UNSAFE_SYMLINKS" | ||
25 | ); | 22 | ); |
26 | /* Prevent further messages */ | ||
27 | setenv("EXTRACT_UNSAFE_SYMLINKS", "0", 0); | ||
28 | return 1; /* "UNSAFE!" */ | ||
29 | } | 23 | } |
24 | } | ||
30 | 25 | ||
31 | dot = target; | 26 | void FAST_FUNC create_symlinks_from_list(llist_t *list) |
32 | for (;;) { | 27 | { |
33 | dot = strchr(dot, '.'); | 28 | while (list) { |
34 | if (!dot) | 29 | char *target; |
35 | return 0; /* safe target */ | ||
36 | 30 | ||
37 | /* Is it a path component starting with ".."? */ | 31 | target = list->data + strlen(list->data) + 1; |
38 | if ((dot[1] == '.') | 32 | if (symlink(target, list->data)) { |
39 | && (dot == target || dot[-1] == '/') | 33 | /* shared message */ |
40 | /* Is it exactly ".."? */ | 34 | bb_error_msg_and_die("can't create %slink '%s' to '%s'", |
41 | && (dot[2] == '/' || dot[2] == '\0') | 35 | "sym", |
42 | ) { | 36 | list->data, target |
43 | goto unsafe; | 37 | ); |
44 | } | 38 | } |
45 | /* NB: it can even be trailing ".", should only add 1 */ | 39 | list = list->link; |
46 | dot += 1; | ||
47 | } | 40 | } |
48 | } | 41 | } |
diff --git a/archival/tar.c b/archival/tar.c index fbe5e3be8..d0684b69e 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1279,6 +1279,8 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1279 | while (get_header_tar(tar_handle) == EXIT_SUCCESS) | 1279 | while (get_header_tar(tar_handle) == EXIT_SUCCESS) |
1280 | bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ | 1280 | bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ |
1281 | 1281 | ||
1282 | create_symlinks_from_list(tar_handle->symlink_placeholders); | ||
1283 | |||
1282 | /* Check that every file that should have been extracted was */ | 1284 | /* Check that every file that should have been extracted was */ |
1283 | while (tar_handle->accept) { | 1285 | while (tar_handle->accept) { |
1284 | if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) | 1286 | if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) |
diff --git a/archival/unzip.c b/archival/unzip.c index fb58b62c0..369c6c028 100644 --- a/archival/unzip.c +++ b/archival/unzip.c | |||
@@ -348,7 +348,9 @@ static void unzip_create_leading_dirs(const char *fn) | |||
348 | } | 348 | } |
349 | 349 | ||
350 | #if ENABLE_FEATURE_UNZIP_CDF | 350 | #if ENABLE_FEATURE_UNZIP_CDF |
351 | static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn) | 351 | static void unzip_extract_symlink(llist_t **symlink_placeholders, |
352 | zip_header_t *zip, | ||
353 | const char *dst_fn) | ||
352 | { | 354 | { |
353 | char *target; | 355 | char *target; |
354 | 356 | ||
@@ -373,15 +375,9 @@ static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn) | |||
373 | target[xstate.mem_output_size] = '\0'; | 375 | target[xstate.mem_output_size] = '\0'; |
374 | #endif | 376 | #endif |
375 | } | 377 | } |
376 | if (!unsafe_symlink_target(target)) { | 378 | create_or_remember_symlink(symlink_placeholders, |
377 | //TODO: libbb candidate | 379 | target, |
378 | if (symlink(target, dst_fn)) { | 380 | dst_fn); |
379 | /* shared message */ | ||
380 | bb_perror_msg_and_die("can't create %slink '%s' to '%s'", | ||
381 | "sym", dst_fn, target | ||
382 | ); | ||
383 | } | ||
384 | } | ||
385 | free(target); | 381 | free(target); |
386 | } | 382 | } |
387 | #endif | 383 | #endif |
@@ -493,6 +489,9 @@ int unzip_main(int argc, char **argv) | |||
493 | llist_t *zaccept = NULL; | 489 | llist_t *zaccept = NULL; |
494 | llist_t *zreject = NULL; | 490 | llist_t *zreject = NULL; |
495 | char *base_dir = NULL; | 491 | char *base_dir = NULL; |
492 | #if ENABLE_FEATURE_UNZIP_CDF | ||
493 | llist_t *symlink_placeholders = NULL; | ||
494 | #endif | ||
496 | int i; | 495 | int i; |
497 | char key_buf[80]; /* must match size used by my_fgets80 */ | 496 | char key_buf[80]; /* must match size used by my_fgets80 */ |
498 | 497 | ||
@@ -957,7 +956,7 @@ int unzip_main(int argc, char **argv) | |||
957 | #if ENABLE_FEATURE_UNZIP_CDF | 956 | #if ENABLE_FEATURE_UNZIP_CDF |
958 | if (S_ISLNK(file_mode)) { | 957 | if (S_ISLNK(file_mode)) { |
959 | if (dst_fd != STDOUT_FILENO) /* not -p? */ | 958 | if (dst_fd != STDOUT_FILENO) /* not -p? */ |
960 | unzip_extract_symlink(&zip, dst_fn); | 959 | unzip_extract_symlink(&symlink_placeholders, &zip, dst_fn); |
961 | } else | 960 | } else |
962 | #endif | 961 | #endif |
963 | { | 962 | { |
@@ -993,6 +992,10 @@ int unzip_main(int argc, char **argv) | |||
993 | total_entries++; | 992 | total_entries++; |
994 | } | 993 | } |
995 | 994 | ||
995 | #if ENABLE_FEATURE_UNZIP_CDF | ||
996 | create_symlinks_from_list(symlink_placeholders); | ||
997 | #endif | ||
998 | |||
996 | if ((opts & OPT_l) && quiet <= 1) { | 999 | if ((opts & OPT_l) && quiet <= 1) { |
997 | if (!verbose) { | 1000 | if (!verbose) { |
998 | // " Length Date Time Name\n" | 1001 | // " Length Date Time Name\n" |