diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/proc/vmcore.c | 359 |
1 files changed, 286 insertions, 73 deletions
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 78c87a1ac01a..9b9270eb0599 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -34,6 +34,9 @@ static char *elfcorebuf; | |||
34 | static size_t elfcorebuf_sz; | 34 | static size_t elfcorebuf_sz; |
35 | static size_t elfcorebuf_sz_orig; | 35 | static size_t elfcorebuf_sz_orig; |
36 | 36 | ||
37 | static char *elfnotes_buf; | ||
38 | static size_t elfnotes_sz; | ||
39 | |||
37 | /* Total size of vmcore file. */ | 40 | /* Total size of vmcore file. */ |
38 | static u64 vmcore_size; | 41 | static u64 vmcore_size; |
39 | 42 | ||
@@ -139,9 +142,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, | |||
139 | 142 | ||
140 | /* Read ELF core header */ | 143 | /* Read ELF core header */ |
141 | if (*fpos < elfcorebuf_sz) { | 144 | if (*fpos < elfcorebuf_sz) { |
142 | tsz = elfcorebuf_sz - *fpos; | 145 | tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen); |
143 | if (buflen < tsz) | ||
144 | tsz = buflen; | ||
145 | if (copy_to_user(buffer, elfcorebuf + *fpos, tsz)) | 146 | if (copy_to_user(buffer, elfcorebuf + *fpos, tsz)) |
146 | return -EFAULT; | 147 | return -EFAULT; |
147 | buflen -= tsz; | 148 | buflen -= tsz; |
@@ -154,11 +155,27 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer, | |||
154 | return acc; | 155 | return acc; |
155 | } | 156 | } |
156 | 157 | ||
158 | /* Read Elf note segment */ | ||
159 | if (*fpos < elfcorebuf_sz + elfnotes_sz) { | ||
160 | void *kaddr; | ||
161 | |||
162 | tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen); | ||
163 | kaddr = elfnotes_buf + *fpos - elfcorebuf_sz; | ||
164 | if (copy_to_user(buffer, kaddr, tsz)) | ||
165 | return -EFAULT; | ||
166 | buflen -= tsz; | ||
167 | *fpos += tsz; | ||
168 | buffer += tsz; | ||
169 | acc += tsz; | ||
170 | |||
171 | /* leave now if filled buffer already */ | ||
172 | if (buflen == 0) | ||
173 | return acc; | ||
174 | } | ||
175 | |||
157 | list_for_each_entry(m, &vmcore_list, list) { | 176 | list_for_each_entry(m, &vmcore_list, list) { |
158 | if (*fpos < m->offset + m->size) { | 177 | if (*fpos < m->offset + m->size) { |
159 | tsz = m->offset + m->size - *fpos; | 178 | tsz = min_t(size_t, m->offset + m->size - *fpos, buflen); |
160 | if (buflen < tsz) | ||
161 | tsz = buflen; | ||
162 | start = m->paddr + *fpos - m->offset; | 179 | start = m->paddr + *fpos - m->offset; |
163 | tmp = read_from_oldmem(buffer, tsz, &start, 1); | 180 | tmp = read_from_oldmem(buffer, tsz, &start, 1); |
164 | if (tmp < 0) | 181 | if (tmp < 0) |
@@ -221,27 +238,27 @@ static u64 __init get_vmcore_size_elf32(char *elfptr, size_t elfsz) | |||
221 | return size; | 238 | return size; |
222 | } | 239 | } |
223 | 240 | ||
224 | /* Merges all the PT_NOTE headers into one. */ | 241 | /** |
225 | static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, | 242 | * update_note_header_size_elf64 - update p_memsz member of each PT_NOTE entry |
226 | struct list_head *vc_list) | 243 | * |
244 | * @ehdr_ptr: ELF header | ||
245 | * | ||
246 | * This function updates p_memsz member of each PT_NOTE entry in the | ||
247 | * program header table pointed to by @ehdr_ptr to real size of ELF | ||
248 | * note segment. | ||
249 | */ | ||
250 | static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr) | ||
227 | { | 251 | { |
228 | int i, nr_ptnote=0, rc=0; | 252 | int i, rc=0; |
229 | char *tmp; | 253 | Elf64_Phdr *phdr_ptr; |
230 | Elf64_Ehdr *ehdr_ptr; | ||
231 | Elf64_Phdr phdr, *phdr_ptr; | ||
232 | Elf64_Nhdr *nhdr_ptr; | 254 | Elf64_Nhdr *nhdr_ptr; |
233 | u64 phdr_sz = 0, note_off; | ||
234 | 255 | ||
235 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | 256 | phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1); |
236 | phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); | ||
237 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | 257 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { |
238 | int j; | ||
239 | void *notes_section; | 258 | void *notes_section; |
240 | struct vmcore *new; | ||
241 | u64 offset, max_sz, sz, real_sz = 0; | 259 | u64 offset, max_sz, sz, real_sz = 0; |
242 | if (phdr_ptr->p_type != PT_NOTE) | 260 | if (phdr_ptr->p_type != PT_NOTE) |
243 | continue; | 261 | continue; |
244 | nr_ptnote++; | ||
245 | max_sz = phdr_ptr->p_memsz; | 262 | max_sz = phdr_ptr->p_memsz; |
246 | offset = phdr_ptr->p_offset; | 263 | offset = phdr_ptr->p_offset; |
247 | notes_section = kmalloc(max_sz, GFP_KERNEL); | 264 | notes_section = kmalloc(max_sz, GFP_KERNEL); |
@@ -253,7 +270,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, | |||
253 | return rc; | 270 | return rc; |
254 | } | 271 | } |
255 | nhdr_ptr = notes_section; | 272 | nhdr_ptr = notes_section; |
256 | for (j = 0; j < max_sz; j += sz) { | 273 | while (real_sz < max_sz) { |
257 | if (nhdr_ptr->n_namesz == 0) | 274 | if (nhdr_ptr->n_namesz == 0) |
258 | break; | 275 | break; |
259 | sz = sizeof(Elf64_Nhdr) + | 276 | sz = sizeof(Elf64_Nhdr) + |
@@ -262,26 +279,122 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, | |||
262 | real_sz += sz; | 279 | real_sz += sz; |
263 | nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz); | 280 | nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz); |
264 | } | 281 | } |
265 | |||
266 | /* Add this contiguous chunk of notes section to vmcore list.*/ | ||
267 | new = get_new_element(); | ||
268 | if (!new) { | ||
269 | kfree(notes_section); | ||
270 | return -ENOMEM; | ||
271 | } | ||
272 | new->paddr = phdr_ptr->p_offset; | ||
273 | new->size = real_sz; | ||
274 | list_add_tail(&new->list, vc_list); | ||
275 | phdr_sz += real_sz; | ||
276 | kfree(notes_section); | 282 | kfree(notes_section); |
283 | phdr_ptr->p_memsz = real_sz; | ||
277 | } | 284 | } |
278 | 285 | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * get_note_number_and_size_elf64 - get the number of PT_NOTE program | ||
291 | * headers and sum of real size of their ELF note segment headers and | ||
292 | * data. | ||
293 | * | ||
294 | * @ehdr_ptr: ELF header | ||
295 | * @nr_ptnote: buffer for the number of PT_NOTE program headers | ||
296 | * @sz_ptnote: buffer for size of unique PT_NOTE program header | ||
297 | * | ||
298 | * This function is used to merge multiple PT_NOTE program headers | ||
299 | * into a unique single one. The resulting unique entry will have | ||
300 | * @sz_ptnote in its phdr->p_mem. | ||
301 | * | ||
302 | * It is assumed that program headers with PT_NOTE type pointed to by | ||
303 | * @ehdr_ptr has already been updated by update_note_header_size_elf64 | ||
304 | * and each of PT_NOTE program headers has actual ELF note segment | ||
305 | * size in its p_memsz member. | ||
306 | */ | ||
307 | static int __init get_note_number_and_size_elf64(const Elf64_Ehdr *ehdr_ptr, | ||
308 | int *nr_ptnote, u64 *sz_ptnote) | ||
309 | { | ||
310 | int i; | ||
311 | Elf64_Phdr *phdr_ptr; | ||
312 | |||
313 | *nr_ptnote = *sz_ptnote = 0; | ||
314 | |||
315 | phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1); | ||
316 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
317 | if (phdr_ptr->p_type != PT_NOTE) | ||
318 | continue; | ||
319 | *nr_ptnote += 1; | ||
320 | *sz_ptnote += phdr_ptr->p_memsz; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * copy_notes_elf64 - copy ELF note segments in a given buffer | ||
328 | * | ||
329 | * @ehdr_ptr: ELF header | ||
330 | * @notes_buf: buffer into which ELF note segments are copied | ||
331 | * | ||
332 | * This function is used to copy ELF note segment in the 1st kernel | ||
333 | * into the buffer @notes_buf in the 2nd kernel. It is assumed that | ||
334 | * size of the buffer @notes_buf is equal to or larger than sum of the | ||
335 | * real ELF note segment headers and data. | ||
336 | * | ||
337 | * It is assumed that program headers with PT_NOTE type pointed to by | ||
338 | * @ehdr_ptr has already been updated by update_note_header_size_elf64 | ||
339 | * and each of PT_NOTE program headers has actual ELF note segment | ||
340 | * size in its p_memsz member. | ||
341 | */ | ||
342 | static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf) | ||
343 | { | ||
344 | int i, rc=0; | ||
345 | Elf64_Phdr *phdr_ptr; | ||
346 | |||
347 | phdr_ptr = (Elf64_Phdr*)(ehdr_ptr + 1); | ||
348 | |||
349 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
350 | u64 offset; | ||
351 | if (phdr_ptr->p_type != PT_NOTE) | ||
352 | continue; | ||
353 | offset = phdr_ptr->p_offset; | ||
354 | rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0); | ||
355 | if (rc < 0) | ||
356 | return rc; | ||
357 | notes_buf += phdr_ptr->p_memsz; | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | /* Merges all the PT_NOTE headers into one. */ | ||
364 | static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, | ||
365 | char **notes_buf, size_t *notes_sz) | ||
366 | { | ||
367 | int i, nr_ptnote=0, rc=0; | ||
368 | char *tmp; | ||
369 | Elf64_Ehdr *ehdr_ptr; | ||
370 | Elf64_Phdr phdr; | ||
371 | u64 phdr_sz = 0, note_off; | ||
372 | |||
373 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | ||
374 | |||
375 | rc = update_note_header_size_elf64(ehdr_ptr); | ||
376 | if (rc < 0) | ||
377 | return rc; | ||
378 | |||
379 | rc = get_note_number_and_size_elf64(ehdr_ptr, &nr_ptnote, &phdr_sz); | ||
380 | if (rc < 0) | ||
381 | return rc; | ||
382 | |||
383 | *notes_sz = roundup(phdr_sz, PAGE_SIZE); | ||
384 | *notes_buf = vzalloc(*notes_sz); | ||
385 | if (!*notes_buf) | ||
386 | return -ENOMEM; | ||
387 | |||
388 | rc = copy_notes_elf64(ehdr_ptr, *notes_buf); | ||
389 | if (rc < 0) | ||
390 | return rc; | ||
391 | |||
279 | /* Prepare merged PT_NOTE program header. */ | 392 | /* Prepare merged PT_NOTE program header. */ |
280 | phdr.p_type = PT_NOTE; | 393 | phdr.p_type = PT_NOTE; |
281 | phdr.p_flags = 0; | 394 | phdr.p_flags = 0; |
282 | note_off = sizeof(Elf64_Ehdr) + | 395 | note_off = sizeof(Elf64_Ehdr) + |
283 | (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr); | 396 | (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr); |
284 | phdr.p_offset = note_off; | 397 | phdr.p_offset = roundup(note_off, PAGE_SIZE); |
285 | phdr.p_vaddr = phdr.p_paddr = 0; | 398 | phdr.p_vaddr = phdr.p_paddr = 0; |
286 | phdr.p_filesz = phdr.p_memsz = phdr_sz; | 399 | phdr.p_filesz = phdr.p_memsz = phdr_sz; |
287 | phdr.p_align = 0; | 400 | phdr.p_align = 0; |
@@ -304,27 +417,27 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz, | |||
304 | return 0; | 417 | return 0; |
305 | } | 418 | } |
306 | 419 | ||
307 | /* Merges all the PT_NOTE headers into one. */ | 420 | /** |
308 | static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, | 421 | * update_note_header_size_elf32 - update p_memsz member of each PT_NOTE entry |
309 | struct list_head *vc_list) | 422 | * |
423 | * @ehdr_ptr: ELF header | ||
424 | * | ||
425 | * This function updates p_memsz member of each PT_NOTE entry in the | ||
426 | * program header table pointed to by @ehdr_ptr to real size of ELF | ||
427 | * note segment. | ||
428 | */ | ||
429 | static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr) | ||
310 | { | 430 | { |
311 | int i, nr_ptnote=0, rc=0; | 431 | int i, rc=0; |
312 | char *tmp; | 432 | Elf32_Phdr *phdr_ptr; |
313 | Elf32_Ehdr *ehdr_ptr; | ||
314 | Elf32_Phdr phdr, *phdr_ptr; | ||
315 | Elf32_Nhdr *nhdr_ptr; | 433 | Elf32_Nhdr *nhdr_ptr; |
316 | u64 phdr_sz = 0, note_off; | ||
317 | 434 | ||
318 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | 435 | phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1); |
319 | phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); | ||
320 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | 436 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { |
321 | int j; | ||
322 | void *notes_section; | 437 | void *notes_section; |
323 | struct vmcore *new; | ||
324 | u64 offset, max_sz, sz, real_sz = 0; | 438 | u64 offset, max_sz, sz, real_sz = 0; |
325 | if (phdr_ptr->p_type != PT_NOTE) | 439 | if (phdr_ptr->p_type != PT_NOTE) |
326 | continue; | 440 | continue; |
327 | nr_ptnote++; | ||
328 | max_sz = phdr_ptr->p_memsz; | 441 | max_sz = phdr_ptr->p_memsz; |
329 | offset = phdr_ptr->p_offset; | 442 | offset = phdr_ptr->p_offset; |
330 | notes_section = kmalloc(max_sz, GFP_KERNEL); | 443 | notes_section = kmalloc(max_sz, GFP_KERNEL); |
@@ -336,7 +449,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, | |||
336 | return rc; | 449 | return rc; |
337 | } | 450 | } |
338 | nhdr_ptr = notes_section; | 451 | nhdr_ptr = notes_section; |
339 | for (j = 0; j < max_sz; j += sz) { | 452 | while (real_sz < max_sz) { |
340 | if (nhdr_ptr->n_namesz == 0) | 453 | if (nhdr_ptr->n_namesz == 0) |
341 | break; | 454 | break; |
342 | sz = sizeof(Elf32_Nhdr) + | 455 | sz = sizeof(Elf32_Nhdr) + |
@@ -345,26 +458,122 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, | |||
345 | real_sz += sz; | 458 | real_sz += sz; |
346 | nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz); | 459 | nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz); |
347 | } | 460 | } |
348 | |||
349 | /* Add this contiguous chunk of notes section to vmcore list.*/ | ||
350 | new = get_new_element(); | ||
351 | if (!new) { | ||
352 | kfree(notes_section); | ||
353 | return -ENOMEM; | ||
354 | } | ||
355 | new->paddr = phdr_ptr->p_offset; | ||
356 | new->size = real_sz; | ||
357 | list_add_tail(&new->list, vc_list); | ||
358 | phdr_sz += real_sz; | ||
359 | kfree(notes_section); | 461 | kfree(notes_section); |
462 | phdr_ptr->p_memsz = real_sz; | ||
463 | } | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | /** | ||
469 | * get_note_number_and_size_elf32 - get the number of PT_NOTE program | ||
470 | * headers and sum of real size of their ELF note segment headers and | ||
471 | * data. | ||
472 | * | ||
473 | * @ehdr_ptr: ELF header | ||
474 | * @nr_ptnote: buffer for the number of PT_NOTE program headers | ||
475 | * @sz_ptnote: buffer for size of unique PT_NOTE program header | ||
476 | * | ||
477 | * This function is used to merge multiple PT_NOTE program headers | ||
478 | * into a unique single one. The resulting unique entry will have | ||
479 | * @sz_ptnote in its phdr->p_mem. | ||
480 | * | ||
481 | * It is assumed that program headers with PT_NOTE type pointed to by | ||
482 | * @ehdr_ptr has already been updated by update_note_header_size_elf32 | ||
483 | * and each of PT_NOTE program headers has actual ELF note segment | ||
484 | * size in its p_memsz member. | ||
485 | */ | ||
486 | static int __init get_note_number_and_size_elf32(const Elf32_Ehdr *ehdr_ptr, | ||
487 | int *nr_ptnote, u64 *sz_ptnote) | ||
488 | { | ||
489 | int i; | ||
490 | Elf32_Phdr *phdr_ptr; | ||
491 | |||
492 | *nr_ptnote = *sz_ptnote = 0; | ||
493 | |||
494 | phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1); | ||
495 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
496 | if (phdr_ptr->p_type != PT_NOTE) | ||
497 | continue; | ||
498 | *nr_ptnote += 1; | ||
499 | *sz_ptnote += phdr_ptr->p_memsz; | ||
360 | } | 500 | } |
361 | 501 | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * copy_notes_elf32 - copy ELF note segments in a given buffer | ||
507 | * | ||
508 | * @ehdr_ptr: ELF header | ||
509 | * @notes_buf: buffer into which ELF note segments are copied | ||
510 | * | ||
511 | * This function is used to copy ELF note segment in the 1st kernel | ||
512 | * into the buffer @notes_buf in the 2nd kernel. It is assumed that | ||
513 | * size of the buffer @notes_buf is equal to or larger than sum of the | ||
514 | * real ELF note segment headers and data. | ||
515 | * | ||
516 | * It is assumed that program headers with PT_NOTE type pointed to by | ||
517 | * @ehdr_ptr has already been updated by update_note_header_size_elf32 | ||
518 | * and each of PT_NOTE program headers has actual ELF note segment | ||
519 | * size in its p_memsz member. | ||
520 | */ | ||
521 | static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf) | ||
522 | { | ||
523 | int i, rc=0; | ||
524 | Elf32_Phdr *phdr_ptr; | ||
525 | |||
526 | phdr_ptr = (Elf32_Phdr*)(ehdr_ptr + 1); | ||
527 | |||
528 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | ||
529 | u64 offset; | ||
530 | if (phdr_ptr->p_type != PT_NOTE) | ||
531 | continue; | ||
532 | offset = phdr_ptr->p_offset; | ||
533 | rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0); | ||
534 | if (rc < 0) | ||
535 | return rc; | ||
536 | notes_buf += phdr_ptr->p_memsz; | ||
537 | } | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | /* Merges all the PT_NOTE headers into one. */ | ||
543 | static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, | ||
544 | char **notes_buf, size_t *notes_sz) | ||
545 | { | ||
546 | int i, nr_ptnote=0, rc=0; | ||
547 | char *tmp; | ||
548 | Elf32_Ehdr *ehdr_ptr; | ||
549 | Elf32_Phdr phdr; | ||
550 | u64 phdr_sz = 0, note_off; | ||
551 | |||
552 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | ||
553 | |||
554 | rc = update_note_header_size_elf32(ehdr_ptr); | ||
555 | if (rc < 0) | ||
556 | return rc; | ||
557 | |||
558 | rc = get_note_number_and_size_elf32(ehdr_ptr, &nr_ptnote, &phdr_sz); | ||
559 | if (rc < 0) | ||
560 | return rc; | ||
561 | |||
562 | *notes_sz = roundup(phdr_sz, PAGE_SIZE); | ||
563 | *notes_buf = vzalloc(*notes_sz); | ||
564 | if (!*notes_buf) | ||
565 | return -ENOMEM; | ||
566 | |||
567 | rc = copy_notes_elf32(ehdr_ptr, *notes_buf); | ||
568 | if (rc < 0) | ||
569 | return rc; | ||
570 | |||
362 | /* Prepare merged PT_NOTE program header. */ | 571 | /* Prepare merged PT_NOTE program header. */ |
363 | phdr.p_type = PT_NOTE; | 572 | phdr.p_type = PT_NOTE; |
364 | phdr.p_flags = 0; | 573 | phdr.p_flags = 0; |
365 | note_off = sizeof(Elf32_Ehdr) + | 574 | note_off = sizeof(Elf32_Ehdr) + |
366 | (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr); | 575 | (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr); |
367 | phdr.p_offset = note_off; | 576 | phdr.p_offset = roundup(note_off, PAGE_SIZE); |
368 | phdr.p_vaddr = phdr.p_paddr = 0; | 577 | phdr.p_vaddr = phdr.p_paddr = 0; |
369 | phdr.p_filesz = phdr.p_memsz = phdr_sz; | 578 | phdr.p_filesz = phdr.p_memsz = phdr_sz; |
370 | phdr.p_align = 0; | 579 | phdr.p_align = 0; |
@@ -391,6 +600,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz, | |||
391 | * the new offset fields of exported program headers. */ | 600 | * the new offset fields of exported program headers. */ |
392 | static int __init process_ptload_program_headers_elf64(char *elfptr, | 601 | static int __init process_ptload_program_headers_elf64(char *elfptr, |
393 | size_t elfsz, | 602 | size_t elfsz, |
603 | size_t elfnotes_sz, | ||
394 | struct list_head *vc_list) | 604 | struct list_head *vc_list) |
395 | { | 605 | { |
396 | int i; | 606 | int i; |
@@ -402,9 +612,8 @@ static int __init process_ptload_program_headers_elf64(char *elfptr, | |||
402 | ehdr_ptr = (Elf64_Ehdr *)elfptr; | 612 | ehdr_ptr = (Elf64_Ehdr *)elfptr; |
403 | phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */ | 613 | phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */ |
404 | 614 | ||
405 | /* First program header is PT_NOTE header. */ | 615 | /* Skip Elf header, program headers and Elf note segment. */ |
406 | vmcore_off = elfsz + | 616 | vmcore_off = elfsz + elfnotes_sz; |
407 | phdr_ptr->p_memsz; /* Note sections */ | ||
408 | 617 | ||
409 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | 618 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { |
410 | u64 paddr, start, end, size; | 619 | u64 paddr, start, end, size; |
@@ -434,6 +643,7 @@ static int __init process_ptload_program_headers_elf64(char *elfptr, | |||
434 | 643 | ||
435 | static int __init process_ptload_program_headers_elf32(char *elfptr, | 644 | static int __init process_ptload_program_headers_elf32(char *elfptr, |
436 | size_t elfsz, | 645 | size_t elfsz, |
646 | size_t elfnotes_sz, | ||
437 | struct list_head *vc_list) | 647 | struct list_head *vc_list) |
438 | { | 648 | { |
439 | int i; | 649 | int i; |
@@ -445,9 +655,8 @@ static int __init process_ptload_program_headers_elf32(char *elfptr, | |||
445 | ehdr_ptr = (Elf32_Ehdr *)elfptr; | 655 | ehdr_ptr = (Elf32_Ehdr *)elfptr; |
446 | phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */ | 656 | phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */ |
447 | 657 | ||
448 | /* First program header is PT_NOTE header. */ | 658 | /* Skip Elf header, program headers and Elf note segment. */ |
449 | vmcore_off = elfsz + | 659 | vmcore_off = elfsz + elfnotes_sz; |
450 | phdr_ptr->p_memsz; /* Note sections */ | ||
451 | 660 | ||
452 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { | 661 | for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) { |
453 | u64 paddr, start, end, size; | 662 | u64 paddr, start, end, size; |
@@ -476,14 +685,14 @@ static int __init process_ptload_program_headers_elf32(char *elfptr, | |||
476 | } | 685 | } |
477 | 686 | ||
478 | /* Sets offset fields of vmcore elements. */ | 687 | /* Sets offset fields of vmcore elements. */ |
479 | static void __init set_vmcore_list_offsets(size_t elfsz, | 688 | static void __init set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz, |
480 | struct list_head *vc_list) | 689 | struct list_head *vc_list) |
481 | { | 690 | { |
482 | loff_t vmcore_off; | 691 | loff_t vmcore_off; |
483 | struct vmcore *m; | 692 | struct vmcore *m; |
484 | 693 | ||
485 | /* Skip Elf header and program headers. */ | 694 | /* Skip Elf header, program headers and Elf note segment. */ |
486 | vmcore_off = elfsz; | 695 | vmcore_off = elfsz + elfnotes_sz; |
487 | 696 | ||
488 | list_for_each_entry(m, vc_list, list) { | 697 | list_for_each_entry(m, vc_list, list) { |
489 | m->offset = vmcore_off; | 698 | m->offset = vmcore_off; |
@@ -495,6 +704,8 @@ static void free_elfcorebuf(void) | |||
495 | { | 704 | { |
496 | free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig)); | 705 | free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig)); |
497 | elfcorebuf = NULL; | 706 | elfcorebuf = NULL; |
707 | vfree(elfnotes_buf); | ||
708 | elfnotes_buf = NULL; | ||
498 | } | 709 | } |
499 | 710 | ||
500 | static int __init parse_crash_elf64_headers(void) | 711 | static int __init parse_crash_elf64_headers(void) |
@@ -538,14 +749,15 @@ static int __init parse_crash_elf64_headers(void) | |||
538 | goto fail; | 749 | goto fail; |
539 | 750 | ||
540 | /* Merge all PT_NOTE headers into one. */ | 751 | /* Merge all PT_NOTE headers into one. */ |
541 | rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list); | 752 | rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, |
753 | &elfnotes_buf, &elfnotes_sz); | ||
542 | if (rc) | 754 | if (rc) |
543 | goto fail; | 755 | goto fail; |
544 | rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz, | 756 | rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz, |
545 | &vmcore_list); | 757 | elfnotes_sz, &vmcore_list); |
546 | if (rc) | 758 | if (rc) |
547 | goto fail; | 759 | goto fail; |
548 | set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list); | 760 | set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list); |
549 | return 0; | 761 | return 0; |
550 | fail: | 762 | fail: |
551 | free_elfcorebuf(); | 763 | free_elfcorebuf(); |
@@ -592,14 +804,15 @@ static int __init parse_crash_elf32_headers(void) | |||
592 | goto fail; | 804 | goto fail; |
593 | 805 | ||
594 | /* Merge all PT_NOTE headers into one. */ | 806 | /* Merge all PT_NOTE headers into one. */ |
595 | rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list); | 807 | rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, |
808 | &elfnotes_buf, &elfnotes_sz); | ||
596 | if (rc) | 809 | if (rc) |
597 | goto fail; | 810 | goto fail; |
598 | rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz, | 811 | rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz, |
599 | &vmcore_list); | 812 | elfnotes_sz, &vmcore_list); |
600 | if (rc) | 813 | if (rc) |
601 | goto fail; | 814 | goto fail; |
602 | set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list); | 815 | set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list); |
603 | return 0; | 816 | return 0; |
604 | fail: | 817 | fail: |
605 | free_elfcorebuf(); | 818 | free_elfcorebuf(); |