diff options
author | Peter Korsgaard <jacmet@sunsite.dk> | 2013-09-10 11:52:35 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2013-09-10 16:22:12 +0200 |
commit | 2a053a2430e8de2f5de3da7d4d25343f61161f09 (patch) | |
tree | ecf4d1bc83b7f7ec3672758d81f3eec5a346246f | |
parent | dc57294485068e644714804ad1b1a3a10c4fceec (diff) | |
download | busybox-w32-2a053a2430e8de2f5de3da7d4d25343f61161f09.tar.gz busybox-w32-2a053a2430e8de2f5de3da7d4d25343f61161f09.tar.bz2 busybox-w32-2a053a2430e8de2f5de3da7d4d25343f61161f09.zip |
ar: read_num(): fix reading fields using the entire width
ar fields are fixed length text strings (padded with spaces). Ensure
bb_strtou doesn't read past the field in case the full width is used.
The fields are only read once, so the simplest/smallest solution to me
seems to be to just pass the length to read_num() and then zero terminate
the string before passing it to bb_strtou. This does mean that the fields
MUST be read in reverse order, so some minor reshuffling was needed.
Bloat-o-meter:
function old new delta
get_header_ar 394 414 +20
read_num 29 36 +7
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 27/0) Total: 27 bytes
Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/libarchive/get_header_ar.c | 32 |
1 files changed, 20 insertions, 12 deletions
diff --git a/archival/libarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c index 23c412496..f655585fe 100644 --- a/archival/libarchive/get_header_ar.c +++ b/archival/libarchive/get_header_ar.c | |||
@@ -8,11 +8,19 @@ | |||
8 | #include "bb_archive.h" | 8 | #include "bb_archive.h" |
9 | #include "ar.h" | 9 | #include "ar.h" |
10 | 10 | ||
11 | static unsigned read_num(const char *str, int base) | 11 | /* WARNING: Clobbers str[len], so fields must be read in reverse order! */ |
12 | static unsigned read_num(char *str, int base, int len) | ||
12 | { | 13 | { |
14 | int err; | ||
15 | |||
16 | /* ar fields are fixed length text strings (padded with spaces). | ||
17 | * Ensure bb_strtou doesn't read past the field in case the full | ||
18 | * width is used. */ | ||
19 | str[len] = 0; | ||
20 | |||
13 | /* This code works because | 21 | /* This code works because |
14 | * on misformatted numbers bb_strtou returns all-ones */ | 22 | * on misformatted numbers bb_strtou returns all-ones */ |
15 | int err = bb_strtou(str, NULL, base); | 23 | err = bb_strtou(str, NULL, base); |
16 | if (err == -1) | 24 | if (err == -1) |
17 | bb_error_msg_and_die("invalid ar header"); | 25 | bb_error_msg_and_die("invalid ar header"); |
18 | return err; | 26 | return err; |
@@ -51,11 +59,8 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) | |||
51 | if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') | 59 | if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') |
52 | bb_error_msg_and_die("invalid ar header"); | 60 | bb_error_msg_and_die("invalid ar header"); |
53 | 61 | ||
54 | /* FIXME: more thorough routine would be in order here | 62 | typed->size = size = read_num(ar.formatted.size, 10, |
55 | * (we have something like that in tar) | 63 | sizeof(ar.formatted.size)); |
56 | * but for now we are lax. */ | ||
57 | ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */ | ||
58 | typed->size = size = read_num(ar.formatted.size, 10); | ||
59 | 64 | ||
60 | /* special filenames have '/' as the first character */ | 65 | /* special filenames have '/' as the first character */ |
61 | if (ar.formatted.name[0] == '/') { | 66 | if (ar.formatted.name[0] == '/') { |
@@ -86,11 +91,13 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) | |||
86 | /* Only size is always present, the rest may be missing in | 91 | /* Only size is always present, the rest may be missing in |
87 | * long filename pseudo file. Thus we decode the rest | 92 | * long filename pseudo file. Thus we decode the rest |
88 | * after dealing with long filename pseudo file. | 93 | * after dealing with long filename pseudo file. |
94 | * Note that the fields MUST be read in reverse order as | ||
95 | * read_num() clobbers the next byte after the field! | ||
89 | */ | 96 | */ |
90 | typed->mode = read_num(ar.formatted.mode, 8); | 97 | typed->mode = read_num(ar.formatted.mode, 8, sizeof(ar.formatted.mode)); |
91 | typed->mtime = read_num(ar.formatted.date, 10); | 98 | typed->gid = read_num(ar.formatted.gid, 10, sizeof(ar.formatted.gid)); |
92 | typed->uid = read_num(ar.formatted.uid, 10); | 99 | typed->uid = read_num(ar.formatted.uid, 10, sizeof(ar.formatted.uid)); |
93 | typed->gid = read_num(ar.formatted.gid, 10); | 100 | typed->mtime = read_num(ar.formatted.date, 10, sizeof(ar.formatted.date)); |
94 | 101 | ||
95 | #if ENABLE_FEATURE_AR_LONG_FILENAMES | 102 | #if ENABLE_FEATURE_AR_LONG_FILENAMES |
96 | if (ar.formatted.name[0] == '/') { | 103 | if (ar.formatted.name[0] == '/') { |
@@ -98,7 +105,8 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) | |||
98 | 105 | ||
99 | /* The number after the '/' indicates the offset in the ar data section | 106 | /* The number after the '/' indicates the offset in the ar data section |
100 | * (saved in ar_long_names) that conatains the real filename */ | 107 | * (saved in ar_long_names) that conatains the real filename */ |
101 | long_offset = read_num(&ar.formatted.name[1], 10); | 108 | long_offset = read_num(&ar.formatted.name[1], 10, |
109 | sizeof(ar.formatted.name) - 1); | ||
102 | if (long_offset >= ar_long_name_size) { | 110 | if (long_offset >= ar_long_name_size) { |
103 | bb_error_msg_and_die("can't resolve long filename"); | 111 | bb_error_msg_and_die("can't resolve long filename"); |
104 | } | 112 | } |