@@ -391,11 +391,211 @@ impl<C: ContextObject> Executable<C> {
391
391
return Err ( ElfError :: UnsupportedSBPFVersion ) ;
392
392
}
393
393
394
- let mut executable = Self :: load_with_lenient_parser ( bytes, loader) ?;
394
+ let mut executable = if sbpf_version. enable_stricter_elf_headers ( ) {
395
+ Self :: load_with_strict_parser ( bytes, loader) ?
396
+ } else {
397
+ Self :: load_with_lenient_parser ( bytes, loader) ?
398
+ } ;
395
399
executable. sbpf_version = sbpf_version;
396
400
Ok ( executable)
397
401
}
398
402
403
+ /// Loads an ELF without relocation
404
+ fn load_with_strict_parser (
405
+ bytes : & [ u8 ] ,
406
+ loader : Arc < BuiltinProgram < C > > ,
407
+ ) -> Result < Self , ElfParserError > {
408
+ use crate :: elf_parser:: {
409
+ consts:: {
410
+ ELFMAG , EV_CURRENT , PF_R , PF_W , PF_X , PT_GNU_STACK , PT_LOAD , SHN_UNDEF , STT_FUNC ,
411
+ } ,
412
+ types:: { Elf64Ehdr , Elf64Shdr , Elf64Sym } ,
413
+ } ;
414
+
415
+ let aligned_memory = AlignedMemory :: < { HOST_ALIGN } > :: from_slice ( bytes) ;
416
+ let elf_bytes = aligned_memory. as_slice ( ) ;
417
+
418
+ let ( file_header_range, file_header) = Elf64 :: parse_file_header ( elf_bytes) ?;
419
+ let program_header_table_range = mem:: size_of :: < Elf64Ehdr > ( )
420
+ ..mem:: size_of :: < Elf64Phdr > ( )
421
+ . saturating_mul ( file_header. e_phnum as usize )
422
+ . saturating_add ( mem:: size_of :: < Elf64Ehdr > ( ) ) ;
423
+ if file_header. e_ident . ei_mag != ELFMAG
424
+ || file_header. e_ident . ei_class != ELFCLASS64
425
+ || file_header. e_ident . ei_data != ELFDATA2LSB
426
+ || file_header. e_ident . ei_version != EV_CURRENT as u8
427
+ || file_header. e_ident . ei_osabi != ELFOSABI_NONE
428
+ || file_header. e_ident . ei_abiversion != 0x00
429
+ || file_header. e_ident . ei_pad != [ 0x00 ; 7 ]
430
+ || file_header. e_type != ET_DYN
431
+ || file_header. e_machine != EM_SBPF
432
+ || file_header. e_version != EV_CURRENT
433
+ // file_header.e_entry
434
+ || file_header. e_phoff != mem:: size_of :: < Elf64Ehdr > ( ) as u64
435
+ // file_header.e_shoff
436
+ // file_header.e_flags
437
+ || file_header. e_ehsize != mem:: size_of :: < Elf64Ehdr > ( ) as u16
438
+ || file_header. e_phentsize != mem:: size_of :: < Elf64Phdr > ( ) as u16
439
+ || file_header. e_phnum < EXPECTED_PROGRAM_HEADERS . len ( ) as u16
440
+ || program_header_table_range. end >= elf_bytes. len ( )
441
+ || file_header. e_shentsize != mem:: size_of :: < Elf64Shdr > ( ) as u16
442
+ // file_header.e_shnum
443
+ || file_header. e_shstrndx >= file_header. e_shnum
444
+ {
445
+ return Err ( ElfParserError :: InvalidFileHeader ) ;
446
+ }
447
+
448
+ const EXPECTED_PROGRAM_HEADERS : [ ( u32 , u32 , u64 ) ; 5 ] = [
449
+ ( PT_LOAD , PF_R | PF_X , ebpf:: MM_BYTECODE_START ) , // byte code
450
+ ( PT_LOAD , PF_R , ebpf:: MM_RODATA_START ) , // read only data
451
+ ( PT_GNU_STACK , PF_R | PF_W , ebpf:: MM_STACK_START ) , // stack
452
+ ( PT_LOAD , PF_R | PF_W , ebpf:: MM_HEAP_START ) , // heap
453
+ ( PT_LOAD , PF_R , 0xFFFFFFFF00000000 ) , // dynamic symbol table
454
+ ] ;
455
+ let program_header_table =
456
+ Elf64 :: slice_from_bytes :: < Elf64Phdr > ( elf_bytes, program_header_table_range. clone ( ) ) ?;
457
+ for ( program_header, ( p_type, p_flags, p_vaddr) ) in program_header_table
458
+ . iter ( )
459
+ . zip ( EXPECTED_PROGRAM_HEADERS . iter ( ) )
460
+ {
461
+ let p_filesz = if ( * p_flags & PF_W ) != 0 {
462
+ 0
463
+ } else {
464
+ program_header. p_memsz
465
+ } ;
466
+ if program_header. p_type != * p_type
467
+ || program_header. p_flags != * p_flags
468
+ || program_header. p_offset < program_header_table_range. end as u64
469
+ || program_header. p_offset >= elf_bytes. len ( ) as u64
470
+ || program_header. p_offset . checked_rem ( ebpf:: INSN_SIZE as u64 ) != Some ( 0 )
471
+ || program_header. p_vaddr != * p_vaddr
472
+ || program_header. p_paddr != * p_vaddr
473
+ || program_header. p_filesz != p_filesz
474
+ || program_header. p_filesz
475
+ > ( elf_bytes. len ( ) as u64 ) . saturating_sub ( program_header. p_offset )
476
+ || program_header. p_memsz >= ebpf:: MM_REGION_SIZE
477
+ {
478
+ return Err ( ElfParserError :: InvalidProgramHeader ) ;
479
+ }
480
+ }
481
+
482
+ let config = loader. get_config ( ) ;
483
+ let symbol_names_section_header = if config. enable_symbol_and_section_labels {
484
+ let ( _section_header_table_range, section_header_table) =
485
+ Elf64 :: parse_section_header_table (
486
+ elf_bytes,
487
+ file_header_range. clone ( ) ,
488
+ file_header,
489
+ program_header_table_range. clone ( ) ,
490
+ ) ?;
491
+ let section_names_section_header = ( file_header. e_shstrndx != SHN_UNDEF )
492
+ . then ( || {
493
+ section_header_table
494
+ . get ( file_header. e_shstrndx as usize )
495
+ . ok_or ( ElfParserError :: OutOfBounds )
496
+ } )
497
+ . transpose ( ) ?
498
+ . ok_or ( ElfParserError :: NoSectionNameStringTable ) ?;
499
+ let mut symbol_names_section_header = None ;
500
+ for section_header in section_header_table. iter ( ) {
501
+ let section_name = Elf64 :: get_string_in_section (
502
+ elf_bytes,
503
+ section_names_section_header,
504
+ section_header. sh_name ,
505
+ 64 ,
506
+ ) ?;
507
+ if section_name == b".strtab" {
508
+ symbol_names_section_header = Some ( section_header) ;
509
+ }
510
+ }
511
+ symbol_names_section_header
512
+ } else {
513
+ None
514
+ } ;
515
+ let bytecode_header = & program_header_table[ 0 ] ;
516
+ let rodata_header = & program_header_table[ 1 ] ;
517
+ let dynamic_symbol_table: & [ Elf64Sym ] =
518
+ Elf64 :: slice_from_program_header ( elf_bytes, & program_header_table[ 4 ] ) ?;
519
+ let mut function_registry = FunctionRegistry :: < usize > :: default ( ) ;
520
+ let mut expected_symbol_address = bytecode_header. p_vaddr ;
521
+ for symbol in dynamic_symbol_table {
522
+ if symbol. st_info & STT_FUNC == 0 {
523
+ continue ;
524
+ }
525
+ if symbol. st_value != expected_symbol_address {
526
+ return Err ( ElfParserError :: OutOfBounds ) ;
527
+ }
528
+ if symbol. st_size == 0 || symbol. st_size . checked_rem ( ebpf:: INSN_SIZE as u64 ) != Some ( 0 )
529
+ {
530
+ return Err ( ElfParserError :: InvalidSize ) ;
531
+ }
532
+ if symbol. st_size
533
+ > bytecode_header
534
+ . vm_range ( )
535
+ . end
536
+ . saturating_sub ( symbol. st_value )
537
+ {
538
+ return Err ( ElfParserError :: OutOfBounds ) ;
539
+ }
540
+ let target_pc = symbol
541
+ . st_value
542
+ . saturating_sub ( bytecode_header. p_vaddr )
543
+ . checked_div ( ebpf:: INSN_SIZE as u64 )
544
+ . unwrap_or_default ( ) as usize ;
545
+ let name = if config. enable_symbol_and_section_labels {
546
+ Elf64 :: get_string_in_section (
547
+ elf_bytes,
548
+ symbol_names_section_header
549
+ . as_ref ( )
550
+ . ok_or ( ElfParserError :: NoStringTable ) ?,
551
+ symbol. st_name as Elf64Word ,
552
+ 1024 , // SYMBOL_NAME_LENGTH_MAXIMUM,
553
+ ) ?
554
+ } else {
555
+ & [ ]
556
+ } ;
557
+ function_registry
558
+ . register_function ( target_pc as u32 , name, target_pc)
559
+ . unwrap ( ) ;
560
+ expected_symbol_address = symbol. st_value . saturating_add ( symbol. st_size ) ;
561
+ }
562
+ if expected_symbol_address != bytecode_header. vm_range ( ) . end {
563
+ return Err ( ElfParserError :: OutOfBounds ) ;
564
+ }
565
+ if !bytecode_header. vm_range ( ) . contains ( & file_header. e_entry )
566
+ || file_header. e_entry . checked_rem ( ebpf:: INSN_SIZE as u64 ) != Some ( 0 )
567
+ {
568
+ return Err ( ElfParserError :: InvalidFileHeader ) ;
569
+ }
570
+ let entry_pc = file_header
571
+ . e_entry
572
+ . saturating_sub ( bytecode_header. p_vaddr )
573
+ . checked_div ( ebpf:: INSN_SIZE as u64 )
574
+ . unwrap_or_default ( ) as usize ;
575
+ if function_registry. lookup_by_key ( entry_pc as u32 ) . is_none ( ) {
576
+ return Err ( ElfParserError :: InvalidFileHeader ) ;
577
+ }
578
+
579
+ let text_section_vaddr = bytecode_header. p_vaddr ;
580
+ let text_section_range = bytecode_header. file_range ( ) . unwrap_or_default ( ) ;
581
+ let ro_section = Section :: Borrowed (
582
+ rodata_header. p_vaddr as usize ,
583
+ rodata_header. file_range ( ) . unwrap_or_default ( ) ,
584
+ ) ;
585
+ Ok ( Self {
586
+ elf_bytes : aligned_memory,
587
+ sbpf_version : SBPFVersion :: Reserved , // Is set in Self::load()
588
+ ro_section,
589
+ text_section_vaddr,
590
+ text_section_range,
591
+ entry_pc,
592
+ function_registry,
593
+ loader,
594
+ #[ cfg( all( feature = "jit" , not( target_os = "windows" ) , target_arch = "x86_64" ) ) ]
595
+ compiled_program : None ,
596
+ } )
597
+ }
598
+
399
599
/// Loads an ELF with relocation
400
600
fn load_with_lenient_parser (
401
601
bytes : & [ u8 ] ,
0 commit comments