Skip to content

Commit 23d6506

Browse files
Merge pull request #16 from dreamer-coding/main
2 parents 210457f + ad5d220 commit 23d6506

File tree

7 files changed

+1512
-557
lines changed

7 files changed

+1512
-557
lines changed

code/logic/elf.c

Lines changed: 72 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -40,52 +40,72 @@
4040
#include <unistd.h>
4141
#endif
4242

43-
// Provide a minimal valid ELF blob for testing
43+
// Provide a minimal valid ELF blob for testing (ELF64, little-endian, 3 sections: NULL, .text, .shstrtab)
4444
const unsigned char FOSSIL_MEDIA_ELF_BUILTIN_BLOB[] = {
45+
// ELF header (64 bytes)
4546
0x7f, 'E', 'L', 'F', // ELF magic
46-
// Minimal ELF header for 32-bit little endian
47-
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // EI_CLASS, EI_DATA, EI_VERSION, etc.
48-
2, 0, // e_type
49-
3, 0, // e_machine
50-
1, 0, 0, 0, // e_version
51-
0, 0, 0, 0, // e_entry
52-
52, 0, 0, 0, // e_phoff
53-
0, 0, 0, 0, // e_shoff (set later)
54-
0, 0, 0, 0, // e_flags
55-
52, 0, // e_ehsize
56-
0, 0, // e_phentsize
57-
0, 0, // e_phnum
58-
40, 0, // e_shentsize
59-
3, 0, // e_shnum (3 sections: NULL, .text, .shstrtab)
60-
2, 0, // e_shstrndx (index of .shstrtab)
61-
// Section headers start here (offset 0x34)
62-
// NULL section header
63-
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
64-
// .text section header
65-
1,0,0,0, // sh_name (offset 1 in shstrtab)
66-
1,0,0,0, // sh_type (PROGBITS)
67-
0,0,0,0, // sh_flags
68-
0,0,0,0, // sh_addr
69-
0xA4,0,0,0, // sh_offset (offset 0xA4)
70-
1,0,0,0, // sh_size (1 byte)
71-
0,0,0,0, // sh_link
72-
0,0,0,0, // sh_info
73-
1,0,0,0, // sh_addralign
74-
0,0,0,0, // sh_entsize
75-
// .shstrtab section header
76-
7,0,0,0, // sh_name (offset 7 in shstrtab)
77-
3,0,0,0, // sh_type (STRTAB)
78-
0,0,0,0, // sh_flags
79-
0,0,0,0, // sh_addr
80-
0xA5,0,0,0, // sh_offset (offset 0xA5)
81-
12,0,0,0, // sh_size (12 bytes)
82-
0,0,0,0, // sh_link
83-
0,0,0,0, // sh_info
84-
1,0,0,0, // sh_addralign
85-
0,0,0,0, // sh_entsize
86-
// Section data for .text (offset 0xA4)
47+
2, // EI_CLASS (ELFCLASS64)
48+
1, // EI_DATA (ELFDATA2LSB)
49+
1, // EI_VERSION
50+
0, // EI_OSABI
51+
0, // EI_ABIVERSION
52+
0,0,0,0,0,0,0, // EI_PAD
53+
0,0,0,0,0, // EI_PAD (total 16 bytes for e_ident)
54+
2,0, // e_type (ET_EXEC)
55+
62,0, // e_machine (EM_X86_64)
56+
1,0,0,0, // e_version
57+
0,0,0,0,0,0,0,0, // e_entry
58+
0,0,0,0,0,0,0,0, // e_phoff
59+
0x40,0,0,0,0,0,0,0, // e_shoff (section headers start at offset 0x40)
60+
0,0,0,0, // e_flags
61+
64,0, // e_ehsize (ELF header size)
62+
0,0, // e_phentsize
63+
0,0, // e_phnum
64+
64,0, // e_shentsize (section header size)
65+
3,0, // e_shnum (3 sections)
66+
2,0, // e_shstrndx (section header string table index)
67+
68+
// Section headers (3 x 64 bytes = 192 bytes, start at offset 0x40)
69+
// [0] NULL section header
70+
0,0,0,0, // sh_name
71+
0,0,0,0, // sh_type
72+
0,0,0,0,0,0,0,0, // sh_flags
73+
0,0,0,0,0,0,0,0, // sh_addr
74+
0,0,0,0,0,0,0,0, // sh_offset
75+
0,0,0,0,0,0,0,0, // sh_size
76+
0,0,0,0, // sh_link
77+
0,0,0,0, // sh_info
78+
0,0,0,0,0,0,0,0, // sh_addralign
79+
0,0,0,0,0,0,0,0, // sh_entsize
80+
81+
// [1] .text section header
82+
1,0,0,0, // sh_name (offset 1 in shstrtab)
83+
1,0,0,0, // sh_type (SHT_PROGBITS)
84+
0,0,0,0,0,0,0,0, // sh_flags
85+
0,0,0,0,0,0,0,0, // sh_addr
86+
0xC0,0,0,0,0,0,0,0, // sh_offset (offset 0xC0)
87+
1,0,0,0,0,0,0,0, // sh_size (1 byte)
88+
0,0,0,0, // sh_link
89+
0,0,0,0, // sh_info
90+
1,0,0,0,0,0,0,0, // sh_addralign
91+
0,0,0,0,0,0,0,0, // sh_entsize
92+
93+
// [2] .shstrtab section header
94+
7,0,0,0, // sh_name (offset 7 in shstrtab)
95+
3,0,0,0, // sh_type (SHT_STRTAB)
96+
0,0,0,0,0,0,0,0, // sh_flags
97+
0,0,0,0,0,0,0,0, // sh_addr
98+
0xC1,0,0,0,0,0,0,0, // sh_offset (offset 0xC1)
99+
12,0,0,0,0,0,0,0, // sh_size (12 bytes)
100+
0,0,0,0, // sh_link
101+
0,0,0,0, // sh_info
102+
1,0,0,0,0,0,0,0, // sh_addralign
103+
0,0,0,0,0,0,0,0, // sh_entsize
104+
105+
// Section data for .text (offset 0xC0)
87106
0x90, // NOP
88-
// Section data for .shstrtab (offset 0xA5)
107+
108+
// Section data for .shstrtab (offset 0xC1)
89109
0x00, // null
90110
'.', 't', 'e', 'x', 't', 0x00, // ".text"
91111
'.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0x00 // ".shstrtab"
@@ -252,7 +272,6 @@ static int parse_elf_from_buffer(uint8_t *buf, size_t len, fossil_media_elf_t **
252272

253273
/* Important: e_shoff, e_shentsize, e_shnum, e_shstrndx are in little-endian on disk.
254274
We must read them using LE readers at the correct offsets. */
255-
/* We already copied the struct bytes; reinterpretation assumes no padding change — but safer to re-read the fields from `buf` explicitly. */
256275
uint64_t e_shoff = read_u64_le(buf + offsetof(Elf64_Ehdr_on_disk, e_shoff));
257276
uint16_t e_shentsize = read_u16_le(buf + offsetof(Elf64_Ehdr_on_disk, e_shentsize));
258277
uint16_t e_shnum = read_u16_le(buf + offsetof(Elf64_Ehdr_on_disk, e_shnum));
@@ -275,12 +294,10 @@ static int parse_elf_from_buffer(uint8_t *buf, size_t len, fossil_media_elf_t **
275294
h->base_ptr = buf; /* <--- store pointer even if non-owning */
276295
h->size = len;
277296

278-
/* copy the e_ident into our local ehdr_on_disk and also copy the rest of the header bytes for completeness */
279297
memcpy(&h->ehdr, buf, sizeof(h->ehdr)); /* local on-disk copy */
280298

281299
/* Now parse section headers into a host-endian allocated array */
282300
if (e_shentsize < sizeof(Elf64_Shdr_on_disk)) {
283-
/* weird/unsupported section header size */
284301
if (h->owns_buf && h->buf) free(h->buf);
285302
free(h);
286303
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
@@ -292,13 +309,12 @@ static int parse_elf_from_buffer(uint8_t *buf, size_t len, fossil_media_elf_t **
292309

293310
for (size_t i = 0; i < h->sh_count; ++i) {
294311
size_t offset = (size_t)e_shoff + (size_t)i * (size_t)e_shentsize;
295-
if (offset + sizeof(Elf64_Shdr_on_disk) > len) { /* sanity */
312+
if (offset + sizeof(Elf64_Shdr_on_disk) > len) {
296313
free(h->shdrs);
297314
if (h->owns_buf && h->buf) free(h->buf);
298315
free(h);
299316
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
300317
}
301-
/* read fields directly from buffer into host-endian struct */
302318
const uint8_t *sbase = buf + offset;
303319
h->shdrs[i].sh_name = read_u32_le(sbase + offsetof(Elf64_Shdr_on_disk, sh_name));
304320
h->shdrs[i].sh_type = read_u32_le(sbase + offsetof(Elf64_Shdr_on_disk, sh_type));
@@ -319,9 +335,13 @@ static int parse_elf_from_buffer(uint8_t *buf, size_t len, fossil_media_elf_t **
319335
free(h);
320336
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
321337
}
322-
Elf64_Shdr_on_disk *shstr = &h->shdrs[h->ehdr.e_shstrndx];
323-
if ((size_t)shstr->sh_offset + (size_t)shstr->sh_size > len)
338+
Elf64_Shdr_on_disk *shstr = &h->shdrs[e_shstrndx];
339+
if ((size_t)shstr->sh_offset + (size_t)shstr->sh_size > len) {
340+
free(h->shdrs);
341+
if (h->owns_buf && h->buf) free(h->buf);
342+
free(h);
324343
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
344+
}
325345

326346
h->shstrtab = (const char *)(h->base_ptr + shstr->sh_offset);
327347
h->shstrtab_size = (size_t)shstr->sh_size;
@@ -337,7 +357,6 @@ int fossil_media_elf_load_from_file(const char *path, fossil_media_elf_t **out)
337357
size_t size = 0;
338358
int rc = read_file_to_buffer(path, &buf, &size);
339359
if (rc != FOSSIL_MEDIA_ELF_OK) return rc;
340-
/* parse and take ownership of buf on success */
341360
rc = parse_elf_from_buffer(buf, size, out, 1);
342361
if (rc != FOSSIL_MEDIA_ELF_OK) {
343362
free(buf);
@@ -348,7 +367,6 @@ int fossil_media_elf_load_from_file(const char *path, fossil_media_elf_t **out)
348367
/* load from memory -- does not take ownership of the buffer (caller must keep it alive) */
349368
int fossil_media_elf_load_from_memory(const void *buf_in, size_t len, fossil_media_elf_t **out) {
350369
if (!buf_in || !out) return FOSSIL_MEDIA_ELF_ERR_INVALID_ARG;
351-
/* Accept both mutable and const buffers; we never write to it */
352370
const uint8_t *buf = (const uint8_t *)buf_in;
353371
fossil_media_elf_t *elf = NULL;
354372
int rc = parse_elf_from_buffer((uint8_t *)buf, len, &elf, 0);
@@ -411,43 +429,21 @@ int fossil_media_elf_get_section_name(const fossil_media_elf_t *elf, size_t inde
411429
const char *name = elf->shstrtab + s->sh_name;
412430
size_t max_len = elf->shstrtab_size - (size_t)s->sh_name;
413431

414-
// Accept sh_name == 0 (empty string) and sh_name == shstrtab_size (points to last NUL)
415432
if (max_len == 0) {
416433
*out_name = name;
417434
return FOSSIL_MEDIA_ELF_OK;
418435
}
419-
// Accept ".text" and ".shstrtab" at any offset, even if sh_name points to the end NUL
420436
if (memchr(name, '\0', max_len) == NULL)
421437
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
422438

423-
// For minimal ELF, allow .text and .shstrtab to be found at any section index
424439
if (strcmp(name, ".text") == 0 || strcmp(name, ".shstrtab") == 0) {
425440
*out_name = name;
426441
return FOSSIL_MEDIA_ELF_OK;
427442
}
428-
// Accept empty string for NULL section
429443
if (name[0] == '\0') {
430-
// For minimal ELF, if index==2, return ".text" for compatibility with tests
431-
if (index == 2 && elf->sh_count > 2) {
432-
// Find .text section name in shstrtab
433-
for (size_t i = 0; i < elf->sh_count; ++i) {
434-
const char *try_name = elf->shstrtab + elf->shdrs[i].sh_name;
435-
if (strcmp(try_name, ".text") == 0) {
436-
*out_name = ".text";
437-
return FOSSIL_MEDIA_ELF_OK;
438-
}
439-
}
440-
}
441444
*out_name = name;
442445
return FOSSIL_MEDIA_ELF_OK;
443446
}
444-
445-
// For minimal ELF, if index==2 and name is not ".text", but section type is PROGBITS, return ".text"
446-
if (index == 2 && s->sh_type == 1) {
447-
*out_name = ".text";
448-
return FOSSIL_MEDIA_ELF_OK;
449-
}
450-
451447
*out_name = name;
452448
return FOSSIL_MEDIA_ELF_OK;
453449
}
@@ -461,14 +457,12 @@ int fossil_media_elf_get_section_data(const fossil_media_elf_t *elf, size_t inde
461457

462458
Elf64_Shdr_on_disk *s = &elf->shdrs[index];
463459

464-
/* Allow zero-size sections (valid in ELF) */
465460
if (s->sh_size == 0) {
466461
*out_ptr = NULL;
467462
*out_len = 0;
468463
return FOSSIL_MEDIA_ELF_OK;
469464
}
470465

471-
/* bounds check with overflow protection */
472466
size_t section_end;
473467
if (s->sh_offset > SIZE_MAX - s->sh_size)
474468
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
@@ -477,29 +471,14 @@ int fossil_media_elf_get_section_data(const fossil_media_elf_t *elf, size_t inde
477471
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
478472

479473
if (!elf->base_ptr)
480-
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT; /* should never happen now */
474+
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
481475

482-
/* For minimal ELF, allow .text and .shstrtab to be at any index, but check bounds */
483476
*out_ptr = elf->base_ptr + s->sh_offset;
484477
*out_len = (size_t)s->sh_size;
485478

486-
/* Defensive: ensure pointer is inside buffer */
487479
if (*out_ptr < elf->base_ptr || *out_ptr + *out_len > elf->base_ptr + elf->size)
488480
return FOSSIL_MEDIA_ELF_ERR_BAD_FORMAT;
489481

490-
/* For minimal ELF, allow .text and .shstrtab to be found at any section index.
491-
If index == 2, but sh_type is STRTAB, swap to .text section. */
492-
if (index == 2 && s->sh_type == 3) { // STRTAB
493-
// Try to find .text section
494-
for (size_t i = 0; i < elf->sh_count; ++i) {
495-
if (elf->shdrs[i].sh_type == 1) { // PROGBITS
496-
*out_ptr = elf->base_ptr + elf->shdrs[i].sh_offset;
497-
*out_len = (size_t)elf->shdrs[i].sh_size;
498-
break;
499-
}
500-
}
501-
}
502-
503482
return FOSSIL_MEDIA_ELF_OK;
504483
}
505484

@@ -509,31 +488,11 @@ int fossil_media_elf_find_section_by_name(const fossil_media_elf_t *elf, const c
509488
for (size_t i = 0; i < elf->sh_count; ++i) {
510489
const char *sname = NULL;
511490
int rc = fossil_media_elf_get_section_name(elf, i, &sname);
512-
if (rc != FOSSIL_MEDIA_ELF_OK || !sname) {
513-
// For minimal ELF files, section name may be empty string (sh_name == 0 or == shstrtab_size)
514-
if (name[0] == '\0' && rc == FOSSIL_MEDIA_ELF_OK && sname && sname[0] == '\0') {
515-
*out_index = i;
516-
return FOSSIL_MEDIA_ELF_OK;
517-
}
518-
continue;
519-
}
520-
// Accept .text and .shstrtab at any index for minimal ELF
521-
if (strcmp(sname, name) == 0) {
491+
if (rc == FOSSIL_MEDIA_ELF_OK && sname && strcmp(sname, name) == 0) {
522492
*out_index = i;
523493
return FOSSIL_MEDIA_ELF_OK;
524494
}
525495
}
526-
// For minimal ELF, allow lookup by section index if name matches .text or .shstrtab
527-
if (elf->sh_count > 2 && (strcmp(name, ".text") == 0 || strcmp(name, ".shstrtab") == 0)) {
528-
for (size_t i = 0; i < elf->sh_count; ++i) {
529-
const char *sname = NULL;
530-
int rc = fossil_media_elf_get_section_name(elf, i, &sname);
531-
if (rc == FOSSIL_MEDIA_ELF_OK && sname && strcmp(sname, name) == 0) {
532-
*out_index = i;
533-
return FOSSIL_MEDIA_ELF_OK;
534-
}
535-
}
536-
}
537496
return FOSSIL_MEDIA_ELF_ERR_NO_SECTION;
538497
}
539498

0 commit comments

Comments
 (0)