aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Tatham <anakin@pobox.com>2017-05-18 06:57:29 +0100
committerSimon Tatham <anakin@pobox.com>2017-05-18 06:57:29 +0100
commit69d886c5757e405785ce811d8622f4ff189a9514 (patch)
tree396774d1e4b25a88e0c23710bf7f5a94a3ee6cdf
parent7e5c5d42320ab39cd8f7d0d181745786196cb0b8 (diff)
downloadwix-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.c12
-rw-r--r--fake-lib.h1
-rw-r--r--version.c96
3 files changed, 58 insertions, 51 deletions
diff --git a/fake-lib.c b/fake-lib.c
index 9862020..36c6198 100644
--- a/fake-lib.c
+++ b/fake-lib.c
@@ -113,15 +113,3 @@ char *dupcat(const char *str, ...)
113 113
114 return out; 114 return out;
115} 115}
116
117unsigned 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}
diff --git a/fake-lib.h b/fake-lib.h
index 8f8774c..de0960f 100644
--- a/fake-lib.h
+++ b/fake-lib.h
@@ -6,4 +6,3 @@ void system_argv(const char *cmd, ...);
6void system_argv_array(char **args); 6void system_argv_array(char **args);
7void c16cpy(char16_t *out, uint32_t *outsize, char *s); 7void c16cpy(char16_t *out, uint32_t *outsize, char *s);
8char *dupcat(const char *str, ...); 8char *dupcat(const char *str, ...);
9unsigned le(const unsigned char *buf, size_t len, size_t off, size_t nbytes);
diff --git a/version.c b/version.c
index dd62fc4..c8d4991 100644
--- a/version.c
+++ b/version.c
@@ -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;