@ -875,6 +875,8 @@ static void check_section(const char *modname, struct elf_info *elf,
# define DATA_SECTIONS ".data", ".data.rel"
# define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
" .kprobes.text "
# define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
" .fixup " , " .entry.text "
# define INIT_SECTIONS ".init.*"
# define MEM_INIT_SECTIONS ".meminit.*"
@ -882,6 +884,9 @@ static void check_section(const char *modname, struct elf_info *elf,
# define EXIT_SECTIONS ".exit.*"
# define MEM_EXIT_SECTIONS ".memexit.*"
# define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \
TEXT_SECTIONS , OTHER_TEXT_SECTIONS
/* init data sections */
static const char * const init_data_sections [ ] =
{ ALL_INIT_DATA_SECTIONS , NULL } ;
@ -922,6 +927,7 @@ enum mismatch {
ANY_INIT_TO_ANY_EXIT ,
ANY_EXIT_TO_ANY_INIT ,
EXPORT_TO_INIT_EXIT ,
EXTABLE_TO_NON_TEXT ,
} ;
struct sectioncheck {
@ -936,6 +942,11 @@ struct sectioncheck {
} ;
static void extable_mismatch_handler ( const char * modname , struct elf_info * elf ,
const struct sectioncheck * const mismatch ,
Elf_Rela * r , Elf_Sym * sym ,
const char * fromsec ) ;
static const struct sectioncheck sectioncheck [ ] = {
/* Do not reference init/exit code/data from
* normal code and data
@ -1013,6 +1024,16 @@ static const struct sectioncheck sectioncheck[] = {
. bad_tosec = { INIT_SECTIONS , EXIT_SECTIONS , NULL } ,
. mismatch = EXPORT_TO_INIT_EXIT ,
. symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST , NULL } ,
} ,
{
. fromsec = { " __ex_table " , NULL } ,
/* If you're adding any new black-listed sections in here, consider
* adding a special ' printer ' for them in scripts / check_extable .
*/
. bad_tosec = { " .altinstr_replacement " , NULL } ,
. good_tosec = { ALL_TEXT_SECTIONS , NULL } ,
. mismatch = EXTABLE_TO_NON_TEXT ,
. handler = extable_mismatch_handler ,
}
} ;
@ -1418,6 +1439,10 @@ static void report_sec_mismatch(const char *modname,
tosym , prl_to , prl_to , tosym ) ;
free ( prl_to ) ;
break ;
case EXTABLE_TO_NON_TEXT :
fatal ( " There's a special handler for this mismatch type, "
" we should never get here. " ) ;
break ;
}
fprintf ( stderr , " \n " ) ;
}
@ -1453,6 +1478,120 @@ static void default_mismatch_handler(const char *modname, struct elf_info *elf,
}
}
static int is_executable_section ( struct elf_info * elf , unsigned int section_index )
{
if ( section_index > elf - > num_sections )
fatal ( " section_index is outside elf->num_sections! \n " ) ;
return ( ( elf - > sechdrs [ section_index ] . sh_flags & SHF_EXECINSTR ) = = SHF_EXECINSTR ) ;
}
/*
* We rely on a gross hack in section_rel [ a ] ( ) calling find_extable_entry_size ( )
* to know the sizeof ( struct exception_table_entry ) for the target architecture .
*/
static unsigned int extable_entry_size = 0 ;
static void find_extable_entry_size ( const char * const sec , const Elf_Rela * r ,
const void * start , const void * cur )
{
/*
* If we ' re currently checking the second relocation within __ex_table ,
* that relocation offset tells us the offsetof ( struct
* exception_table_entry , fixup ) which is equal to sizeof ( struct
* exception_table_entry ) divided by two . We use that to our advantage
* since there ' s no portable way to get that size as every architecture
* seems to go with different sized types . Not pretty but better than
* hard - coding the size for every architecture . .
*/
if ( ! extable_entry_size & & cur = = start + 1 & &
strcmp ( " __ex_table " , sec ) = = 0 )
extable_entry_size = r - > r_offset * 2 ;
}
static inline bool is_extable_fault_address ( Elf_Rela * r )
{
if ( ! extable_entry_size = = 0 )
fatal ( " extable_entry size hasn't been discovered! \n " ) ;
return ( ( r - > r_offset = = 0 ) | |
( r - > r_offset % extable_entry_size = = 0 ) ) ;
}
static void report_extable_warnings ( const char * modname , struct elf_info * elf ,
const struct sectioncheck * const mismatch ,
Elf_Rela * r , Elf_Sym * sym ,
const char * fromsec , const char * tosec )
{
Elf_Sym * fromsym = find_elf_symbol2 ( elf , r - > r_offset , fromsec ) ;
const char * fromsym_name = sym_name ( elf , fromsym ) ;
Elf_Sym * tosym = find_elf_symbol ( elf , r - > r_addend , sym ) ;
const char * tosym_name = sym_name ( elf , tosym ) ;
const char * from_pretty_name ;
const char * from_pretty_name_p ;
const char * to_pretty_name ;
const char * to_pretty_name_p ;
get_pretty_name ( is_function ( fromsym ) ,
& from_pretty_name , & from_pretty_name_p ) ;
get_pretty_name ( is_function ( tosym ) ,
& to_pretty_name , & to_pretty_name_p ) ;
warn ( " %s(%s+0x%lx): Section mismatch in reference "
" from the %s %s%s to the %s %s:%s%s \n " ,
modname , fromsec , ( long ) r - > r_offset , from_pretty_name ,
fromsym_name , from_pretty_name_p ,
to_pretty_name , tosec , tosym_name , to_pretty_name_p ) ;
if ( ! match ( tosec , mismatch - > bad_tosec ) & &
is_executable_section ( elf , get_secindex ( elf , sym ) ) )
fprintf ( stderr ,
" The relocation at %s+0x%lx references \n "
" section \" %s \" which is not in the list of \n "
" authorized sections. If you're adding a new section \n "
" and/or if this reference is valid, add \" %s \" to the \n "
" list of authorized sections to jump to on fault. \n "
" This can be achieved by adding \" %s \" to \n "
" OTHER_TEXT_SECTIONS in scripts/mod/modpost.c. \n " ,
fromsec , ( long ) r - > r_offset , tosec , tosec , tosec ) ;
}
static void extable_mismatch_handler ( const char * modname , struct elf_info * elf ,
const struct sectioncheck * const mismatch ,
Elf_Rela * r , Elf_Sym * sym ,
const char * fromsec )
{
const char * tosec = sec_name ( elf , get_secindex ( elf , sym ) ) ;
sec_mismatch_count + + ;
if ( sec_mismatch_verbose )
report_extable_warnings ( modname , elf , mismatch , r , sym ,
fromsec , tosec ) ;
if ( match ( tosec , mismatch - > bad_tosec ) )
fatal ( " The relocation at %s+0x%lx references \n "
" section \" %s \" which is black-listed. \n "
" Something is seriously wrong and should be fixed. \n "
" You might get more information about where this is \n "
" coming from by using scripts/check_extable.sh %s \n " ,
fromsec , ( long ) r - > r_offset , tosec , modname ) ;
else if ( ! is_executable_section ( elf , get_secindex ( elf , sym ) ) ) {
if ( is_extable_fault_address ( r ) )
fatal ( " The relocation at %s+0x%lx references \n "
" section \" %s \" which is not executable, IOW \n "
" it is not possible for the kernel to fault \n "
" at that address. Something is seriously wrong \n "
" and should be fixed. \n " ,
fromsec , ( long ) r - > r_offset , tosec ) ;
else
fatal ( " The relocation at %s+0x%lx references \n "
" section \" %s \" which is not executable, IOW \n "
" the kernel will fault if it ever tries to \n "
" jump to it. Something is seriously wrong \n "
" and should be fixed. \n " ,
fromsec , ( long ) r - > r_offset , tosec ) ;
}
}
static void check_section_mismatch ( const char * modname , struct elf_info * elf ,
Elf_Rela * r , Elf_Sym * sym , const char * fromsec )
{
@ -1605,6 +1744,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
/* Skip special sections */
if ( is_shndx_special ( sym - > st_shndx ) )
continue ;
find_extable_entry_size ( fromsec , & r , start , rela ) ;
check_section_mismatch ( modname , elf , & r , sym , fromsec ) ;
}
}
@ -1663,6 +1803,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
/* Skip special sections */
if ( is_shndx_special ( sym - > st_shndx ) )
continue ;
find_extable_entry_size ( fromsec , & r , start , rel ) ;
check_section_mismatch ( modname , elf , & r , sym , fromsec ) ;
}
}