Skip to content

Commit d38e485

Browse files
author
Alexander Gordeev
committed
s390/crash: Do not use VM info if os_info does not have it
The virtual memory information stored in os_info area is required for creation of the kernel image PT_LOAD program header for kernels since commit a2ec5bec56dd ("s390/mm: uncouple physical vs virtual address spaces"). By contrast, if such information in os_info is absent the PT_LOAD program header should not be created. Currently the proper PT_LOAD program header is created for kernels that contain the virtual memory information, but for kernels without one an invalid header of zero size is created. That in turn leads to stand-alone dump failures. Use OS_INFO_KASLR_OFFSET variable to check whether os_info is present or not (same as crash and makedumpfile tools do) and based on that create or do not create the kernel image PT_LOAD program header. Fixes: f4cac27 ("s390/crash: Use old os_info to create PT_LOAD headers") Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com> Acked-by: Mikhail Zaslonko <zaslonko@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
1 parent c3f38fa commit d38e485

File tree

1 file changed

+30
-24
lines changed

1 file changed

+30
-24
lines changed

arch/s390/kernel/crash_dump.c

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ static void *nt_final(void *ptr)
451451
/*
452452
* Initialize ELF header (new kernel)
453453
*/
454-
static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
454+
static void *ehdr_init(Elf64_Ehdr *ehdr, int phdr_count)
455455
{
456456
memset(ehdr, 0, sizeof(*ehdr));
457457
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
@@ -465,11 +465,8 @@ static void *ehdr_init(Elf64_Ehdr *ehdr, int mem_chunk_cnt)
465465
ehdr->e_phoff = sizeof(Elf64_Ehdr);
466466
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
467467
ehdr->e_phentsize = sizeof(Elf64_Phdr);
468-
/*
469-
* Number of memory chunk PT_LOAD program headers plus one kernel
470-
* image PT_LOAD program header plus one PT_NOTE program header.
471-
*/
472-
ehdr->e_phnum = mem_chunk_cnt + 1 + 1;
468+
/* Number of PT_LOAD program headers plus PT_NOTE program header */
469+
ehdr->e_phnum = phdr_count + 1;
473470
return ehdr + 1;
474471
}
475472

@@ -503,12 +500,14 @@ static int get_mem_chunk_cnt(void)
503500
/*
504501
* Initialize ELF loads (new kernel)
505502
*/
506-
static void loads_init(Elf64_Phdr *phdr)
503+
static void loads_init(Elf64_Phdr *phdr, bool os_info_has_vm)
507504
{
508-
unsigned long old_identity_base = os_info_old_value(OS_INFO_IDENTITY_BASE);
505+
unsigned long old_identity_base = 0;
509506
phys_addr_t start, end;
510507
u64 idx;
511508

509+
if (os_info_has_vm)
510+
old_identity_base = os_info_old_value(OS_INFO_IDENTITY_BASE);
512511
for_each_physmem_range(idx, &oldmem_type, &start, &end) {
513512
phdr->p_type = PT_LOAD;
514513
phdr->p_vaddr = old_identity_base + start;
@@ -522,6 +521,11 @@ static void loads_init(Elf64_Phdr *phdr)
522521
}
523522
}
524523

524+
static bool os_info_has_vm(void)
525+
{
526+
return os_info_old_value(OS_INFO_KASLR_OFFSET);
527+
}
528+
525529
/*
526530
* Prepare PT_LOAD type program header for kernel image region
527531
*/
@@ -566,7 +570,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
566570
return ptr;
567571
}
568572

569-
static size_t get_elfcorehdr_size(int mem_chunk_cnt)
573+
static size_t get_elfcorehdr_size(int phdr_count)
570574
{
571575
size_t size;
572576

@@ -581,10 +585,8 @@ static size_t get_elfcorehdr_size(int mem_chunk_cnt)
581585
size += nt_vmcoreinfo_size();
582586
/* nt_final */
583587
size += sizeof(Elf64_Nhdr);
584-
/* PT_LOAD type program header for kernel text region */
585-
size += sizeof(Elf64_Phdr);
586588
/* PT_LOADS */
587-
size += mem_chunk_cnt * sizeof(Elf64_Phdr);
589+
size += phdr_count * sizeof(Elf64_Phdr);
588590

589591
return size;
590592
}
@@ -595,8 +597,8 @@ static size_t get_elfcorehdr_size(int mem_chunk_cnt)
595597
int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
596598
{
597599
Elf64_Phdr *phdr_notes, *phdr_loads, *phdr_text;
600+
int mem_chunk_cnt, phdr_text_cnt;
598601
size_t alloc_size;
599-
int mem_chunk_cnt;
600602
void *ptr, *hdr;
601603
u64 hdr_off;
602604

@@ -615,34 +617,38 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
615617
}
616618

617619
mem_chunk_cnt = get_mem_chunk_cnt();
620+
phdr_text_cnt = os_info_has_vm() ? 1 : 0;
618621

619-
alloc_size = get_elfcorehdr_size(mem_chunk_cnt);
622+
alloc_size = get_elfcorehdr_size(mem_chunk_cnt + phdr_text_cnt);
620623

621624
hdr = kzalloc(alloc_size, GFP_KERNEL);
622625

623-
/* Without elfcorehdr /proc/vmcore cannot be created. Thus creating
626+
/*
627+
* Without elfcorehdr /proc/vmcore cannot be created. Thus creating
624628
* a dump with this crash kernel will fail. Panic now to allow other
625629
* dump mechanisms to take over.
626630
*/
627631
if (!hdr)
628632
panic("s390 kdump allocating elfcorehdr failed");
629633

630634
/* Init elf header */
631-
ptr = ehdr_init(hdr, mem_chunk_cnt);
635+
phdr_notes = ehdr_init(hdr, mem_chunk_cnt + phdr_text_cnt);
632636
/* Init program headers */
633-
phdr_notes = ptr;
634-
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
635-
phdr_text = ptr;
636-
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
637-
phdr_loads = ptr;
638-
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * mem_chunk_cnt);
637+
if (phdr_text_cnt) {
638+
phdr_text = phdr_notes + 1;
639+
phdr_loads = phdr_text + 1;
640+
} else {
641+
phdr_loads = phdr_notes + 1;
642+
}
643+
ptr = PTR_ADD(phdr_loads, sizeof(Elf64_Phdr) * mem_chunk_cnt);
639644
/* Init notes */
640645
hdr_off = PTR_DIFF(ptr, hdr);
641646
ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
642647
/* Init kernel text program header */
643-
text_init(phdr_text);
648+
if (phdr_text_cnt)
649+
text_init(phdr_text);
644650
/* Init loads */
645-
loads_init(phdr_loads);
651+
loads_init(phdr_loads, phdr_text_cnt);
646652
/* Finalize program headers */
647653
hdr_off = PTR_DIFF(ptr, hdr);
648654
*addr = (unsigned long long) hdr;

0 commit comments

Comments
 (0)