@@ -11,8 +11,9 @@ use crate::{
11
11
ebpf:: { self , EF_SBPF_V2 , HOST_ALIGN , INSN_SIZE } ,
12
12
elf_parser:: {
13
13
consts:: {
14
- ELFCLASS64 , ELFDATA2LSB , ELFOSABI_NONE , EM_BPF , EM_SBPF , ET_DYN , R_X86_64_32 ,
15
- R_X86_64_64 , R_X86_64_NONE , R_X86_64_RELATIVE ,
14
+ ELFCLASS64 , ELFDATA2LSB , ELFOSABI_NONE , EM_BPF , EM_SBPF , ET_DYN , PF_R , PF_W , PF_X ,
15
+ PT_GNU_STACK , PT_LOAD , R_X86_64_32 , R_X86_64_64 , R_X86_64_NONE , R_X86_64_RELATIVE ,
16
+ STT_FUNC ,
16
17
} ,
17
18
types:: { Elf64Phdr , Elf64Shdr , Elf64Word } ,
18
19
Elf64 , ElfParserError ,
@@ -378,10 +379,129 @@ impl<C: ContextObject> Executable<C> {
378
379
aligned = AlignedMemory :: < { HOST_ALIGN } > :: from_slice ( bytes) ;
379
380
aligned. as_slice ( )
380
381
} ;
381
- Self :: load_with_parser ( & Elf64 :: parse ( bytes) ?, bytes, loader)
382
+ let elf = Elf64 :: parse ( bytes) ?;
383
+ let sbpf_version = if elf. file_header ( ) . e_flags == EF_SBPF_V2 {
384
+ SBPFVersion :: V2
385
+ } else {
386
+ SBPFVersion :: V1
387
+ } ;
388
+ if !loader
389
+ . get_config ( )
390
+ . enabled_sbpf_versions
391
+ . contains ( & sbpf_version)
392
+ {
393
+ return Err ( ElfError :: UnsupportedSBPFVersion ) ;
394
+ }
395
+ if sbpf_version == SBPFVersion :: V1 {
396
+ Self :: load_with_lenient_parser ( & elf, bytes, loader)
397
+ } else {
398
+ Self :: load_with_strict_parser ( & elf, bytes, loader) . map_err ( |err| err. into ( ) )
399
+ }
400
+ }
401
+
402
+ fn load_with_strict_parser (
403
+ elf : & Elf64 ,
404
+ bytes : & [ u8 ] ,
405
+ loader : Arc < BuiltinProgram < C > > ,
406
+ ) -> Result < Self , ElfParserError > {
407
+ const EXPECTED_PROGRAM_HEADERS : [ ( u32 , u32 , u64 ) ; 4 ] = [
408
+ ( PT_LOAD , PF_R | PF_X , 0 ) , // byte code
409
+ ( PT_LOAD , PF_R , ebpf:: MM_RODATA_START ) , // read only data
410
+ ( PT_GNU_STACK , PF_R | PF_W , ebpf:: MM_STACK_START ) , // stack
411
+ ( PT_LOAD , PF_R | PF_W , ebpf:: MM_HEAP_START ) , // heap
412
+ ] ;
413
+ if elf. file_header ( ) . e_type != ET_DYN
414
+ || elf. file_header ( ) . e_ident . ei_osabi != 0x00
415
+ || elf. file_header ( ) . e_ident . ei_abiversion != 0x00
416
+ || elf. program_header_table ( ) . len ( ) < EXPECTED_PROGRAM_HEADERS . len ( )
417
+ {
418
+ return Err ( ElfParserError :: InvalidFileHeader ) ;
419
+ }
420
+ const REGION_MASK : u64 = ( -( 1i64 << 32 ) ) as u64 ;
421
+ for ( program_header, ( p_type, p_flags, p_vaddr) ) in elf
422
+ . program_header_table ( )
423
+ . iter ( )
424
+ . zip ( EXPECTED_PROGRAM_HEADERS . iter ( ) )
425
+ {
426
+ if program_header. p_type != * p_type
427
+ || program_header. p_flags != * p_flags
428
+ || program_header. p_paddr != * p_vaddr
429
+ || program_header. p_vaddr != * p_vaddr
430
+ || program_header. p_memsz & REGION_MASK != 0
431
+ || program_header. p_filesz > program_header. p_memsz
432
+ {
433
+ return Err ( ElfParserError :: InvalidProgramHeader ) ;
434
+ }
435
+ }
436
+ let config = loader. get_config ( ) ;
437
+ let text_section = & elf. section_header_table ( ) [ 1 ] ;
438
+ let rodata_section = & elf. section_header_table ( ) [ 2 ] ;
439
+ let symbol_table = elf
440
+ . dynamic_symbol_table ( )
441
+ . ok_or ( ElfParserError :: InvalidFileHeader ) ?;
442
+ let mut function_registry = FunctionRegistry :: < usize > :: default ( ) ;
443
+ for symbol in symbol_table {
444
+ if symbol. st_info & STT_FUNC == 0 {
445
+ continue ;
446
+ }
447
+ if !text_section. vm_range ( ) . contains ( & symbol. st_value )
448
+ || symbol. st_value . checked_rem ( ebpf:: INSN_SIZE as u64 ) != Some ( 0 )
449
+ {
450
+ return Err ( ElfParserError :: OutOfBounds ) ;
451
+ }
452
+ let target_pc = symbol
453
+ . st_value
454
+ . saturating_sub ( text_section. sh_addr )
455
+ . checked_div ( ebpf:: INSN_SIZE as u64 )
456
+ . unwrap_or_default ( ) as usize ;
457
+ function_registry
458
+ . register_function (
459
+ target_pc as u32 ,
460
+ if config. enable_symbol_and_section_labels {
461
+ elf. symbol_name ( symbol. st_name as Elf64Word ) ?
462
+ } else {
463
+ & [ ]
464
+ } ,
465
+ target_pc,
466
+ )
467
+ . map_err ( |_| ElfParserError :: Overlap ) ?;
468
+ }
469
+ if !text_section. vm_range ( ) . contains ( & elf. file_header ( ) . e_entry )
470
+ || elf
471
+ . file_header ( )
472
+ . e_entry
473
+ . checked_rem ( ebpf:: INSN_SIZE as u64 )
474
+ != Some ( 0 )
475
+ {
476
+ return Err ( ElfParserError :: OutOfBounds ) ;
477
+ }
478
+ let entry_pc = elf
479
+ . file_header ( )
480
+ . e_entry
481
+ . saturating_sub ( text_section. sh_addr )
482
+ . checked_div ( ebpf:: INSN_SIZE as u64 )
483
+ . unwrap_or_default ( ) as usize ;
484
+ if function_registry. lookup_by_key ( entry_pc as u32 ) . is_none ( ) {
485
+ return Err ( ElfParserError :: InvalidFileHeader ) ;
486
+ }
487
+ Ok ( Self {
488
+ elf_bytes : AlignedMemory :: from_slice ( bytes) , // TODO: borrow
489
+ sbpf_version : SBPFVersion :: V2 ,
490
+ ro_section : Section :: Borrowed (
491
+ rodata_section. sh_addr as usize ,
492
+ rodata_section. file_range ( ) . unwrap_or_default ( ) ,
493
+ ) ,
494
+ text_section_vaddr : text_section. sh_addr , // ebpf::MM_RODATA_START,
495
+ text_section_range : text_section. file_range ( ) . unwrap_or_default ( ) ,
496
+ entry_pc,
497
+ function_registry,
498
+ loader,
499
+ #[ cfg( all( feature = "jit" , not( target_os = "windows" ) , target_arch = "x86_64" ) ) ]
500
+ compiled_program : None ,
501
+ } )
382
502
}
383
503
384
- fn load_with_parser (
504
+ fn load_with_lenient_parser (
385
505
elf : & Elf64 ,
386
506
bytes : & [ u8 ] ,
387
507
loader : Arc < BuiltinProgram < C > > ,
@@ -1947,4 +2067,11 @@ mod test {
1947
2067
SECTION_NAME_LENGTH_MAXIMUM
1948
2068
) ;
1949
2069
}
2070
+
2071
+ #[ test]
2072
+ fn test_strict_header ( ) {
2073
+ let elf_bytes =
2074
+ std:: fs:: read ( "tests/elfs/strict_header.so" ) . expect ( "failed to read elf file" ) ;
2075
+ ElfExecutable :: load ( & elf_bytes, loader ( ) ) . expect ( "validation failed" ) ;
2076
+ }
1950
2077
}
0 commit comments