aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archival/libunarchive/get_header_tar.c53
-rw-r--r--archival/tar.c2
2 files changed, 35 insertions, 20 deletions
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c
index b785d631d..583f6f811 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -40,11 +40,12 @@ static unsigned long long getOctal(char *str, int len)
40 bb_error_msg_and_die("corrupted octal value in tar header"); 40 bb_error_msg_and_die("corrupted octal value in tar header");
41 return v; 41 return v;
42} 42}
43#define GET_OCTAL(a) getOctal((a), sizeof(a))
43 44
44void BUG_tar_header_size(void); 45void BUG_tar_header_size(void);
45char get_header_tar(archive_handle_t *archive_handle) 46char get_header_tar(archive_handle_t *archive_handle)
46{ 47{
47 static int end = 0; 48 static int end;
48 49
49 file_header_t *file_header = archive_handle->file_header; 50 file_header_t *file_header = archive_handle->file_header;
50 struct { 51 struct {
@@ -69,18 +70,17 @@ char get_header_tar(archive_handle_t *archive_handle)
69 } tar; 70 } tar;
70 char *cp; 71 char *cp;
71 int sum, i; 72 int sum, i;
72#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
73 int parse_names; 73 int parse_names;
74#else
75 enum { parse_names = 1 };
76#endif
77 74
78 if (sizeof(tar) != 512) 75 if (sizeof(tar) != 512)
79 BUG_tar_header_size(); 76 BUG_tar_header_size();
77 again:
80 78
81 /* Align header */ 79 /* Align header */
82 data_align(archive_handle, 512); 80 data_align(archive_handle, 512);
83 81
82 again_after_align:
83
84 xread(archive_handle->src_fd, &tar, 512); 84 xread(archive_handle->src_fd, &tar, 512);
85 archive_handle->offset += 512; 85 archive_handle->offset += 512;
86 86
@@ -121,13 +121,12 @@ char get_header_tar(archive_handle_t *archive_handle)
121 bb_error_msg_and_die("invalid tar header checksum"); 121 bb_error_msg_and_die("invalid tar header checksum");
122 } 122 }
123 123
124#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 124 /* 0 is reserved for high perf file, treat as normal file */
125 parse_names = (tar.typeflag != 'L' && tar.typeflag != 'K'); 125 if (!tar.typeflag) tar.typeflag = '0';
126#endif 126 parse_names = (tar.typeflag >= '0' && tar.typeflag <= '7');
127 127
128 /* getOctal trashes subsequent field, therefore we call it 128 /* getOctal trashes subsequent field, therefore we call it
129 * on fields in reverse order */ 129 * on fields in reverse order */
130#define GET_OCTAL(a) getOctal((a), sizeof(a))
131 if (tar.devmajor[0]) { 130 if (tar.devmajor[0]) {
132 unsigned minor = GET_OCTAL(tar.devminor); 131 unsigned minor = GET_OCTAL(tar.devminor);
133 unsigned major = GET_OCTAL(tar.devmajor); 132 unsigned major = GET_OCTAL(tar.devmajor);
@@ -147,8 +146,8 @@ char get_header_tar(archive_handle_t *archive_handle)
147 file_header->uid = GET_OCTAL(tar.uid); 146 file_header->uid = GET_OCTAL(tar.uid);
148 /* Set bits 0-11 of the files mode */ 147 /* Set bits 0-11 of the files mode */
149 file_header->mode = 07777 & GET_OCTAL(tar.mode); 148 file_header->mode = 07777 & GET_OCTAL(tar.mode);
150#undef GET_OCTAL
151 149
150 file_header->name = NULL;
152 if (!longname && parse_names) { 151 if (!longname && parse_names) {
153 /* we trash mode[0] here, it's ok */ 152 /* we trash mode[0] here, it's ok */
154 tar.name[sizeof(tar.name)] = '\0'; 153 tar.name[sizeof(tar.name)] = '\0';
@@ -158,6 +157,7 @@ char get_header_tar(archive_handle_t *archive_handle)
158 file_header->name = concat_path_file(tar.prefix, tar.name); 157 file_header->name = concat_path_file(tar.prefix, tar.name);
159 } else 158 } else
160 file_header->name = xstrdup(tar.name); 159 file_header->name = xstrdup(tar.name);
160 /* FIXME: add check for /../ attacks */
161 } 161 }
162 162
163 /* Set bits 12-15 of the files mode */ 163 /* Set bits 12-15 of the files mode */
@@ -168,8 +168,7 @@ char get_header_tar(archive_handle_t *archive_handle)
168 file_header->mode |= S_IFREG; 168 file_header->mode |= S_IFREG;
169 break; 169 break;
170 case '7': 170 case '7':
171 /* Reserved for high performance files, treat as normal file */ 171 /* case 0: */
172 case 0:
173 case '0': 172 case '0':
174#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY 173#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
175 if (last_char_is(file_header->name, '/')) { 174 if (last_char_is(file_header->name, '/')) {
@@ -195,18 +194,24 @@ char get_header_tar(archive_handle_t *archive_handle)
195 break; 194 break;
196#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 195#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
197 case 'L': 196 case 'L':
198 /* paranoia: tar with several consecutive longnames */ 197 /* free: paranoia: tar with several consecutive longnames */
199 free(longname); 198 free(longname);
199 /* For paranoia reasons we allocate extra NUL char */
200 longname = xzalloc(file_header->size + 1); 200 longname = xzalloc(file_header->size + 1);
201 /* We read ASCIZ string, including NUL */
201 xread(archive_handle->src_fd, longname, file_header->size); 202 xread(archive_handle->src_fd, longname, file_header->size);
202 archive_handle->offset += file_header->size; 203 archive_handle->offset += file_header->size;
203 return get_header_tar(archive_handle); 204 /* return get_header_tar(archive_handle); */
205 /* gcc 4.1.1 didn't optimize it into jump */
206 /* so we will do it ourself, this also saves stack */
207 goto again;
204 case 'K': 208 case 'K':
205 free(linkname); 209 free(linkname);
206 linkname = xzalloc(file_header->size + 1); 210 linkname = xzalloc(file_header->size + 1);
207 xread(archive_handle->src_fd, linkname, file_header->size); 211 xread(archive_handle->src_fd, linkname, file_header->size);
208 archive_handle->offset += file_header->size; 212 archive_handle->offset += file_header->size;
209 return get_header_tar(archive_handle); 213 /* return get_header_tar(archive_handle); */
214 goto again;
210 case 'D': /* GNU dump dir */ 215 case 'D': /* GNU dump dir */
211 case 'M': /* Continuation of multi volume archive */ 216 case 'M': /* Continuation of multi volume archive */
212 case 'N': /* Old GNU for names > 100 characters */ 217 case 'N': /* Old GNU for names > 100 characters */
@@ -214,11 +219,19 @@ char get_header_tar(archive_handle_t *archive_handle)
214 case 'V': /* Volume header */ 219 case 'V': /* Volume header */
215#endif 220#endif
216 case 'g': /* pax global header */ 221 case 'g': /* pax global header */
217 case 'x': /* pax extended header */ 222 case 'x': { /* pax extended header */
218 bb_error_msg("ignoring extension type %c", tar.typeflag); 223 off_t sz;
219 break; 224 bb_error_msg("warning: skipping header '%c'", tar.typeflag);
225 sz = (file_header->size + 511) & ~(off_t)511;
226 archive_handle->offset += sz;
227 sz >>= 9; /* sz /= 512 but w/o contortions for signed div */
228 while (sz--)
229 xread(archive_handle->src_fd, &tar, 512);
230 /* return get_header_tar(archive_handle); */
231 goto again_after_align;
232 }
220 default: 233 default:
221 bb_error_msg("unknown typeflag: 0x%x", tar.typeflag); 234 bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
222 } 235 }
223 236
224#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 237#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
@@ -246,10 +259,12 @@ char get_header_tar(archive_handle_t *archive_handle)
246 llist_add_to(&(archive_handle->passed), file_header->name); 259 llist_add_to(&(archive_handle->passed), file_header->name);
247 } else { 260 } else {
248 data_skip(archive_handle); 261 data_skip(archive_handle);
262 free(file_header->name);
249 } 263 }
250 archive_handle->offset += file_header->size; 264 archive_handle->offset += file_header->size;
251 265
252 free(file_header->link_name); 266 free(file_header->link_name);
267 /* Do not free(file_header->name)! */
253 268
254 return EXIT_SUCCESS; 269 return EXIT_SUCCESS;
255} 270}
diff --git a/archival/tar.c b/archival/tar.c
index bf6786f0a..48a1c34cd 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -768,7 +768,7 @@ int tar_main(int argc, char **argv)
768 if (verboseFlag) tar_handle->action_header = header_verbose_list; 768 if (verboseFlag) tar_handle->action_header = header_verbose_list;
769 if (verboseFlag == 1) tar_handle->action_header = header_list; 769 if (verboseFlag == 1) tar_handle->action_header = header_list;
770 770
771 if ((opt & OPT_EXTRACT) && tar_handle->action_data != data_extract_to_stdout) 771 if (opt & OPT_EXTRACT)
772 tar_handle->action_data = data_extract_all; 772 tar_handle->action_data = data_extract_all;
773 773
774 if (opt & OPT_2STDOUT) 774 if (opt & OPT_2STDOUT)