Skip to content
This repository was archived by the owner on Jan 10, 2025. It is now read-only.

Commit c20a353

Browse files
authored
Feature - Restrict ro data layout in SBPFv2 (#481)
* Restricts SBPFv2 to borrowable readonly section layouts. * Adjusts the tests accordingly.
1 parent 31b7cad commit c20a353

File tree

5 files changed

+114
-99
lines changed

5 files changed

+114
-99
lines changed

src/elf.rs

Lines changed: 112 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,9 @@ impl<V: Verifier, C: ContextObject> Executable<V, C> {
905905
.saturating_add(1)
906906
.saturating_sub(first_ro_section)
907907
== n_ro_sections;
908+
if sbpf_version.enable_elf_vaddr() && !can_borrow {
909+
return Err(ElfError::ValueOutOfBounds);
910+
}
908911
let ro_section = if config.optimize_rodata && can_borrow {
909912
// Read only sections are grouped together with no intermixed non-ro
910913
// sections. We can borrow.
@@ -924,6 +927,9 @@ impl<V: Verifier, C: ContextObject> Executable<V, C> {
924927
// it now.
925928
lowest_addr.saturating_sub(ebpf::MM_PROGRAM_START as usize)
926929
} else {
930+
if sbpf_version.enable_elf_vaddr() {
931+
return Err(ElfError::ValueOutOfBounds);
932+
}
927933
lowest_addr
928934
};
929935

@@ -1760,7 +1766,9 @@ mod test {
17601766
fn new_section(sh_addr: u64, sh_size: u64) -> Elf64Shdr {
17611767
Elf64Shdr {
17621768
sh_addr,
1763-
sh_offset: sh_addr,
1769+
sh_offset: sh_addr
1770+
.checked_sub(ebpf::MM_PROGRAM_START)
1771+
.unwrap_or(sh_addr),
17641772
sh_size,
17651773
sh_name: 0,
17661774
sh_type: 0,
@@ -1790,7 +1798,7 @@ mod test {
17901798
assert!(matches!(
17911799
ElfExecutable::parse_ro_sections(
17921800
&config,
1793-
&SBPFVersion::V2,
1801+
&SBPFVersion::V1,
17941802
sections,
17951803
&elf_bytes,
17961804
),
@@ -1817,7 +1825,7 @@ mod test {
18171825
assert!(matches!(
18181826
ElfExecutable::parse_ro_sections(
18191827
&config,
1820-
&SBPFVersion::V2,
1828+
&SBPFVersion::V1,
18211829
sections,
18221830
&elf_bytes,
18231831
),
@@ -1895,7 +1903,7 @@ mod test {
18951903
let sections: [(Option<&[u8]>, &Elf64Shdr); 2] =
18961904
[(Some(b".text"), &s1), (Some(b".rodata"), &s2)];
18971905
assert_eq!(
1898-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes,),
1906+
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes),
18991907
Err(ElfError::ValueOutOfBounds)
19001908
);
19011909
}
@@ -1917,7 +1925,7 @@ mod test {
19171925
let sections: [(Option<&[u8]>, &Elf64Shdr); 2] =
19181926
[(Some(b".text"), &s1), (Some(b".rodata"), &s2)];
19191927
assert_eq!(
1920-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes,),
1928+
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes),
19211929
Ok(Section::Borrowed(10, 100..120))
19221930
);
19231931
}
@@ -1938,7 +1946,7 @@ mod test {
19381946
(Some(b".rodata"), &s3),
19391947
];
19401948
let ro_section =
1941-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes)
1949+
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V1, sections, &elf_bytes)
19421950
.unwrap();
19431951
let ro_region = get_ro_region(&ro_section, &elf_bytes);
19441952
let owned_section = match &ro_section {
@@ -2020,7 +2028,7 @@ mod test {
20202028
(Some(b".rodata"), &s3),
20212029
];
20222030
let ro_section =
2023-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes)
2031+
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V1, sections, &elf_bytes)
20242032
.unwrap();
20252033
let owned_section = match &ro_section {
20262034
Section::Owned(_offset, data) => data.as_slice(),
@@ -2091,107 +2099,117 @@ mod test {
20912099
fn test_borrowed_ro_sections() {
20922100
let config = Config::default();
20932101
let elf_bytes = [0u8; 512];
2094-
2095-
let s1 = new_section(0, 10);
2096-
let s2 = new_section(20, 10);
2097-
let s3 = new_section(40, 10);
2098-
let s4 = new_section(50, 10);
2099-
2100-
let sections: [(Option<&[u8]>, &Elf64Shdr); 4] = [
2101-
(Some(b".dynsym"), &s1),
2102-
(Some(b".text"), &s2),
2103-
(Some(b".rodata"), &s3),
2104-
(Some(b".dynamic"), &s4),
2105-
];
2106-
assert_eq!(
2107-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes,),
2108-
Ok(Section::Borrowed(20, 20..50))
2109-
);
2102+
for (vaddr_base, sbpf_version) in [
2103+
(0, SBPFVersion::V1),
2104+
(ebpf::MM_PROGRAM_START, SBPFVersion::V2),
2105+
] {
2106+
let s1 = new_section(vaddr_base, 10);
2107+
let s2 = new_section(vaddr_base + 20, 10);
2108+
let s3 = new_section(vaddr_base + 40, 10);
2109+
let s4 = new_section(vaddr_base + 50, 10);
2110+
let sections: [(Option<&[u8]>, &Elf64Shdr); 4] = [
2111+
(Some(b".dynsym"), &s1),
2112+
(Some(b".text"), &s2),
2113+
(Some(b".rodata"), &s3),
2114+
(Some(b".dynamic"), &s4),
2115+
];
2116+
assert_eq!(
2117+
ElfExecutable::parse_ro_sections(&config, &sbpf_version, sections, &elf_bytes),
2118+
Ok(Section::Borrowed(20, 20..50))
2119+
);
2120+
}
21102121
}
21112122

21122123
#[test]
21132124
fn test_borrowed_ro_region_no_initial_gap() {
21142125
let config = Config::default();
21152126
let elf_bytes = [0u8; 512];
2127+
for (vaddr_base, sbpf_version) in [
2128+
(0, SBPFVersion::V1),
2129+
(ebpf::MM_PROGRAM_START, SBPFVersion::V2),
2130+
] {
2131+
let s1 = new_section(vaddr_base, 10);
2132+
let s2 = new_section(vaddr_base + 10, 10);
2133+
let s3 = new_section(vaddr_base + 20, 10);
2134+
let sections: [(Option<&[u8]>, &Elf64Shdr); 3] = [
2135+
(Some(b".text"), &s1),
2136+
(Some(b".rodata"), &s2),
2137+
(Some(b".dynamic"), &s3),
2138+
];
2139+
let ro_section =
2140+
ElfExecutable::parse_ro_sections(&config, &sbpf_version, sections, &elf_bytes)
2141+
.unwrap();
2142+
let ro_region = get_ro_region(&ro_section, &elf_bytes);
2143+
2144+
// s1 starts at sh_offset=0 so [0..s2.sh_offset + s2.sh_size]
2145+
// is the valid ro memory area
2146+
assert!(matches!(
2147+
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s1.sh_offset, s2.sh_offset + s2.sh_size),
2148+
ProgramResult::Ok(ptr) if ptr == elf_bytes.as_ptr() as u64,
2149+
));
21162150

2117-
let s1 = new_section(0, 10);
2118-
let s2 = new_section(10, 10);
2119-
let s3 = new_section(10, 10);
2120-
2121-
let sections: [(Option<&[u8]>, &Elf64Shdr); 3] = [
2122-
(Some(b".text"), &s1),
2123-
(Some(b".rodata"), &s2),
2124-
(Some(b".dynamic"), &s3),
2125-
];
2126-
let ro_section =
2127-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes)
2128-
.unwrap();
2129-
let ro_region = get_ro_region(&ro_section, &elf_bytes);
2130-
2131-
// s1 starts at sh_addr=0 so [0..s2.sh_addr + s2.sh_size] is the valid
2132-
// ro memory area
2133-
assert!(matches!(
2134-
ro_region.vm_to_host(ebpf::MM_PROGRAM_START, s2.sh_addr + s2.sh_size),
2135-
ProgramResult::Ok(ptr) if ptr == elf_bytes.as_ptr() as u64,
2136-
));
2137-
2138-
// one byte past the ro section is not mappable
2139-
assert_error!(
2140-
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s2.sh_addr + s2.sh_size, 1),
2141-
"InvalidVirtualAddress({})",
2142-
ebpf::MM_PROGRAM_START + s2.sh_addr + s2.sh_size
2143-
);
2151+
// one byte past the ro section is not mappable
2152+
assert_error!(
2153+
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s3.sh_offset, 1),
2154+
"InvalidVirtualAddress({})",
2155+
ebpf::MM_PROGRAM_START + s3.sh_offset
2156+
);
2157+
}
21442158
}
21452159

21462160
#[test]
21472161
fn test_borrowed_ro_region_initial_gap() {
21482162
let config = Config::default();
21492163
let elf_bytes = [0u8; 512];
2150-
let s1 = new_section(0, 10);
2151-
let s2 = new_section(10, 10);
2152-
let s3 = new_section(20, 10);
2153-
2154-
let sections: [(Option<&[u8]>, &Elf64Shdr); 3] = [
2155-
(Some(b".dynamic"), &s1),
2156-
(Some(b".text"), &s2),
2157-
(Some(b".rodata"), &s3),
2158-
];
2159-
let ro_section =
2160-
ElfExecutable::parse_ro_sections(&config, &SBPFVersion::V2, sections, &elf_bytes)
2161-
.unwrap();
2162-
let ro_region = get_ro_region(&ro_section, &elf_bytes);
2163-
2164-
// s2 starts at sh_addr=10 so [0..10] is not mappable
2165-
2166-
// the low bound of the initial gap is not mappable
2167-
assert_error!(
2168-
ro_region.vm_to_host(ebpf::MM_PROGRAM_START, 1),
2169-
"InvalidVirtualAddress({})",
2170-
ebpf::MM_PROGRAM_START
2171-
);
2172-
2173-
// the hi bound of the initial gap is not mappable
2174-
assert_error!(
2175-
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s2.sh_addr - 1, 1),
2176-
"InvalidVirtualAddress({})",
2177-
ebpf::MM_PROGRAM_START + 9
2178-
);
2179-
2180-
// [s2.sh_addr..s3.sh_addr + s3.sh_size] is the valid ro memory area
2181-
assert!(matches!(
2182-
ro_region.vm_to_host(
2183-
ebpf::MM_PROGRAM_START + s2.sh_addr,
2184-
s3.sh_addr + s3.sh_size - s2.sh_addr
2185-
),
2186-
ProgramResult::Ok(ptr) if ptr == elf_bytes[s2.sh_addr as usize..].as_ptr() as u64,
2187-
));
2164+
for (vaddr_base, sbpf_version) in [
2165+
(0, SBPFVersion::V1),
2166+
(ebpf::MM_PROGRAM_START, SBPFVersion::V2),
2167+
] {
2168+
let s1 = new_section(vaddr_base, 10);
2169+
let s2 = new_section(vaddr_base + 10, 10);
2170+
let s3 = new_section(vaddr_base + 20, 10);
2171+
let sections: [(Option<&[u8]>, &Elf64Shdr); 3] = [
2172+
(Some(b".dynamic"), &s1),
2173+
(Some(b".text"), &s2),
2174+
(Some(b".rodata"), &s3),
2175+
];
2176+
let ro_section =
2177+
ElfExecutable::parse_ro_sections(&config, &sbpf_version, sections, &elf_bytes)
2178+
.unwrap();
2179+
let ro_region = get_ro_region(&ro_section, &elf_bytes);
2180+
2181+
// s2 starts at sh_addr=10 so [0..10] is not mappable
2182+
2183+
// the low bound of the initial gap is not mappable
2184+
assert_error!(
2185+
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s1.sh_offset, 1),
2186+
"InvalidVirtualAddress({})",
2187+
ebpf::MM_PROGRAM_START + s1.sh_offset
2188+
);
2189+
2190+
// the hi bound of the initial gap is not mappable
2191+
assert_error!(
2192+
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s2.sh_offset - 1, 1),
2193+
"InvalidVirtualAddress({})",
2194+
ebpf::MM_PROGRAM_START + s2.sh_offset - 1
2195+
);
2196+
2197+
// [s2.sh_offset..s3.sh_offset + s3.sh_size] is the valid ro memory area
2198+
assert!(matches!(
2199+
ro_region.vm_to_host(
2200+
ebpf::MM_PROGRAM_START + s2.sh_offset,
2201+
s3.sh_offset + s3.sh_size - s2.sh_offset
2202+
),
2203+
ProgramResult::Ok(ptr) if ptr == elf_bytes[s2.sh_offset as usize..].as_ptr() as u64,
2204+
));
21882205

2189-
// one byte past the ro section is not mappable
2190-
assert_error!(
2191-
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s3.sh_addr + s3.sh_size, 1),
2192-
"InvalidVirtualAddress({})",
2193-
ebpf::MM_PROGRAM_START + s3.sh_addr + s3.sh_size
2194-
);
2206+
// one byte past the ro section is not mappable
2207+
assert_error!(
2208+
ro_region.vm_to_host(ebpf::MM_PROGRAM_START + s3.sh_offset + s3.sh_size, 1),
2209+
"InvalidVirtualAddress({})",
2210+
ebpf::MM_PROGRAM_START + s3.sh_offset + s3.sh_size
2211+
);
2212+
}
21952213
}
21962214

21972215
#[test]

tests/elfs/elf.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SECTIONS
1010
. = SIZEOF_HEADERS;
1111
.text : { *(.text) } :text
1212
.rodata : { *(.rodata*) } :rodata
13+
.data.rel.ro : { *(.data.rel.ro) } :rodata
1314
.dynamic : { *(.dynamic) } :dynamic
1415
.dynsym : { *(.dynsym) } :dynamic
1516
.dynstr : { *(.dynstr) } :dynamic

tests/elfs/elfs.sh

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ rm reloc_64_relative.o
5858
rm reloc_64_relative_data.o
5959

6060
"$LLVM_DIR"clang $CC_FLAGS -o reloc_64_relative_data.o -c reloc_64_relative_data.c
61-
"$LLVM_DIR"ld.lld $LD_FLAGS --section-start=.text=0x100000000 -o reloc_64_relative_data.so reloc_64_relative_data.o
62-
rm reloc_64_relative_data.o
63-
64-
"$LLVM_DIR"clang $CC_FLAGS_V1 -o reloc_64_relative_data.o -c reloc_64_relative_data.c
65-
"$LLVM_DIR"ld.lld $LD_FLAGS_V1 -o reloc_64_relative_data_sbpfv1.so reloc_64_relative_data.o
61+
"$LLVM_DIR"ld.lld $LD_FLAGS -o reloc_64_relative_data.so reloc_64_relative_data.o
6662
rm reloc_64_relative_data.o
6763

6864
"$LLVM_DIR"clang $CC_FLAGS -o scratch_registers.o -c scratch_registers.c

tests/elfs/reloc_64_relative_data.so

0 Bytes
Binary file not shown.

tests/elfs/struct_func_pointer.so

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)