diff options
author | Simon Tatham <anakin@pobox.com> | 2017-05-18 06:57:29 +0100 |
---|---|---|
committer | Simon Tatham <anakin@pobox.com> | 2017-05-18 06:57:29 +0100 |
commit | 69d886c5757e405785ce811d8622f4ff189a9514 (patch) | |
tree | 396774d1e4b25a88e0c23710bf7f5a94a3ee6cdf | |
parent | 7e5c5d42320ab39cd8f7d0d181745786196cb0b8 (diff) | |
download | wix-on-linux-69d886c5757e405785ce811d8622f4ff189a9514.tar.gz wix-on-linux-69d886c5757e405785ce811d8622f4ff189a9514.tar.bz2 wix-on-linux-69d886c5757e405785ce811d8622f4ff189a9514.zip |
Redo the bounds checks in MsiGetFileVersion.
Now any failing bounds check causes the whole function to fail, rather
than returning a made-up value.
-rw-r--r-- | fake-lib.c | 12 | ||||
-rw-r--r-- | fake-lib.h | 1 | ||||
-rw-r--r-- | version.c | 96 |
3 files changed, 58 insertions, 51 deletions
@@ -113,15 +113,3 @@ char *dupcat(const char *str, ...) | |||
113 | 113 | ||
114 | return out; | 114 | return out; |
115 | } | 115 | } |
116 | |||
117 | unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes) | ||
118 | { | ||
119 | unsigned toret = 0; | ||
120 | off += nbytes; | ||
121 | while (nbytes-- > 0) { | ||
122 | toret <<= 8; | ||
123 | if (--off < len) | ||
124 | toret |= buf[off]; | ||
125 | } | ||
126 | return toret; | ||
127 | } | ||
@@ -6,4 +6,3 @@ void system_argv(const char *cmd, ...); | |||
6 | void system_argv_array(char **args); | 6 | void system_argv_array(char **args); |
7 | void c16cpy(char16_t *out, uint32_t *outsize, char *s); | 7 | void c16cpy(char16_t *out, uint32_t *outsize, char *s); |
8 | char *dupcat(const char *str, ...); | 8 | char *dupcat(const char *str, ...); |
9 | unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes); | ||
@@ -38,28 +38,48 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
38 | err(1, "%s: mmap", fname); | 38 | err(1, "%s: mmap", fname); |
39 | unsigned char *map = (unsigned char *)mapv; | 39 | unsigned char *map = (unsigned char *)mapv; |
40 | 40 | ||
41 | if (le(map, fsize, 0, 2) != (('Z'<<8) | 'M')) { | 41 | #define BYTE(offset) ({ \ |
42 | size_t _offset = (offset); \ | ||
43 | if (_offset >= fsize) goto cleanup; /* outside file bounds */ \ | ||
44 | map[_offset]; \ | ||
45 | }) | ||
46 | #define WORD16(offset) ({ \ | ||
47 | size_t _offset = (offset); \ | ||
48 | uint16_t toret = BYTE(_offset+1); \ | ||
49 | toret = (toret << 8) | BYTE(_offset+0); \ | ||
50 | toret; \ | ||
51 | }) | ||
52 | #define WORD32(offset) ({ \ | ||
53 | size_t _offset = (offset); \ | ||
54 | uint16_t toret = BYTE(_offset+3); \ | ||
55 | toret = (toret << 8) | BYTE(_offset+2); \ | ||
56 | toret = (toret << 8) | BYTE(_offset+1); \ | ||
57 | toret = (toret << 8) | BYTE(_offset+0); \ | ||
58 | toret; \ | ||
59 | }) | ||
60 | |||
61 | if (WORD16(0) != (('Z'<<8) | 'M')) { | ||
42 | warnx("MsiGetFileInfo(%s) -> no MZ", fname); | 62 | warnx("MsiGetFileInfo(%s) -> no MZ", fname); |
43 | goto cleanup; | 63 | goto cleanup; |
44 | } | 64 | } |
45 | unsigned pe_pos = le(map, fsize, 0x3c, 4); | 65 | unsigned pe_pos = WORD32(0x3c); |
46 | if (le(map, fsize, pe_pos, 4) != (('E'<<8) | 'P')) { | 66 | if (WORD32(pe_pos) != (('E'<<8) | 'P')) { |
47 | warnx("MsiGetFileInfo(%s) -> no PE", fname); | 67 | warnx("MsiGetFileInfo(%s) -> no PE", fname); |
48 | goto cleanup; | 68 | goto cleanup; |
49 | } | 69 | } |
50 | pe_pos += 4; /* skip to the main header */ | 70 | pe_pos += 4; /* skip to the main header */ |
51 | unsigned nsections = le(map, fsize, pe_pos + 2, 2); | 71 | unsigned nsections = WORD16(pe_pos + 2); |
52 | unsigned opthdr_size = le(map, fsize, pe_pos + 16, 2); | 72 | unsigned opthdr_size = WORD16(pe_pos + 16); |
53 | unsigned opthdr_pos = pe_pos + 20; | 73 | unsigned opthdr_pos = pe_pos + 20; |
54 | /* bool sixtyfourbit = le(map, fsize, opthdr_pos, 2) == 0x020B; */ | 74 | /* bool sixtyfourbit = WORD16(opthdr_pos) == 0x020B; */ |
55 | unsigned secthdr_pos = opthdr_pos + opthdr_size; | 75 | unsigned secthdr_pos = opthdr_pos + opthdr_size; |
56 | while (nsections > 0) { | 76 | while (nsections > 0) { |
57 | if (le(map, fsize, secthdr_pos+0, 1) == '.' && | 77 | if (BYTE(secthdr_pos+0) == '.' && |
58 | le(map, fsize, secthdr_pos+1, 1) == 'r' && | 78 | BYTE(secthdr_pos+1) == 'r' && |
59 | le(map, fsize, secthdr_pos+2, 1) == 's' && | 79 | BYTE(secthdr_pos+2) == 's' && |
60 | le(map, fsize, secthdr_pos+3, 1) == 'r' && | 80 | BYTE(secthdr_pos+3) == 'r' && |
61 | le(map, fsize, secthdr_pos+4, 1) == 'c' && | 81 | BYTE(secthdr_pos+4) == 'c' && |
62 | le(map, fsize, secthdr_pos+5, 1) == 0) | 82 | BYTE(secthdr_pos+5) == 0) |
63 | goto found_resource_section; | 83 | goto found_resource_section; |
64 | secthdr_pos += 0x28; | 84 | secthdr_pos += 0x28; |
65 | nsections--; | 85 | nsections--; |
@@ -68,17 +88,17 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
68 | goto cleanup; | 88 | goto cleanup; |
69 | 89 | ||
70 | found_resource_section:; | 90 | found_resource_section:; |
71 | unsigned rsrc_size = le(map, fsize, secthdr_pos+8, 4); | 91 | unsigned rsrc_size = WORD32(secthdr_pos+8); |
72 | unsigned rsrc_offset = le(map, fsize, secthdr_pos+20, 4); | 92 | unsigned rsrc_offset = WORD32(secthdr_pos+20); |
73 | unsigned rsrc_vaddr = le(map, fsize, secthdr_pos+12, 4); | 93 | unsigned rsrc_vaddr = WORD32(secthdr_pos+12); |
74 | 94 | ||
75 | unsigned res_dir_offset = rsrc_offset; | 95 | unsigned res_dir_offset = rsrc_offset; |
76 | unsigned nnamed, nid; | 96 | unsigned nnamed, nid; |
77 | nnamed = le(map, fsize, res_dir_offset+12, 2); | 97 | nnamed = WORD16(res_dir_offset+12); |
78 | nid = le(map, fsize, res_dir_offset+14, 2); | 98 | nid = WORD16(res_dir_offset+14); |
79 | for (unsigned i = nnamed; i < nnamed+nid; i++) { | 99 | for (unsigned i = nnamed; i < nnamed+nid; i++) { |
80 | unsigned id = le(map, fsize, res_dir_offset + 16 + 8*i, 4); | 100 | unsigned id = WORD32(res_dir_offset + 16 + 8*i); |
81 | unsigned entry = le(map, fsize, res_dir_offset + 16 + 8*i + 4, 4); | 101 | unsigned entry = WORD32(res_dir_offset + 16 + 8*i + 4); |
82 | if (id == 16 && (entry & 0x80000000)) { | 102 | if (id == 16 && (entry & 0x80000000)) { |
83 | res_dir_offset = rsrc_offset + (entry & 0x7FFFFFFF); | 103 | res_dir_offset = rsrc_offset + (entry & 0x7FFFFFFF); |
84 | goto found_versioninfo_toplevel; | 104 | goto found_versioninfo_toplevel; |
@@ -88,10 +108,10 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
88 | goto cleanup; | 108 | goto cleanup; |
89 | 109 | ||
90 | found_versioninfo_toplevel: | 110 | found_versioninfo_toplevel: |
91 | nnamed = le(map, fsize, res_dir_offset+12, 2); | 111 | nnamed = WORD16(res_dir_offset+12); |
92 | nid = le(map, fsize, res_dir_offset+14, 2); | 112 | nid = WORD16(res_dir_offset+14); |
93 | for (unsigned i = 0; i < nnamed+nid; i++) { | 113 | for (unsigned i = 0; i < nnamed+nid; i++) { |
94 | unsigned entry = le(map, fsize, res_dir_offset + 16 + 8*i + 4, 4); | 114 | unsigned entry = WORD32(res_dir_offset + 16 + 8*i + 4); |
95 | if (entry & 0x80000000) { | 115 | if (entry & 0x80000000) { |
96 | res_dir_offset = rsrc_offset + (entry & 0x7FFFFFFF); | 116 | res_dir_offset = rsrc_offset + (entry & 0x7FFFFFFF); |
97 | goto found_versioninfo_2ndlevel; | 117 | goto found_versioninfo_2ndlevel; |
@@ -101,10 +121,10 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
101 | goto cleanup; | 121 | goto cleanup; |
102 | 122 | ||
103 | found_versioninfo_2ndlevel: | 123 | found_versioninfo_2ndlevel: |
104 | nnamed = le(map, fsize, res_dir_offset+12, 2); | 124 | nnamed = WORD16(res_dir_offset+12); |
105 | nid = le(map, fsize, res_dir_offset+14, 2); | 125 | nid = WORD16(res_dir_offset+14); |
106 | for (unsigned i = 0; i < nnamed+nid; i++) { | 126 | for (unsigned i = 0; i < nnamed+nid; i++) { |
107 | unsigned entry = le(map, fsize, res_dir_offset + 16 + 8*i + 4, 4); | 127 | unsigned entry = WORD32(res_dir_offset + 16 + 8*i + 4); |
108 | if (!(entry & 0x80000000)) { | 128 | if (!(entry & 0x80000000)) { |
109 | res_dir_offset = rsrc_offset + (entry & 0x7FFFFFFF); | 129 | res_dir_offset = rsrc_offset + (entry & 0x7FFFFFFF); |
110 | goto found_versioninfo_3rdlevel; | 130 | goto found_versioninfo_3rdlevel; |
@@ -114,33 +134,33 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
114 | goto cleanup; | 134 | goto cleanup; |
115 | 135 | ||
116 | found_versioninfo_3rdlevel:; | 136 | found_versioninfo_3rdlevel:; |
117 | unsigned versioninfo_offset = le(map, fsize, res_dir_offset, 4); | 137 | unsigned versioninfo_offset = WORD32(res_dir_offset); |
118 | unsigned versioninfo_size = le(map, fsize, res_dir_offset+4, 4); | 138 | unsigned versioninfo_size = WORD32(res_dir_offset+4); |
119 | versioninfo_offset = rsrc_offset + versioninfo_offset - rsrc_vaddr; | 139 | versioninfo_offset = rsrc_offset + versioninfo_offset - rsrc_vaddr; |
120 | 140 | ||
121 | unsigned name_offset = versioninfo_offset + 6; | 141 | unsigned name_offset = versioninfo_offset + 6; |
122 | const char *next_name_chr = "VS_VERSION_INFO"; | 142 | const char *next_name_chr = "VS_VERSION_INFO"; |
123 | do { | 143 | do { |
124 | if (le(map, fsize, name_offset, 2) != *next_name_chr) | 144 | if (WORD16(name_offset) != *next_name_chr) |
125 | goto cleanup; /* identifying string didn't match */ | 145 | goto cleanup; /* identifying string didn't match */ |
126 | name_offset += 2; | 146 | name_offset += 2; |
127 | } while (*next_name_chr++); | 147 | } while (*next_name_chr++); |
128 | unsigned fixed_offset = (name_offset + 3) & ~3; | 148 | unsigned fixed_offset = (name_offset + 3) & ~3; |
129 | if (le(map, fsize, fixed_offset, 4) != 0xFEEF04BDU) { | 149 | if (WORD32(fixed_offset) != 0xFEEF04BDU) { |
130 | warnx("MsiGetFileInfo(%s) -> no VS_FIXEDFILEINFO magic number", fname); | 150 | warnx("MsiGetFileInfo(%s) -> no VS_FIXEDFILEINFO magic number", fname); |
131 | goto cleanup; | 151 | goto cleanup; |
132 | } | 152 | } |
133 | int four_part_version[4]; | 153 | int four_part_version[4]; |
134 | four_part_version[0] = le(map, fsize, fixed_offset + 10, 2); | 154 | four_part_version[0] = WORD16(fixed_offset + 10); |
135 | four_part_version[1] = le(map, fsize, fixed_offset + 8, 2); | 155 | four_part_version[1] = WORD16(fixed_offset + 8); |
136 | four_part_version[2] = le(map, fsize, fixed_offset + 14, 2); | 156 | four_part_version[2] = WORD16(fixed_offset + 14); |
137 | four_part_version[3] = le(map, fsize, fixed_offset + 12, 2); | 157 | four_part_version[3] = WORD16(fixed_offset + 12); |
138 | unsigned child_offset = fixed_offset + | 158 | unsigned child_offset = fixed_offset + |
139 | le(map, fsize, versioninfo_offset+2, 2); | 159 | WORD16(versioninfo_offset+2); |
140 | unsigned lcid; | 160 | unsigned lcid; |
141 | while (child_offset < versioninfo_offset + versioninfo_size) { | 161 | while (child_offset < versioninfo_offset + versioninfo_size) { |
142 | unsigned this_child_offset = child_offset; | 162 | unsigned this_child_offset = child_offset; |
143 | child_offset += le(map, fsize, child_offset, 2); | 163 | child_offset += WORD16(child_offset); |
144 | child_offset = (child_offset + 3) &~ 3; | 164 | child_offset = (child_offset + 3) &~ 3; |
145 | if (child_offset <= this_child_offset) { | 165 | if (child_offset <= this_child_offset) { |
146 | warnx("MsiGetFileInfo(%s) -> bad length field", fname); | 166 | warnx("MsiGetFileInfo(%s) -> bad length field", fname); |
@@ -149,7 +169,7 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
149 | const char *next_name_chr = "VarFileInfo"; | 169 | const char *next_name_chr = "VarFileInfo"; |
150 | name_offset = this_child_offset + 6; | 170 | name_offset = this_child_offset + 6; |
151 | do { | 171 | do { |
152 | if (le(map, fsize, name_offset, 2) != *next_name_chr) | 172 | if (WORD16(name_offset) != *next_name_chr) |
153 | goto this_is_not_a_varfileinfo; | 173 | goto this_is_not_a_varfileinfo; |
154 | name_offset += 2; | 174 | name_offset += 2; |
155 | } while (*next_name_chr++); | 175 | } while (*next_name_chr++); |
@@ -158,14 +178,14 @@ uint32_t MsiGetFileVersionW(const char16_t *filename, | |||
158 | next_name_chr = "Translation"; | 178 | next_name_chr = "Translation"; |
159 | name_offset = subchild_offset + 6; | 179 | name_offset = subchild_offset + 6; |
160 | do { | 180 | do { |
161 | if (le(map, fsize, name_offset, 2) != *next_name_chr) { | 181 | if (WORD16(name_offset) != *next_name_chr) { |
162 | warnx("MsiGetFileInfo(%s) -> child not called 'Translation'", fname); | 182 | warnx("MsiGetFileInfo(%s) -> child not called 'Translation'", fname); |
163 | goto cleanup; | 183 | goto cleanup; |
164 | } | 184 | } |
165 | name_offset += 2; | 185 | name_offset += 2; |
166 | } while (*next_name_chr++); | 186 | } while (*next_name_chr++); |
167 | subchild_offset = (name_offset + 3) & ~3; | 187 | subchild_offset = (name_offset + 3) & ~3; |
168 | lcid = le(map, fsize, subchild_offset, 2); | 188 | lcid = WORD16(subchild_offset); |
169 | goto success; | 189 | goto success; |
170 | this_is_not_a_varfileinfo: | 190 | this_is_not_a_varfileinfo: |
171 | continue; | 191 | continue; |