aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-11-24 17:21:44 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-11-24 17:21:44 +0000
commitd6772501db451b5d7fd4001f5e9c4f1ad20c63d6 (patch)
tree30b4606de7dbbe62462ad7dc106e429a32e22272
parentd398ecab9d6e42b1091d214df50bf938030d11a2 (diff)
downloadbusybox-w32-d6772501db451b5d7fd4001f5e9c4f1ad20c63d6.tar.gz
busybox-w32-d6772501db451b5d7fd4001f5e9c4f1ad20c63d6.tar.bz2
busybox-w32-d6772501db451b5d7fd4001f5e9c4f1ad20c63d6.zip
tar: fix and sanitize handling of long filenames/linknames
(GNU extensions 'K' and 'L'). We correctly handle them when untarring now, but unfortunately we still don't use them when tarring! That stupid 100 char limit is still there! The biggest problem is that we don't support 'pax' tar format. Linux kernel tarballs are in this format... shame
-rw-r--r--archival/libunarchive/get_header_ar.c2
-rw-r--r--archival/libunarchive/get_header_tar.c65
-rw-r--r--libbb/xfuncs.c1
3 files changed, 47 insertions, 21 deletions
diff --git a/archival/libunarchive/get_header_ar.c b/archival/libunarchive/get_header_ar.c
index b91c6f97d..0d040e30b 100644
--- a/archival/libunarchive/get_header_ar.c
+++ b/archival/libunarchive/get_header_ar.c
@@ -88,7 +88,7 @@ char get_header_ar(archive_handle_t *archive_handle)
88#endif 88#endif
89 } else { 89 } else {
90 /* short filenames */ 90 /* short filenames */
91 typed->name = xstrndup(ar.formatted.name, 16); 91 typed->name = xstrndup(ar.formatted.name, 16);
92 } 92 }
93 93
94 typed->name[strcspn(typed->name, " /")] = '\0'; 94 typed->name[strcspn(typed->name, " /")] = '\0';
diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c
index 68f7b2b9b..0fb14e8e4 100644
--- a/archival/libunarchive/get_header_tar.c
+++ b/archival/libunarchive/get_header_tar.c
@@ -14,9 +14,14 @@
14#include "libbb.h" 14#include "libbb.h"
15#include "unarchive.h" 15#include "unarchive.h"
16 16
17#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS 17#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
18static char *longname = NULL; 18static char *longname;
19static char *linkname = NULL; 19static char *linkname;
20#else
21enum {
22 longname = 0,
23 linkname = 0,
24};
20#endif 25#endif
21 26
22/* NB: _DESTROYS_ str[len] character! */ 27/* NB: _DESTROYS_ str[len] character! */
@@ -64,6 +69,11 @@ char get_header_tar(archive_handle_t *archive_handle)
64 } tar; 69 } tar;
65 char *cp; 70 char *cp;
66 int sum, i; 71 int sum, i;
72#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
73 int parse_names;
74#else
75 enum { parse_names = 0 };
76#endif
67 77
68 if (sizeof(tar) != 512) 78 if (sizeof(tar) != 512)
69 BUG_tar_header_size(); 79 BUG_tar_header_size();
@@ -93,7 +103,7 @@ char get_header_tar(archive_handle_t *archive_handle)
93 * 0's are for the old tar format 103 * 0's are for the old tar format
94 */ 104 */
95 if (strncmp(tar.magic, "ustar", 5) != 0) { 105 if (strncmp(tar.magic, "ustar", 5) != 0) {
96#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY 106#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
97 if (memcmp(tar.magic, "\0\0\0\0", 5) != 0) 107 if (memcmp(tar.magic, "\0\0\0\0", 5) != 0)
98#endif 108#endif
99 bb_error_msg_and_die("invalid tar magic"); 109 bb_error_msg_and_die("invalid tar magic");
@@ -111,6 +121,10 @@ char get_header_tar(archive_handle_t *archive_handle)
111 bb_error_msg_and_die("invalid tar header checksum"); 121 bb_error_msg_and_die("invalid tar header checksum");
112 } 122 }
113 123
124#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
125 parse_names = (tar.typeflag != 'L' && tar.typeflag != 'K');
126#endif
127
114 /* getOctal trashes subsequent field, therefore we call it 128 /* getOctal trashes subsequent field, therefore we call it
115 * on fields in reverse order */ 129 * on fields in reverse order */
116#define GET_OCTAL(a) getOctal((a), sizeof(a)) 130#define GET_OCTAL(a) getOctal((a), sizeof(a))
@@ -119,27 +133,24 @@ char get_header_tar(archive_handle_t *archive_handle)
119 unsigned major = GET_OCTAL(tar.devmajor); 133 unsigned major = GET_OCTAL(tar.devmajor);
120 file_header->device = makedev(major, minor); 134 file_header->device = makedev(major, minor);
121 } 135 }
136 file_header->link_name = NULL;
137 if (!linkname && parse_names && tar.linkname[0]) {
138 /* we trash magic[0] here, it's ok */
139 tar.linkname[sizeof(tar.linkname)] = '\0';
140 file_header->link_name = xstrdup(tar.linkname);
141 /* FIXME: what if we have non-link object with link_name? */
142 /* Will link_name be free()ed? */
143 }
122 file_header->mtime = GET_OCTAL(tar.mtime); 144 file_header->mtime = GET_OCTAL(tar.mtime);
123 file_header->size = GET_OCTAL(tar.size); 145 file_header->size = GET_OCTAL(tar.size);
124 file_header->gid = GET_OCTAL(tar.gid); 146 file_header->gid = GET_OCTAL(tar.gid);
125 file_header->uid = GET_OCTAL(tar.uid); 147 file_header->uid = GET_OCTAL(tar.uid);
126 file_header->link_name = !tar.linkname[0] ? NULL :
127 xstrndup(tar.linkname, sizeof(tar.linkname));
128 /* Set bits 0-11 of the files mode */ 148 /* Set bits 0-11 of the files mode */
129 file_header->mode = 07777 & GET_OCTAL(tar.mode); 149 file_header->mode = 07777 & GET_OCTAL(tar.mode);
130#undef GET_OCTAL 150#undef GET_OCTAL
131 151
132#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS 152 if (!longname && parse_names) {
133 if (longname) { 153 /* we trash mode[0] here, it's ok */
134 file_header->name = longname;
135 longname = NULL;
136 }
137 else if (linkname) {
138 file_header->name = linkname;
139 linkname = NULL;
140 } else
141#endif
142 { /* we trash mode[0] here, it's ok */
143 tar.name[sizeof(tar.name)] = '\0'; 154 tar.name[sizeof(tar.name)] = '\0';
144 if (tar.prefix[0]) 155 if (tar.prefix[0])
145 file_header->name = concat_path_file(tar.prefix, tar.name); 156 file_header->name = concat_path_file(tar.prefix, tar.name);
@@ -148,6 +159,7 @@ char get_header_tar(archive_handle_t *archive_handle)
148 } 159 }
149 160
150 /* Set bits 12-15 of the files mode */ 161 /* Set bits 12-15 of the files mode */
162 /* (typeflag was not trashed because chksum does not use getOctal) */
151 switch (tar.typeflag) { 163 switch (tar.typeflag) {
152 /* busybox identifies hard links as being regular files with 0 size and a link name */ 164 /* busybox identifies hard links as being regular files with 0 size and a link name */
153 case '1': 165 case '1':
@@ -157,7 +169,7 @@ char get_header_tar(archive_handle_t *archive_handle)
157 /* Reserved for high performance files, treat as normal file */ 169 /* Reserved for high performance files, treat as normal file */
158 case 0: 170 case 0:
159 case '0': 171 case '0':
160#ifdef CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY 172#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
161 if (last_char_is(file_header->name, '/')) { 173 if (last_char_is(file_header->name, '/')) {
162 file_header->mode |= S_IFDIR; 174 file_header->mode |= S_IFDIR;
163 } else 175 } else
@@ -179,17 +191,19 @@ char get_header_tar(archive_handle_t *archive_handle)
179 case '6': 191 case '6':
180 file_header->mode |= S_IFIFO; 192 file_header->mode |= S_IFIFO;
181 break; 193 break;
182#ifdef CONFIG_FEATURE_TAR_GNU_EXTENSIONS 194#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
183 case 'L': 195 case 'L':
196 /* paranoia: tar with several consecutive longnames */
197 free(longname);
184 longname = xzalloc(file_header->size + 1); 198 longname = xzalloc(file_header->size + 1);
185 xread(archive_handle->src_fd, longname, file_header->size); 199 xread(archive_handle->src_fd, longname, file_header->size);
186 archive_handle->offset += file_header->size; 200 archive_handle->offset += file_header->size;
187 return get_header_tar(archive_handle); 201 return get_header_tar(archive_handle);
188 case 'K': 202 case 'K':
203 free(linkname);
189 linkname = xzalloc(file_header->size + 1); 204 linkname = xzalloc(file_header->size + 1);
190 xread(archive_handle->src_fd, linkname, file_header->size); 205 xread(archive_handle->src_fd, linkname, file_header->size);
191 archive_handle->offset += file_header->size; 206 archive_handle->offset += file_header->size;
192 file_header->name = linkname;
193 return get_header_tar(archive_handle); 207 return get_header_tar(archive_handle);
194 case 'D': /* GNU dump dir */ 208 case 'D': /* GNU dump dir */
195 case 'M': /* Continuation of multi volume archive */ 209 case 'M': /* Continuation of multi volume archive */
@@ -205,6 +219,17 @@ char get_header_tar(archive_handle_t *archive_handle)
205 bb_error_msg("unknown typeflag: 0x%x", tar.typeflag); 219 bb_error_msg("unknown typeflag: 0x%x", tar.typeflag);
206 } 220 }
207 221
222#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
223 if (longname) {
224 file_header->name = longname;
225 longname = NULL;
226 }
227 if (linkname) {
228 file_header->link_name = linkname;
229 linkname = NULL;
230 }
231#endif
232
208 /* Strip trailing '/' in directories */ 233 /* Strip trailing '/' in directories */
209 /* Must be done after mode is set as '/' is used to check if its a directory */ 234 /* Must be done after mode is set as '/' is used to check if its a directory */
210 cp = last_char_is(file_header->name, '/'); 235 cp = last_char_is(file_header->name, '/');
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index e6f4e3a48..1dbd7521b 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -74,6 +74,7 @@ char * xstrndup(const char *s, int n)
74 if (ENABLE_DEBUG && s == NULL) 74 if (ENABLE_DEBUG && s == NULL)
75 bb_error_msg_and_die("xstrndup bug"); 75 bb_error_msg_and_die("xstrndup bug");
76 76
77 /* TODO: think about xstrndup("abc", 10000)!!! */
77 t = xmalloc(++n); 78 t = xmalloc(++n);
78 79
79 return safe_strncpy(t,s,n); 80 return safe_strncpy(t,s,n);