Skip to content

Commit 1631e27

Browse files
authored
Fix encryption when using clang, and with allocatable heap (#243)
* Fix encryption when using clang, and with allocatable heap * Test build examples with clang too * Delete empty PH segments when moving These segments are not necessary, and will likely be moved to invalid memory addresses
1 parent dcbeb00 commit 1631e27

File tree

5 files changed

+68
-3
lines changed

5 files changed

+68
-3
lines changed

.github/workflows/test.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,22 @@ jobs:
7676
# Prevent running twice for PRs from same repo
7777
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
7878
name: Test Build Examples
79+
strategy:
80+
fail-fast: false
81+
matrix:
82+
compiler: ["gcc", "clang"]
7983
runs-on: ubuntu-latest
8084
steps:
8185
- name: Checkout
8286
uses: actions/checkout@v4
8387
- name: Install dependencies
84-
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
88+
run: sudo apt install cmake ninja-build python3 build-essential libusb-1.0-0-dev
89+
- name: Install GCC
90+
if: matrix.compiler == 'gcc'
91+
run: sudo apt install gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
92+
- name: Install Clang
93+
if: matrix.compiler == 'clang'
94+
uses: stellar-aria/llvm-embedded-toolchain-for-arm-action@latest
8595
- name: Checkout Pico SDK
8696
uses: actions/checkout@v4
8797
with:
@@ -102,5 +112,5 @@ jobs:
102112
path: pico-examples
103113
- name: Build Pico Examples
104114
run: |
105-
cmake -S pico-examples -B build-examples -G "Ninja" -D PICO_SDK_PATH="${{ github.workspace }}/pico-sdk" -D PICO_BOARD=pico2_w
115+
cmake -S pico-examples -B build-examples -G "Ninja" -D PICO_SDK_PATH="${{ github.workspace }}/pico-sdk" -D PICO_BOARD=pico2_w ${{ matrix.compiler == 'clang' && '-D PICO_COMPILER=pico_arm_clang' || '' }}
106116
cmake --build build-examples

bintool/bintool.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ block place_new_block(elf_file *elf, std::unique_ptr<block> &first_block, bool s
263263
// std::cout << &seg << " " << to_string(seg) << std::endl;
264264
const uint32_t paddr = seg.physical_address();
265265
const uint32_t psize = seg.physical_size();
266+
if (psize == 0) continue;
266267
if (paddr >= 0x20000000 && paddr < 0x20080000) {
267268
highest_ram_address = std::max(paddr + psize, highest_ram_address);
268269
} else if (paddr >= 0x10000000 && paddr < 0x20000000) {
@@ -406,6 +407,9 @@ std::vector<std::unique_ptr<block>> get_all_blocks(std::vector<uint8_t> &bin, ui
406407
next_item += size;
407408
}
408409
}
410+
if (new_first_block == nullptr) {
411+
fail(ERROR_UNKNOWN, "Block loop is not valid - incomplete block found at %08x\n", (int)(next_block_addr));
412+
}
409413
if (new_first_block->physical_addr + new_first_block->next_block_rel == first_block->physical_addr) {
410414
DEBUG_LOG("Found last block in block loop\n");
411415
all_blocks.push_back(std::move(new_first_block));

elf/elf_file.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,33 @@ void elf_file::read_sh(void) {
251251
}
252252
}
253253

254-
// If there are holes between sections within segments, increase the section size to plug the hole
254+
// If there are holes between segments, increase the segment size to plug the hole
255+
// This is necessary to ensure that segments are contiguous, which is required for encrypting,
256+
// but this is not necessary for signing/hashing
257+
void elf_file::remove_ph_holes(void) {
258+
for (int i=0; i+1 < ph_entries.size(); i++) {
259+
auto ph0 = &(ph_entries[i]);
260+
elf32_ph_entry ph1 = ph_entries[i+1];
261+
if (
262+
(ph0->type == PT_LOAD && ph1.type == PT_LOAD)
263+
&& (ph0->filez && ph1.filez)
264+
&& (ph0->paddr + ph0->filez < ph1.paddr)
265+
) {
266+
uint32_t gap = ph1.paddr - ph0->paddr - ph0->filez;
267+
if (gap > ph1.align) {
268+
fail(ERROR_INCOMPATIBLE, "Segment %d: Cannot plug gap greater than alignment - gap %d, alignment %d", i, gap, ph1.align);
269+
}
270+
if (ph0->offset + ph0->filez + gap > ph1.offset) {
271+
fail(ERROR_INCOMPATIBLE, "Segment %d: Cannot plug gap without space in file - gap %d", i, gap);
272+
}
273+
if (verbose) printf("Segment %d: Moving end from 0x%08x to 0x%08x to plug gap\n", i, ph0->paddr + ph0->filez, ph1.paddr);
274+
ph0->filez = ph1.paddr - ph0->paddr;
275+
ph0->memsz = ph0->filez;
276+
}
277+
}
278+
}
279+
280+
// If there are holes within segments, increase the section size to plug the hole
255281
// This is necessary to ensure the whole segment contains data defined in sections, otherwise you end up
256282
// signing/hashing/encrypting data that may not be written, as many tools write in sections not segments
257283
void elf_file::remove_sh_holes(void) {
@@ -273,11 +299,31 @@ void elf_file::remove_sh_holes(void) {
273299
if (verbose) printf("Section %d: Moving end from 0x%08x to 0x%08x to plug gap\n", i, sh0->addr + sh0->size, sh1.addr);
274300
sh0->size = sh1.addr - sh0->addr;
275301
found_hole = true;
302+
} else if (
303+
(sh0->type == SHT_PROGBITS)
304+
&& (segment_from_section(*sh0) != segment_from_section(sh1))
305+
&& segment_from_section(*sh0) != NULL
306+
&& (sh0->offset + sh0->size < segment_from_section(*sh0)->offset + segment_from_section(*sh0)->filez)
307+
) {
308+
const elf32_ph_entry *seg = segment_from_section(*sh0);
309+
uint32_t gap = seg->offset + seg->filez - sh0->offset - sh0->size;
310+
if (verbose) printf("Section %d: Moving end from 0x%08x to 0x%08x to plug gap at end of segment\n", i, sh0->addr + sh0->size, seg->offset + seg->filez);
311+
sh0->size = seg->offset + seg->filez - sh0->offset;
312+
found_hole = true;
276313
}
277314
}
278315
if (found_hole) read_sh_data();
279316
}
280317

318+
void elf_file::remove_empty_ph_entries(void) {
319+
for (int i = 0; i < ph_entries.size(); i++) {
320+
if (ph_entries[i].filez == 0) {
321+
ph_entries.erase(ph_entries.begin() + i);
322+
eh.ph_num--; i--;
323+
}
324+
}
325+
}
326+
281327
// Read the section data from the internal byte array into discrete sections.
282328
// This is used after modifying segments but before inserting new segments
283329
void elf_file::read_sh_data(void) {
@@ -373,6 +419,8 @@ void elf_file::dump(void) const {
373419

374420
void elf_file::move_all(int dist) {
375421
if (verbose) printf("Incrementing all paddr by %d\n", dist);
422+
// Remove empty ph entries, as they will likely be moved to invalid addresses
423+
remove_empty_ph_entries();
376424
for (auto &ph: ph_entries) {
377425
ph.paddr += dist;
378426
}

elf/elf_file.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class elf_file {
4747
void dump(void) const;
4848

4949
void move_all(int dist);
50+
void remove_ph_holes(void);
5051
void remove_sh_holes(void);
52+
void remove_empty_ph_entries(void);
5153

5254
static std::vector<uint8_t> read_binfile(std::shared_ptr<std::iostream> file);
5355

main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5218,6 +5218,7 @@ bool encrypt_command::execute(device_map &devices) {
52185218
elf_file *elf = &source_file;
52195219
elf->read_file(get_file(ios::in|ios::binary));
52205220
// Remove any holes in the ELF file, as these cause issues when encrypting
5221+
elf->remove_ph_holes();
52215222
elf->remove_sh_holes();
52225223

52235224
std::unique_ptr<block> first_block = find_first_block(elf);

0 commit comments

Comments
 (0)