Skip to content

Commit c291aeb

Browse files
authored
Fix plugging alignment holes for encrypted binaries (#227)
Use new `segment_from_section` function, as virtual addresses are not unique per segment in encrypted binaries Fixes #224
1 parent 6039f63 commit c291aeb

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

.github/workflows/test.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,33 @@ jobs:
7171
picotool info -a blink.uf2
7272
picotool info -a hello_world.uf2
7373
picotool info -a flash_nuke.uf2
74+
75+
test-examples:
76+
runs-on: ubuntu-latest
77+
steps:
78+
- name: Checkout
79+
uses: actions/checkout@v4
80+
- name: Install dependencies
81+
run: sudo apt install cmake ninja-build python3 build-essential gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib libusb-1.0-0-dev
82+
- name: Checkout Pico SDK
83+
uses: actions/checkout@v4
84+
with:
85+
repository: raspberrypi/pico-sdk
86+
ref: develop
87+
path: pico-sdk
88+
submodules: 'recursive'
89+
- name: Build and Install
90+
run: |
91+
cmake -S . -B build -G "Ninja" -D PICO_SDK_PATH="${{ github.workspace }}/pico-sdk"
92+
cmake --build build
93+
sudo cmake --install build
94+
- name: Checkout Pico Examples
95+
uses: actions/checkout@v4
96+
with:
97+
repository: raspberrypi/pico-examples
98+
ref: develop
99+
path: pico-examples
100+
- name: Build Pico Examples
101+
run: |
102+
cmake -S pico-examples -B build-examples -G "Ninja" -D PICO_SDK_PATH="${{ github.workspace }}/pico-sdk" -D PICO_BOARD=pico2_w
103+
cmake --build build-examples

elf/elf_file.cpp

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,24 +255,27 @@ void elf_file::read_sh(void) {
255255
// This is necessary to ensure the whole segment contains data defined in sections, otherwise you end up
256256
// signing/hashing/encrypting data that may not be written, as many tools write in sections not segments
257257
void elf_file::remove_sh_holes(void) {
258+
bool found_hole = false;
258259
for (int i=0; i+1 < sh_entries.size(); i++) {
259260
auto sh0 = &(sh_entries[i]);
260261
elf32_sh_entry sh1 = sh_entries[i+1];
261262
if (
262263
(sh0->type == SHT_PROGBITS && sh1.type == SHT_PROGBITS)
263264
&& (sh0->size && sh1.size)
264265
&& (sh0->addr + sh0->size < sh1.addr)
265-
&& (segment_from_virtual_address(sh0->addr) == segment_from_virtual_address(sh1.addr))
266-
&& segment_from_virtual_address(sh0->addr) != NULL
266+
&& (segment_from_section(*sh0) == segment_from_section(sh1))
267+
&& segment_from_section(*sh0) != NULL
267268
) {
268269
uint32_t gap = sh1.addr - sh0->addr - sh0->size;
269270
if (gap > sh1.addralign) {
270-
fail(ERROR_INCOMPATIBLE, "Cannot plug gap greater than alignment - gap %d, alignment %d", gap, sh1.addralign);
271+
fail(ERROR_INCOMPATIBLE, "Section %d: Cannot plug gap greater than alignment - gap %d, alignment %d", i, gap, sh1.addralign);
271272
}
272273
if (verbose) printf("Section %d: Moving end from 0x%08x to 0x%08x to plug gap\n", i, sh0->addr + sh0->size, sh1.addr);
273274
sh0->size = sh1.addr - sh0->addr;
275+
found_hole = true;
274276
}
275277
}
278+
if (found_hole) read_sh_data();
276279
}
277280

278281
// Read the section data from the internal byte array into discrete sections.
@@ -290,7 +293,7 @@ void elf_file::read_sh_data(void) {
290293
}
291294

292295
const std::string elf_file::section_name(uint32_t sh_name) const {
293-
if (!eh.sh_str_index || eh.sh_str_index > eh.sh_num)
296+
if (!eh.sh_str_index || eh.sh_str_index > eh.sh_num || eh.sh_str_index >= sh_data.size())
294297
return "";
295298

296299
if (sh_name > sh_data[eh.sh_str_index].size())
@@ -394,9 +397,6 @@ int elf_file::read_file(std::shared_ptr<std::iostream> file) {
394397
if (!rc) {
395398
read_ph();
396399
read_sh();
397-
398-
// Remove any holes in the ELF file, as these cause issues when signing/hashing/encrypting
399-
remove_sh_holes();
400400
}
401401
read_sh_data();
402402
}
@@ -475,6 +475,16 @@ const elf32_ph_entry* elf_file::segment_from_virtual_address(uint32_t vaddr) {
475475
return NULL;
476476
}
477477

478+
const elf32_ph_entry* elf_file::segment_from_section(const elf32_sh_entry &sh) {
479+
for (int i = 0; i < eh.ph_num; i++) {
480+
if (sh.offset >= ph_entries[i].offset && sh.offset < ph_entries[i].offset + ph_entries[i].filez) {
481+
if (verbose) printf("segment %d contains section %s\n", i, section_name(sh.name).c_str());
482+
return &ph_entries[i];
483+
}
484+
}
485+
return nullptr;
486+
}
487+
478488
// Appends a new segment and section - filled with zeros
479489
// Use content to replace the content
480490
const elf32_ph_entry& elf_file::append_segment(uint32_t vaddr, uint32_t paddr, uint32_t size, const std::string &name) {

elf/elf_file.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ class elf_file {
4343
const std::string section_name(uint32_t sh_name) const;
4444
const elf32_ph_entry* segment_from_physical_address(uint32_t paddr);
4545
const elf32_ph_entry* segment_from_virtual_address(uint32_t vaddr);
46+
const elf32_ph_entry* segment_from_section(const elf32_sh_entry &sh);
4647
void dump(void) const;
4748

4849
void move_all(int dist);
50+
void remove_sh_holes(void);
4951

5052
static std::vector<uint8_t> read_binfile(std::shared_ptr<std::iostream> file);
5153

@@ -54,7 +56,6 @@ class elf_file {
5456
int read_header(void);
5557
void read_ph(void);
5658
void read_sh(void);
57-
void remove_sh_holes(void);
5859
void read_sh_data(void);
5960
void read_bytes(unsigned offset, unsigned length, void *dest);
6061
uint32_t append_section_name(const std::string &sh_name_str);

main.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4827,6 +4827,8 @@ bool encrypt_command::execute(device_map &devices) {
48274827
elf_file source_file(settings.verbose);
48284828
elf_file *elf = &source_file;
48294829
elf->read_file(get_file(ios::in|ios::binary));
4830+
// Remove any holes in the ELF file, as these cause issues when encrypting
4831+
elf->remove_sh_holes();
48304832

48314833
std::unique_ptr<block> first_block = find_first_block(elf);
48324834
if (!first_block) {
@@ -5063,6 +5065,8 @@ bool seal_command::execute(device_map &devices) {
50635065
elf_file source_file(settings.verbose);
50645066
elf_file *elf = &source_file;
50655067
elf->read_file(get_file(ios::in|ios::binary));
5068+
// Remove any holes in the ELF file, as these cause issues when signing/hashing
5069+
elf->remove_sh_holes();
50665070
sign_guts_elf(elf, private_key, public_key);
50675071

50685072
auto out = get_file_idx(ios::out|ios::binary, 1);

0 commit comments

Comments
 (0)