@@ -6,6 +6,7 @@ use elf::{
66 file:: Class ,
77 ElfBytes ,
88} ;
9+ use eyre:: OptionExt ;
910use hashbrown:: HashMap ;
1011use sp1_primitives:: consts:: { MAXIMUM_MEMORY_SIZE , WORD_SIZE } ;
1112
@@ -82,6 +83,11 @@ impl Elf {
8283 let mut instructions: Vec < u32 > = Vec :: new ( ) ;
8384 let mut base_address = u32:: MAX ;
8485
86+ // Data about the last segment.
87+ let mut prev_segment_end_addr = None ;
88+
89+ // Check that the segments are sorted and disjoint.
90+
8591 // Only read segments that are executable instructions that are also PT_LOAD.
8692 for segment in segments. iter ( ) . filter ( |x| x. p_type == PT_LOAD ) {
8793 // Get the file size of the segment as an u32.
@@ -102,10 +108,30 @@ impl Elf {
102108 eyre:: bail!( "vaddr {vaddr:08x} is unaligned" ) ;
103109 }
104110
105- // If the virtual address is less than the first memory address, then update the first
106- // memory address.
107- if ( segment. p_flags & PF_X ) != 0 && base_address > vaddr {
108- base_address = vaddr;
111+ // Check that the ELF structure is supported.
112+ if let Some ( last_addr) = prev_segment_end_addr {
113+ eyre:: ensure!( last_addr <= vaddr, "unsupported elf structure" ) ;
114+ }
115+ prev_segment_end_addr =
116+ Some ( vaddr. checked_add ( mem_size) . ok_or_eyre ( "last addr overflow" ) ?) ;
117+
118+ if ( segment. p_flags & PF_X ) != 0 {
119+ if base_address == u32:: MAX {
120+ base_address = vaddr;
121+ eyre:: ensure!(
122+ base_address > 0x20 ,
123+ "base address {base_address} should be greater than 0x20"
124+ ) ;
125+ } else {
126+ let instr_len: u32 = WORD_SIZE
127+ . checked_mul ( instructions. len ( ) )
128+ . ok_or_eyre ( "instructions length overflow" ) ?
129+ . try_into ( ) ?;
130+ let last_instruction_addr = base_address
131+ . checked_add ( instr_len)
132+ . ok_or_eyre ( "instruction addr overflow" ) ?;
133+ eyre:: ensure!( vaddr == last_instruction_addr, "unsupported elf structure" ) ;
134+ }
109135 }
110136
111137 // Get the offset to the segment.
0 commit comments