Print this page
5507 libelf may overflow data buffer when translating data to memory representation
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/libelf/common/clscook.c
+++ new/usr/src/cmd/sgs/libelf/common/clscook.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /* Copyright (c) 1988 AT&T */
28 28 /* All Rights Reserved */
29 29
30 -#pragma ident "%Z%%M% %I% %E% SMI"
31 -
32 30 /*
33 31 * This stuff used to live in cook.c, but was moved out to
34 32 * facilitate dual (Elf32 and Elf64) compilation. See block
35 33 * comment in cook.c for more info.
36 34 */
37 35
38 36 #include <string.h>
39 37 #include <ar.h>
40 38 #include <stdlib.h>
41 39 #include <errno.h>
40 +#include <sys/sysmacros.h>
42 41 #include "decl.h"
43 42 #include "member.h"
44 43 #include "msg.h"
45 44
46 45 /*
47 46 * This module is compiled twice, the second time having
48 47 * -D_ELF64 defined. The following set of macros, along
49 48 * with machelf.h, represent the differences between the
50 49 * two compilations. Be careful *not* to add any class-
51 50 * dependent code (anything that has elf32 or elf64 in the
52 51 * name) to this code without hiding it behind a switch-
53 52 * able macro like these.
54 53 */
55 54 #if defined(_ELF64)
56 55 #define Snode Snode64
57 56 #define ELFCLASS ELFCLASS64
58 57 #define ElfField Elf64
59 58 #define _elf_snode_init _elf64_snode_init
60 59 #define _elf_prepscan _elf64_prepscan
61 60 #define _elf_cookscn _elf64_cookscn
62 61 #define _elf_mtype _elf64_mtype
63 62 #define _elf_msize _elf64_msize
64 63 #define elf_fsize elf64_fsize
65 64 #define _elf_snode _elf64_snode
66 65 #define _elf_ehdr _elf64_ehdr
67 66 #define elf_xlatetom elf64_xlatetom
68 67 #define _elf_phdr _elf64_phdr
69 68 #define _elf_shdr _elf64_shdr
70 69 #define _elf_prepscn _elf64_prepscn
71 70
72 71 #else /* Elf32 */
73 72 #define Snode Snode32
74 73 #define ELFCLASS ELFCLASS32
75 74 #define ElfField Elf32
76 75 #define _elf_snode_init _elf32_snode_init
77 76 #define _elf_prepscan _elf32_prepscan
78 77 #define _elf_cookscn _elf32_cookscn
79 78 #define _elf_mtype _elf32_mtype
80 79 #define _elf_msize _elf32_msize
81 80 #define elf_fsize elf32_fsize
82 81 #define _elf_snode _elf32_snode
83 82 #define _elf_ehdr _elf32_ehdr
84 83 #define elf_xlatetom elf32_xlatetom
85 84 #define _elf_phdr _elf32_phdr
86 85 #define _elf_shdr _elf32_shdr
87 86 #define _elf_prepscn _elf32_prepscn
88 87
89 88 #endif /* _ELF64 */
90 89
91 90
92 91 static Okay
93 92 _elf_prepscn(Elf *elf, size_t cnt)
94 93 {
95 94 NOTE(ASSUMING_PROTECTED(*elf))
96 95 Elf_Scn * s;
97 96 Elf_Scn * end;
98 97
99 98 if (cnt == 0)
100 99 return (OK_YES);
101 100
102 101 if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) {
103 102 _elf_seterr(EMEM_SCN, errno);
104 103 return (OK_NO);
105 104 }
106 105 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*s))
107 106 elf->ed_scntabsz = cnt;
108 107 end = s + cnt;
109 108 elf->ed_hdscn = s;
110 109 do {
111 110 *s = _elf_snode_init.sb_scn;
112 111 s->s_elf = elf;
113 112 s->s_next = s + 1;
114 113 s->s_index = s - elf->ed_hdscn;
115 114 s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index;
116 115 ELFMUTEXINIT(&s->s_mutex);
117 116
118 117 /*
119 118 * Section has not yet been cooked!
120 119 *
121 120 * We don't cook a section until it's data is actually
122 121 * referenced.
123 122 */
124 123 s->s_myflags = 0;
125 124 } while (++s < end);
126 125
127 126 elf->ed_tlscn = --s;
128 127 s->s_next = 0;
129 128
130 129 /*
131 130 * Section index SHN_UNDEF (0) does not and cannot
132 131 * have a data buffer. Fix it here. Also mark the
133 132 * initial section as being allocated for the block
134 133 */
135 134
136 135 s = elf->ed_hdscn;
137 136 s->s_myflags = SF_ALLOC;
138 137 s->s_hdnode = 0;
139 138 s->s_tlnode = 0;
140 139 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*s))
141 140 return (OK_YES);
142 141 }
143 142
144 143
145 144 Okay
146 145 _elf_cookscn(Elf_Scn * s)
147 146 {
148 147 NOTE(ASSUMING_PROTECTED(*s, *(s->s_elf)))
149 148 Elf * elf;
150 149 Shdr * sh;
151 150 register Dnode * d = &s->s_dnode;
152 151 size_t fsz, msz;
153 152 unsigned work;
154 153
155 154 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d))
156 155 s->s_hdnode = s->s_tlnode = d;
157 156 s->s_err = 0;
158 157 s->s_shflags = 0;
159 158 s->s_uflags = 0;
160 159
161 160
162 161 /*
163 162 * Prepare d_data for inspection, but don't actually
164 163 * translate data until needed. Leave the READY
165 164 * flag off. NOBITS sections see zero size.
166 165 */
167 166 elf = s->s_elf;
168 167 sh = s->s_shdr;
169 168
↓ open down ↓ |
118 lines elided |
↑ open up ↑ |
170 169 d->db_scn = s;
171 170 d->db_off = sh->sh_offset;
172 171 d->db_data.d_align = sh->sh_addralign;
173 172 d->db_data.d_version = elf->ed_version;
174 173 ELFACCESSDATA(work, _elf_work)
175 174 d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work);
176 175 d->db_data.d_buf = 0;
177 176 d->db_data.d_off = 0;
178 177 fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version);
179 178 msz = _elf_msize(d->db_data.d_type, elf->ed_version);
180 - d->db_data.d_size = (sh->sh_size / fsz) * msz;
179 + d->db_data.d_size = MAX(sh->sh_size, (sh->sh_size / fsz) * msz);
181 180 d->db_shsz = sh->sh_size;
182 181 d->db_raw = 0;
183 182 d->db_buf = 0;
184 183 d->db_uflags = 0;
185 184 d->db_myflags = 0;
186 185 d->db_next = 0;
187 186
188 187 if (sh->sh_type != SHT_NOBITS)
189 188 d->db_fsz = sh->sh_size;
190 189 else
191 190 d->db_fsz = 0;
192 191
193 192 s->s_myflags |= SF_READY;
194 193
195 194 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d))
196 195 return (OK_YES);
197 196 }
198 197
199 198
200 199
201 200 Snode *
202 201 _elf_snode()
203 202 {
204 203 register Snode *s;
205 204
206 205 if ((s = malloc(sizeof (Snode))) == 0) {
207 206 _elf_seterr(EMEM_SNODE, errno);
208 207 return (0);
209 208 }
210 209 *s = _elf_snode_init;
211 210 ELFMUTEXINIT(&s->sb_scn.s_mutex);
212 211 s->sb_scn.s_myflags = SF_ALLOC | SF_READY;
213 212 s->sb_scn.s_shdr = &s->sb_shdr;
214 213 return (s);
215 214 }
216 215
217 216
218 217
219 218 int
220 219 _elf_ehdr(Elf * elf, int inplace)
221 220 {
222 221 NOTE(ASSUMING_PROTECTED(*elf))
223 222 register size_t fsz; /* field size */
224 223 Elf_Data dst, src;
225 224
226 225 fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version);
227 226 if (fsz > elf->ed_fsz) {
228 227 _elf_seterr(EFMT_EHDRSZ, 0);
229 228 return (-1);
230 229 }
231 230 if (inplace && (fsz >= sizeof (Ehdr))) {
232 231 /*
233 232 * The translated Ehdr will fit over the original Ehdr.
234 233 */
235 234 /* LINTED */
236 235 elf->ed_ehdr = (Ehdr *)elf->ed_ident;
237 236 elf->ed_status = ES_COOKED;
238 237 } else {
239 238 elf->ed_ehdr = malloc(sizeof (Ehdr));
240 239 if (elf->ed_ehdr == 0) {
241 240 _elf_seterr(EMEM_EHDR, errno);
242 241 return (-1);
243 242 }
244 243 elf->ed_myflags |= EDF_EHALLOC;
245 244 }
246 245
247 246 /*
248 247 * Memory size >= fsz, because otherwise the memory version
249 248 * loses information and cannot accurately implement the
250 249 * file.
251 250 */
252 251
253 252 src.d_buf = (Elf_Void *)elf->ed_ident;
254 253 src.d_type = ELF_T_EHDR;
255 254 src.d_size = fsz;
256 255 src.d_version = elf->ed_version;
257 256 dst.d_buf = (Elf_Void *)elf->ed_ehdr;
258 257 dst.d_size = sizeof (Ehdr);
259 258 dst.d_version = EV_CURRENT;
260 259
261 260 if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) ||
262 261 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
263 262 if (elf->ed_myflags & EDF_EHALLOC) {
264 263 elf->ed_myflags &= ~EDF_EHALLOC;
265 264 free(elf->ed_ehdr);
266 265 }
267 266 elf->ed_ehdr = 0;
268 267 return (-1);
269 268 }
270 269
271 270 if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) {
272 271 _elf_seterr(EREQ_CLASS, 0);
273 272 if (elf->ed_myflags & EDF_EHALLOC) {
274 273 elf->ed_myflags &= ~EDF_EHALLOC;
275 274 free(elf->ed_ehdr);
276 275 }
277 276 elf->ed_ehdr = 0;
278 277 return (-1);
279 278 }
280 279
281 280 if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) {
282 281 _elf_seterr(EFMT_VER2, 0);
283 282 if (elf->ed_myflags & EDF_EHALLOC) {
284 283 elf->ed_myflags &= ~EDF_EHALLOC;
285 284 free(elf->ed_ehdr);
286 285 }
287 286 elf->ed_ehdr = 0;
288 287 return (-1);
289 288 }
290 289
291 290 return (0);
292 291 }
293 292
294 293
295 294
296 295 int
297 296 _elf_phdr(Elf * elf, int inplace)
298 297 {
299 298 NOTE(ASSUMING_PROTECTED(*elf))
300 299 register size_t fsz, msz;
301 300 Elf_Data dst, src;
302 301 Ehdr * eh = elf->ed_ehdr; /* must be present */
303 302 unsigned work;
304 303
305 304 if (eh->e_phnum == 0)
306 305 return (0);
307 306
308 307 fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version);
309 308 if (eh->e_phentsize != fsz) {
310 309 _elf_seterr(EFMT_PHDRSZ, 0);
311 310 return (-1);
312 311 }
313 312
314 313 fsz *= eh->e_phnum;
315 314 ELFACCESSDATA(work, _elf_work)
316 315 msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum;
317 316 if ((eh->e_phoff == 0) ||
318 317 ((fsz + eh->e_phoff) > elf->ed_fsz)) {
319 318 _elf_seterr(EFMT_PHTAB, 0);
320 319 return (-1);
321 320 }
322 321
323 322 if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) {
324 323 elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
325 324 elf->ed_status = ES_COOKED;
326 325 } else {
327 326 if ((elf->ed_phdr = malloc(msz)) == 0) {
328 327 _elf_seterr(EMEM_PHDR, errno);
329 328 return (-1);
330 329 }
331 330 elf->ed_myflags |= EDF_PHALLOC;
332 331 }
333 332 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
334 333 src.d_type = ELF_T_PHDR;
335 334 src.d_size = fsz;
336 335 src.d_version = elf->ed_version;
337 336 dst.d_buf = elf->ed_phdr;
338 337 dst.d_size = msz;
339 338 dst.d_version = work;
340 339 if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) ||
341 340 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
342 341 if (elf->ed_myflags & EDF_PHALLOC) {
343 342 elf->ed_myflags &= ~EDF_PHALLOC;
344 343 free(elf->ed_phdr);
345 344 }
346 345 elf->ed_phdr = 0;
347 346 return (-1);
348 347 }
349 348 elf->ed_phdrsz = msz;
350 349 return (0);
351 350 }
352 351
353 352
354 353
355 354 int
356 355 _elf_shdr(Elf * elf, int inplace)
357 356 {
358 357 NOTE(ASSUMING_PROTECTED(*elf))
359 358 register size_t fsz, msz;
360 359 size_t scncnt;
361 360 Elf_Data dst, src;
362 361 register Ehdr *eh = elf->ed_ehdr; /* must be present */
363 362
364 363 if ((eh->e_shnum == 0) && (eh->e_shoff == 0))
365 364 return (0);
366 365
367 366 fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version);
368 367 if (eh->e_shentsize != fsz) {
369 368 _elf_seterr(EFMT_SHDRSZ, 0);
370 369 return (-1);
371 370 }
372 371 /*
373 372 * If we are dealing with a file with 'extended section
374 373 * indexes' - then we need to load the first section
375 374 * header. The actual section count is stored in
376 375 * Shdr[0].sh_size.
377 376 */
378 377 if ((scncnt = eh->e_shnum) == 0) {
379 378 Shdr sh;
380 379 if ((eh->e_shoff == 0) ||
381 380 (elf->ed_fsz <= eh->e_shoff) ||
382 381 (elf->ed_fsz - eh->e_shoff < fsz)) {
383 382 _elf_seterr(EFMT_SHTAB, 0);
384 383 return (-1);
385 384 }
386 385 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
387 386 src.d_type = ELF_T_SHDR;
388 387 src.d_size = fsz;
389 388 src.d_version = elf->ed_version;
390 389 dst.d_buf = (Elf_Void *)&sh;
391 390 dst.d_size = sizeof (Shdr);
392 391 dst.d_version = EV_CURRENT;
393 392 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
394 393 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
395 394 return (-1);
396 395 }
397 396 scncnt = sh.sh_size;
398 397 }
399 398
400 399 fsz *= scncnt;
401 400 msz = scncnt * sizeof (Shdr);
402 401 if ((eh->e_shoff == 0) ||
403 402 (elf->ed_fsz <= eh->e_shoff) ||
404 403 (elf->ed_fsz - eh->e_shoff < fsz)) {
405 404 _elf_seterr(EFMT_SHTAB, 0);
406 405 return (-1);
407 406 }
408 407
409 408 if (inplace && (fsz >= msz) &&
410 409 ((eh->e_shoff % sizeof (ElfField)) == 0)) {
411 410 /* LINTED */
412 411 elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff);
413 412 elf->ed_status = ES_COOKED;
414 413 } else {
415 414 if ((elf->ed_shdr = malloc(msz)) == 0) {
416 415 _elf_seterr(EMEM_SHDR, errno);
417 416 return (-1);
418 417 }
419 418 elf->ed_myflags |= EDF_SHALLOC;
420 419 }
421 420 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
422 421 src.d_type = ELF_T_SHDR;
423 422 src.d_size = fsz;
424 423 src.d_version = elf->ed_version;
425 424 dst.d_buf = (Elf_Void *)elf->ed_shdr;
426 425 dst.d_size = msz;
427 426 dst.d_version = EV_CURRENT;
428 427 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
429 428 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) ||
430 429 (_elf_prepscn(elf, scncnt) != OK_YES)) {
431 430 if (elf->ed_myflags & EDF_SHALLOC) {
432 431 elf->ed_myflags &= ~EDF_SHALLOC;
433 432 free(elf->ed_shdr);
434 433 }
435 434 elf->ed_shdr = 0;
436 435 return (-1);
437 436 }
438 437 return (0);
439 438 }
↓ open down ↓ |
249 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX