Coverage Report

Created: 2025-10-13 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/td-shim/td-loader/src/elf.rs
Line
Count
Source
1
// Copyright (c) 2020 Intel Corporation
2
//
3
// SPDX-License-Identifier: BSD-2-Clause-Patent
4
5
use core::ops::Range;
6
use scroll::Pwrite;
7
8
use crate::elf64;
9
10
const SIZE_4KB: u64 = 0x00001000u64;
11
12
/// Number of bytes in an identifier.
13
pub const SIZEOF_IDENT: usize = 16;
14
15
pub const R_X86_64_RELATIVE: u32 = 8;
16
17
pub const ELFMAG: [u8; 4] = [b'\x7F', b'E', b'L', b'F'];
18
19
2.38k
pub fn is_elf(image: &[u8]) -> bool {
20
2.38k
    image.len() >= 4 && image[0..4] == ELFMAG
21
2.38k
}
22
23
2.31k
pub fn relocate_elf_mem_with_per_program_header(
24
2.31k
    image: &[u8],
25
2.31k
    loaded_buffer: &mut [u8],
26
2.31k
) -> Option<(u64, u64, u64)> {
27
2.31k
    relocate_elf_with_per_program_header(image, loaded_buffer, loaded_buffer.as_ptr() as usize)
28
2.31k
}
29
30
2.31k
pub fn relocate_elf_with_per_program_header(
31
2.31k
    image: &[u8],
32
2.31k
    loaded_buffer: &mut [u8],
33
2.31k
    new_image_base: usize,
34
2.31k
) -> Option<(u64, u64, u64)> {
35
    // parser file and get entry point
36
2.31k
    let elf = crate::elf64::Elf::parse(image)?;
37
38
2.13k
    let mut bottom: u64 = 0xFFFFFFFFu64;
39
2.13k
    let mut top: u64 = 0u64;
40
41
18.6k
    for ph in elf.program_headers()? {
42
18.6k
        if bottom > ph.p_vaddr {
43
1.90k
            bottom = ph.p_vaddr;
44
16.7k
        }
45
18.6k
        if top < ph.p_vaddr.checked_add(ph.p_memsz)? {
46
2.56k
            top = ph.p_vaddr + ph.p_memsz;
47
15.8k
        }
48
    }
49
50
1.96k
    bottom.checked_add(new_image_base as u64)?;
51
1.96k
    top.checked_add(new_image_base as u64)?;
52
1.88k
    let mut bottom = bottom + new_image_base as u64;
53
1.88k
    let mut top = top + new_image_base as u64;
54
1.88k
    bottom = align_value(bottom, SIZE_4KB, true);
55
1.88k
    top = align_value(top, SIZE_4KB, false);
56
    // load per program header
57
5.19k
    for ph in elf.program_headers()? {
58
5.19k
        if ph.p_memsz != 0 {
59
2.20k
            if ph.p_offset.checked_add(ph.p_filesz)? > image.len() as u64
60
1.85k
                || ph.p_vaddr.checked_add(ph.p_filesz)? > loaded_buffer.len() as u64
61
            {
62
609
                return None;
63
1.56k
            }
64
1.56k
            let data_range = ph.p_offset as usize..(ph.p_offset + ph.p_filesz) as usize;
65
1.56k
            let loaded_range = (ph.p_vaddr) as usize..(ph.p_vaddr + ph.p_filesz) as usize;
66
1.56k
            loaded_buffer[loaded_range].copy_from_slice(&image[data_range]);
67
2.99k
        }
68
    }
69
70
    // relocate to base
71
291k
    for reloc in elf.relocations()? {
72
291k
        if reloc.r_type() == R_X86_64_RELATIVE {
73
897
            let r_addend = reloc.r_addend;
74
897
            loaded_buffer
75
896
                .pwrite::<u64>(
76
897
                    new_image_base.checked_add(r_addend as usize)? as u64,
77
896
                    reloc.r_offset as usize,
78
                )
79
896
                .ok()?;
80
290k
        }
81
    }
82
83
    Some((
84
978
        elf.header.e_entry.checked_add(new_image_base as u64)?,
85
916
        bottom,
86
916
        top.checked_sub(bottom)?,
87
    ))
88
2.31k
}
89
90
2.31k
pub fn parse_pre_init_array_section(loaded_image: &[u8]) -> Option<Range<usize>> {
91
2.31k
    elf64::get_init_array(
92
2.31k
        loaded_image,
93
        elf64::DT_PREINIT_ARRAY,
94
        elf64::DT_PREINIT_ARRAYSZ,
95
    )
96
2.31k
}
97
98
/// Parse ELF binary and get the .init_array section, if any
99
2.31k
pub fn parse_init_array_section(loaded_image: &[u8]) -> Option<Range<usize>> {
100
2.31k
    elf64::get_init_array(loaded_image, elf64::DT_INIT_ARRAY, elf64::DT_INIT_ARRAYSZ)
101
2.31k
}
102
103
// Parse ELF binary and get the .finit_array section, if any
104
2.31k
pub fn parse_finit_array_section(loaded_image: &[u8]) -> Option<Range<usize>> {
105
2.31k
    elf64::get_init_array(loaded_image, elf64::DT_FINI_ARRAY, elf64::DT_FINI_ARRAYSZ)
106
2.31k
}
107
108
/// flag true align to low address else high address
109
3.77k
fn align_value(value: u64, align: u64, flag: bool) -> u64 {
110
3.77k
    if flag {
111
1.88k
        value & (!(align - 1))
112
    } else {
113
1.88k
        value - (value & (align - 1)) + align
114
    }
115
3.77k
}
116
117
#[cfg(test)]
118
mod test_elf_loader {
119
    use std::vec;
120
121
    #[test]
122
    fn test_is_elf() {
123
        let image_bytes = include_bytes!("../../data/blobs/td-payload.elf");
124
125
        assert_eq!(super::is_elf(image_bytes), true);
126
    }
127
    #[test]
128
    fn test_relocate() {
129
        let image_bytes = &include_bytes!("../../data/blobs/td-payload.elf")[..];
130
131
        let mut loaded_buffer = vec![0u8; 0x800000];
132
        let new_image_base = loaded_buffer.as_ptr() as usize;
133
134
        super::relocate_elf_with_per_program_header(
135
            image_bytes,
136
            loaded_buffer.as_mut_slice(),
137
            new_image_base,
138
        )
139
        .unwrap();
140
    }
141
    #[test]
142
    fn test_relocate_mem() {
143
        let image_bytes = &include_bytes!("../../data/blobs/td-payload.elf")[..];
144
145
        let mut loaded_buffer = vec![0u8; 0x800000];
146
147
        super::relocate_elf_mem_with_per_program_header(image_bytes, loaded_buffer.as_mut_slice())
148
            .unwrap();
149
    }
150
}