2017-09-11 15:15:29 +02:00
// SPDX-License-Identifier: GPL-2.0
/*
* ELF loader for kexec_file_load system call .
*
* Copyright IBM Corp . 2018
*
* Author ( s ) : Philipp Rudo < prudo @ linux . vnet . ibm . com >
*/
# include <linux/errno.h>
# include <linux/kernel.h>
# include <linux/kexec.h>
2019-03-18 12:53:47 +01:00
# include <asm/ipl.h>
2017-09-11 15:15:29 +02:00
# include <asm/setup.h>
2019-03-07 12:48:03 +01:00
static int kexec_file_add_kernel_elf ( struct kimage * image ,
struct s390_load_data * data )
2017-09-11 15:15:29 +02:00
{
struct kexec_buf buf ;
const Elf_Ehdr * ehdr ;
const Elf_Phdr * phdr ;
2019-04-01 12:48:43 +02:00
Elf_Addr entry ;
2019-03-07 12:48:03 +01:00
void * kernel ;
2017-09-11 15:15:29 +02:00
int i , ret ;
2019-03-07 12:48:03 +01:00
kernel = image - > kernel_buf ;
2017-09-11 15:15:29 +02:00
ehdr = ( Elf_Ehdr * ) kernel ;
buf . image = image ;
2019-04-01 12:48:43 +02:00
if ( image - > type = = KEXEC_TYPE_CRASH )
entry = STARTUP_KDUMP_OFFSET ;
else
entry = ehdr - > e_entry ;
2017-09-11 15:15:29 +02:00
phdr = ( void * ) ehdr + ehdr - > e_phoff ;
for ( i = 0 ; i < ehdr - > e_phnum ; i + + , phdr + + ) {
if ( phdr - > p_type ! = PT_LOAD )
continue ;
buf . buffer = kernel + phdr - > p_offset ;
buf . bufsz = phdr - > p_filesz ;
buf . mem = ALIGN ( phdr - > p_paddr , phdr - > p_align ) ;
2019-03-07 15:56:34 +01:00
if ( image - > type = = KEXEC_TYPE_CRASH )
buf . mem + = crashk_res . start ;
2017-09-11 15:15:29 +02:00
buf . memsz = phdr - > p_memsz ;
2019-03-07 15:56:34 +01:00
data - > memsz = ALIGN ( data - > memsz , phdr - > p_align ) + buf . memsz ;
2017-09-11 15:15:29 +02:00
2019-04-01 12:48:43 +02:00
if ( entry - phdr - > p_paddr < phdr - > p_memsz ) {
2017-09-11 15:15:29 +02:00
data - > kernel_buf = buf . buffer ;
2019-03-07 15:56:34 +01:00
data - > kernel_mem = buf . mem ;
2019-03-06 17:36:26 +01:00
data - > parm = buf . buffer + PARMAREA ;
2017-09-11 15:15:29 +02:00
}
2019-03-18 12:53:47 +01:00
ipl_report_add_component ( data - > report , & buf ,
IPL_RB_COMPONENT_FLAG_SIGNED |
IPL_RB_COMPONENT_FLAG_VERIFIED ,
IPL_RB_CERT_UNKNOWN ) ;
2017-09-11 15:15:29 +02:00
ret = kexec_add_buffer ( & buf ) ;
if ( ret )
return ret ;
}
2019-03-07 12:48:03 +01:00
return data - > memsz ? 0 : - EINVAL ;
2017-09-11 15:15:29 +02:00
}
static void * s390_elf_load ( struct kimage * image ,
char * kernel , unsigned long kernel_len ,
char * initrd , unsigned long initrd_len ,
char * cmdline , unsigned long cmdline_len )
{
const Elf_Ehdr * ehdr ;
const Elf_Phdr * phdr ;
size_t size ;
2019-03-07 12:48:03 +01:00
int i ;
2017-09-11 15:15:29 +02:00
/* image->fobs->probe already checked for valid ELF magic number. */
ehdr = ( Elf_Ehdr * ) kernel ;
if ( ehdr - > e_type ! = ET_EXEC | |
ehdr - > e_ident [ EI_CLASS ] ! = ELFCLASS64 | |
! elf_check_arch ( ehdr ) )
return ERR_PTR ( - EINVAL ) ;
if ( ! ehdr - > e_phnum | | ehdr - > e_phentsize ! = sizeof ( Elf_Phdr ) )
return ERR_PTR ( - EINVAL ) ;
size = ehdr - > e_ehsize + ehdr - > e_phoff ;
size + = ehdr - > e_phentsize * ehdr - > e_phnum ;
if ( size > kernel_len )
return ERR_PTR ( - EINVAL ) ;
phdr = ( void * ) ehdr + ehdr - > e_phoff ;
size = ALIGN ( size , phdr - > p_align ) ;
for ( i = 0 ; i < ehdr - > e_phnum ; i + + , phdr + + ) {
if ( phdr - > p_type = = PT_INTERP )
return ERR_PTR ( - EINVAL ) ;
if ( phdr - > p_offset > kernel_len )
return ERR_PTR ( - EINVAL ) ;
size + = ALIGN ( phdr - > p_filesz , phdr - > p_align ) ;
}
if ( size > kernel_len )
return ERR_PTR ( - EINVAL ) ;
2019-03-07 12:48:03 +01:00
return kexec_file_add_components ( image , kexec_file_add_kernel_elf ) ;
2017-09-11 15:15:29 +02:00
}
static int s390_elf_probe ( const char * buf , unsigned long len )
{
const Elf_Ehdr * ehdr ;
if ( len < sizeof ( Elf_Ehdr ) )
return - ENOEXEC ;
ehdr = ( Elf_Ehdr * ) buf ;
/* Only check the ELF magic number here and do proper validity check
* in the loader . Any check here that fails would send the erroneous
* ELF file to the image loader that does not care what it gets .
* ( Most likely ) causing behavior not intended by the user .
*/
if ( memcmp ( ehdr - > e_ident , ELFMAG , SELFMAG ) ! = 0 )
return - ENOEXEC ;
return 0 ;
}
const struct kexec_file_ops s390_kexec_elf_ops = {
. probe = s390_elf_probe ,
. load = s390_elf_load ,
2019-02-26 10:50:39 +01:00
# ifdef CONFIG_KEXEC_VERIFY_SIG
. verify_sig = s390_verify_sig ,
# endif /* CONFIG_KEXEC_VERIFY_SIG */
2017-09-11 15:15:29 +02:00
} ;