]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
s390/kexec_file: fix error handling when applying relocations
authorPhilipp Rudo <prudo@redhat.com>
Wed, 8 Dec 2021 13:07:41 +0000 (14:07 +0100)
committerAndrea Righi <andrea.righi@canonical.com>
Tue, 4 Jan 2022 08:49:25 +0000 (09:49 +0100)
BugLink: https://bugs.launchpad.net/bugs/1956302
[ Upstream commit 41967a37b8eedfee15b81406a9f3015be90d3980 ]

arch_kexec_apply_relocations_add currently ignores all errors returned
by arch_kexec_do_relocs. This means that every unknown relocation is
silently skipped causing unpredictable behavior while the relocated code
runs. Fix this by checking for errors and fail kexec_file_load if an
unknown relocation type is encountered.

The problem was found after gcc changed its behavior and used
R_390_PLT32DBL relocations for brasl instruction and relied on ld to
resolve the relocations in the final link in case direct calls are
possible. As the purgatory code is only linked partially (option -r)
ld didn't resolve the relocations leaving them for arch_kexec_do_relocs.
But arch_kexec_do_relocs doesn't know how to handle R_390_PLT32DBL
relocations so they were silently skipped. This ultimately caused an
endless loop in the purgatory as the brasl instructions kept branching
to itself.

Fixes: 71406883fd35 ("s390/kexec_file: Add kexec_file_load system call")
Reported-by: Tao Liu <ltao@redhat.com>
Signed-off-by: Philipp Rudo <prudo@redhat.com>
Link: https://lore.kernel.org/r/20211208130741.5821-3-prudo@redhat.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
arch/s390/kernel/machine_kexec_file.c

index e7435f3a3d2d225afb5e4614530977a4d2dfeac0..76cd09879eaf452314d0d7aae30e5ebd9707d74d 100644 (file)
@@ -277,6 +277,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
 {
        Elf_Rela *relas;
        int i, r_type;
+       int ret;
 
        relas = (void *)pi->ehdr + relsec->sh_offset;
 
@@ -311,7 +312,11 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                addr = section->sh_addr + relas[i].r_offset;
 
                r_type = ELF64_R_TYPE(relas[i].r_info);
-               arch_kexec_do_relocs(r_type, loc, val, addr);
+               ret = arch_kexec_do_relocs(r_type, loc, val, addr);
+               if (ret) {
+                       pr_err("Unknown rela relocation: %d\n", r_type);
+                       return -ENOEXEC;
+               }
        }
        return 0;
 }