diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-24 17:21:44 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-24 17:21:44 +0000 |
commit | d6772501db451b5d7fd4001f5e9c4f1ad20c63d6 (patch) | |
tree | 30b4606de7dbbe62462ad7dc106e429a32e22272 | |
parent | d398ecab9d6e42b1091d214df50bf938030d11a2 (diff) | |
download | busybox-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.c | 2 | ||||
-rw-r--r-- | archival/libunarchive/get_header_tar.c | 65 | ||||
-rw-r--r-- | libbb/xfuncs.c | 1 |
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 |
18 | static char *longname = NULL; | 18 | static char *longname; |
19 | static char *linkname = NULL; | 19 | static char *linkname; |
20 | #else | ||
21 | enum { | ||
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); |