Skip to content

Commit 63ca5ba

Browse files
Harden BusyBox usermode startup diagnostics
1 parent 179e9ae commit 63ca5ba

12 files changed

Lines changed: 764 additions & 56 deletions

File tree

source/includes/executables/elf.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,15 @@ typedef struct {
163163
int64_t r_addend; // Addend
164164
} Elf64_Rela;
165165

166+
typedef struct {
167+
uint64_t entry;
168+
uint64_t phdr_addr;
169+
uint16_t phentsize;
170+
uint16_t phnum;
171+
} elf_image_info_t;
172+
166173
void* elf_load_from_memory(void* file_base_address, uint64_t file_size);
167174
void* elf_load_from_vfs(const char* path);
175+
void* elf_load_from_memory_ex(void* file_base_address, uint64_t file_size, elf_image_info_t* info);
176+
void* elf_load_from_vfs_ex(const char* path, elf_image_info_t* info);
168177
#endif

source/includes/filesystems/fat32.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ typedef struct {
140140
uint8_t is_dir;
141141
} fat32_file_t;
142142

143+
uint32_t fat32_read_fat(fat32_fs_t* fs, uint32_t cluster);
143144
int fat32_find_path(fat32_fs_t* fs, const char* path, fat32_dir_entry_t* out);
144145
void fat32_list_root(fat32_fs_t* fs);
145146
void fat32_list_dir_cluster(fat32_fs_t* fs, uint32_t cluster);

source/includes/paging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ void paging_set_hhdm_offset(uint64_t offset);
4646
uintptr_t allocate_page(void);
4747
uintptr_t allocate_pages(size_t count);
4848
uint64_t virtual_to_physical(uint64_t virt);
49-
49+
uint64_t fast_virt_to_phys(void* v);
5050
uint64_t virt_to_phys(void* v);
5151

5252
#endif

source/includes/userland.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@
2121
#define USER_CODE_VADDR 0x0000400000000000ULL // canonical user space, isolated PML4 slot
2222
#define USER_HEAP_VADDR 0x0000400010000000ULL // user heap right above code region
2323
#define USER_MMAP_VADDR (USER_HEAP_VADDR + USER_HEAP_SIZE)
24+
#define USER_TLS_VADDR (USER_MMAP_VADDR + USER_MMAP_SIZE)
25+
#define USER_PHDR_VADDR (USER_TLS_VADDR + 0x1000ULL)
2426
#define USER_STACK_TOP 0x00007FFFFFFFF000ULL // near top of canonical lower half
2527

2628
void enter_userland_at(uint64_t entry_point);
29+
int userland_exec(const char* path, int argc, const char* const* argv, const char* const* envp);
2730
void userland_heap_init(void);
2831
uint64_t userland_brk(uint64_t requested_break);
2932
uint64_t userland_mmap_anon(uint64_t length);

source/kernel/C/executables/elf.c

Lines changed: 259 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,121 @@
1515
#include <heap.h>
1616
#include <filesystems/vfs.h>
1717
#include <paging.h>
18+
#include <userland.h>
19+
20+
static uint32_t* elf_vfs_pos_ptr(vfs_file_t* file)
21+
{
22+
if (!file || !file->mnt)
23+
return NULL;
24+
25+
switch (file->mnt->type) {
26+
case FS_FAT16:
27+
return &file->f.fat16.pos;
28+
case FS_FAT32:
29+
return &file->f.fat32.pos;
30+
case FS_ISO9660:
31+
return &file->f.iso9660.pos;
32+
default:
33+
return NULL;
34+
}
35+
}
36+
37+
static int elf_vfs_seek(vfs_file_t* file, uint32_t offset)
38+
{
39+
uint32_t* pos = elf_vfs_pos_ptr(file);
40+
if (!pos)
41+
return -1;
42+
43+
if (file->mnt->type == FS_FAT32) {
44+
fat32_file_t* fat32 = &file->f.fat32;
45+
uint32_t cluster_size = fat32->fs->sectors_per_cluster * FAT32_SECTOR_SIZE;
46+
uint32_t cluster = fat32->start_cluster;
47+
uint32_t steps = cluster_size ? (offset / cluster_size) : 0;
48+
49+
while (steps > 0 && cluster < FAT32_CLUSTER_EOC) {
50+
cluster = fat32_read_fat(fat32->fs, cluster);
51+
steps--;
52+
}
53+
54+
fat32->current_cluster = cluster;
55+
}
56+
57+
*pos = offset;
58+
return 0;
59+
}
60+
61+
static int elf_vfs_read_exact(vfs_file_t* file, uint32_t offset, void* buf, uint32_t size)
62+
{
63+
if (elf_vfs_seek(file, offset) != 0)
64+
return -1;
65+
66+
int rd = vfs_read(file, (uint8_t*)buf, size);
67+
return (rd >= 0 && (uint32_t)rd == size) ? 0 : -1;
68+
}
69+
70+
static int elf_vfs_read_exact_path(const char* path, uint32_t offset, void* buf, uint32_t size)
71+
{
72+
vfs_file_t file;
73+
if (vfs_open(path, VFS_RDONLY, &file) != 0)
74+
return -1;
75+
76+
int rc = elf_vfs_read_exact(&file, offset, buf, size);
77+
vfs_close(&file);
78+
return rc;
79+
}
80+
81+
static uint64_t elf_runtime_addr_for_offset(Elf64_Phdr* headers, uint16_t phnum, uint64_t file_offset)
82+
{
83+
for (uint16_t i = 0; i < phnum; ++i) {
84+
Elf64_Phdr* ph = &headers[i];
85+
if (ph->p_type != PT_LOAD || ph->p_filesz == 0)
86+
continue;
87+
88+
uint64_t seg_start = ph->p_offset;
89+
uint64_t seg_end = ph->p_offset + ph->p_filesz;
90+
if (file_offset >= seg_start && file_offset < seg_end)
91+
return ph->p_vaddr + (file_offset - ph->p_offset);
92+
}
93+
94+
return 0;
95+
}
96+
97+
static uint64_t elf_stage_phdrs_for_user(Elf64_Phdr* headers, uint64_t phdr_bytes)
98+
{
99+
if (!headers || phdr_bytes == 0)
100+
return 0;
101+
102+
uint64_t base = USER_PHDR_VADDR;
103+
uint64_t aligned = (phdr_bytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
104+
105+
for (uint64_t off = 0; off < aligned; off += PAGE_SIZE) {
106+
uint64_t phys = allocate_page();
107+
map_user_page(base + off, phys, USER_DATA_FLAGS);
108+
}
109+
110+
memset((void*)base, 0, aligned);
111+
memcpy((void*)base, headers, phdr_bytes);
112+
return base;
113+
}
114+
115+
static int elf_validate_header(const Elf64_Ehdr* header, uint64_t file_size)
116+
{
117+
if (memcmp(&header->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 || header->e_ident[EI_CLASS] != ELFCLASS64 ||
118+
header->e_ident[EI_DATA] != ELFDATA2LSB || header->e_type != ET_EXEC ||
119+
header->e_machine != EM_X86_64 || header->e_version != EV_CURRENT)
120+
{
121+
error("Not a valid ELF file to load!", __FILE__);
122+
return -1;
123+
}
124+
125+
if (header->e_phoff + ((uint64_t)header->e_phnum * header->e_phentsize) > file_size ||
126+
header->e_phentsize != sizeof(Elf64_Phdr)) {
127+
eprintf("elf: invalid program header table");
128+
return -1;
129+
}
130+
131+
return 0;
132+
}
18133

19134
static int elf_map_program_header(Elf64_Phdr* ph, void* file_base, uint64_t file_size)
20135
{
@@ -52,7 +167,89 @@ static int elf_map_program_header(Elf64_Phdr* ph, void* file_base, uint64_t file
52167
return 0;
53168
}
54169

55-
void* elf_load_from_memory(void* file_base_address, uint64_t file_size)
170+
static int elf_map_program_header_from_vfs(Elf64_Phdr* ph, const char* path, uint64_t file_size, uint16_t seg_index)
171+
{
172+
if (ph->p_type != PT_LOAD)
173+
return 0;
174+
175+
if (ph->p_offset + ph->p_filesz > file_size || ph->p_memsz < ph->p_filesz) {
176+
eprintf("elf: invalid PT_LOAD bounds");
177+
return -1;
178+
}
179+
180+
uint64_t seg_start = ph->p_vaddr & ~0xFFFULL;
181+
uint64_t seg_end = (ph->p_vaddr + ph->p_memsz + 0xFFFULL) & ~0xFFFULL;
182+
183+
uint64_t page_flags = PAGE_PRESENT | PAGE_USER;
184+
if (ph->p_flags & PF_W)
185+
page_flags |= PAGE_RW;
186+
if (!(ph->p_flags & PF_X))
187+
page_flags |= PAGE_NX;
188+
189+
for (uint64_t page = seg_start; page < seg_end; page += PAGE_SIZE) {
190+
uint64_t phys = allocate_page();
191+
map_user_page(page, phys, page_flags);
192+
}
193+
194+
printf("elf: seg %u off=%x vaddr=%x filesz=%u memsz=%u",
195+
seg_index,
196+
ph->p_offset,
197+
ph->p_vaddr,
198+
ph->p_filesz,
199+
ph->p_memsz);
200+
201+
if (ph->p_filesz != 0) {
202+
vfs_file_t file;
203+
if (vfs_open(path, VFS_RDONLY, &file) != 0) {
204+
eprintf("elf: seg %u reopen failed", seg_index);
205+
return -1;
206+
}
207+
208+
if (elf_vfs_seek(&file, (uint32_t)ph->p_offset) != 0) {
209+
vfs_close(&file);
210+
eprintf("elf: seg %u seek failed", seg_index);
211+
return -1;
212+
}
213+
214+
uint8_t chunk[4096];
215+
uint64_t copied = 0;
216+
while (copied < ph->p_filesz) {
217+
uint32_t remaining = (uint32_t)(ph->p_filesz - copied);
218+
uint32_t want = remaining > sizeof(chunk) ? sizeof(chunk) : remaining;
219+
int rd = vfs_read(&file, chunk, want);
220+
if (rd < 0 || (uint32_t)rd != want) {
221+
vfs_close(&file);
222+
eprintf("elf: seg %u short read off=%x want=%u got=%d copied=%u/%u",
223+
seg_index,
224+
ph->p_offset + copied,
225+
want,
226+
rd,
227+
copied,
228+
ph->p_filesz);
229+
return -1;
230+
}
231+
232+
memcpy((void*)(ph->p_vaddr + copied), chunk, want);
233+
copied += want;
234+
}
235+
236+
vfs_close(&file);
237+
if (copied != ph->p_filesz) {
238+
eprintf("elf: seg %u copy mismatch copied=%u expected=%u",
239+
seg_index,
240+
copied,
241+
ph->p_filesz);
242+
return -1;
243+
}
244+
}
245+
246+
if (ph->p_memsz > ph->p_filesz)
247+
memset((uint8_t*)ph->p_vaddr + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
248+
249+
return 0;
250+
}
251+
252+
void* elf_load_from_memory_ex(void* file_base_address, uint64_t file_size, elf_image_info_t* info)
56253
{
57254
if (file_base_address == NULL || file_size < sizeof(Elf64_Ehdr))
58255
return NULL;
@@ -61,19 +258,8 @@ void* elf_load_from_memory(void* file_base_address, uint64_t file_size)
61258
Elf64_Ehdr header = {};
62259
memcpy(&header, file_ptr, sizeof(Elf64_Ehdr));
63260

64-
if (memcmp(&header.e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0 || header.e_ident[EI_CLASS] != ELFCLASS64 ||
65-
header.e_ident[EI_DATA] != ELFDATA2LSB || header.e_type != ET_EXEC ||
66-
header.e_machine != EM_X86_64 || header.e_version != EV_CURRENT)
67-
{
68-
error("Not a valid ELF file to load!", __FILE__);
69-
return NULL;
70-
}
71-
72-
if (header.e_phoff + ((uint64_t)header.e_phnum * header.e_phentsize) > file_size ||
73-
header.e_phentsize != sizeof(Elf64_Phdr)) {
74-
eprintf("elf: invalid program header table");
261+
if (elf_validate_header(&header, file_size) != 0)
75262
return NULL;
76-
}
77263

78264
// printf("Parsing ELF64 file with %d PHDRs\n", header.e_phnum);
79265

@@ -86,10 +272,25 @@ void* elf_load_from_memory(void* file_base_address, uint64_t file_size)
86272
}
87273
}
88274

275+
if (info) {
276+
info->entry = header.e_entry;
277+
info->phdr_addr = elf_stage_phdrs_for_user(program_headers_start,
278+
(uint64_t)header.e_phnum * header.e_phentsize);
279+
if (info->phdr_addr == 0)
280+
info->phdr_addr = elf_runtime_addr_for_offset(program_headers_start, header.e_phnum, header.e_phoff);
281+
info->phentsize = header.e_phentsize;
282+
info->phnum = header.e_phnum;
283+
}
284+
89285
return (void*)header.e_entry;
90286
}
91287

92-
void* elf_load_from_vfs(const char* path)
288+
void* elf_load_from_memory(void* file_base_address, uint64_t file_size)
289+
{
290+
return elf_load_from_memory_ex(file_base_address, file_size, NULL);
291+
}
292+
293+
void* elf_load_from_vfs_ex(const char* path, elf_image_info_t* info)
93294
{
94295
if (!path)
95296
return NULL;
@@ -121,21 +322,57 @@ void* elf_load_from_vfs(const char* path)
121322
return NULL;
122323
}
123324

124-
void* image = kmalloc(size);
125-
if (!image) {
325+
Elf64_Ehdr header = {};
326+
if (elf_vfs_read_exact(&file, 0, &header, sizeof(header)) != 0) {
327+
eprintf("elf: failed to read header");
126328
vfs_close(&file);
127329
return NULL;
128330
}
129331

130-
int rd = vfs_read(&file, (uint8_t*)image, size);
131-
vfs_close(&file);
332+
if (elf_validate_header(&header, size) != 0) {
333+
vfs_close(&file);
334+
return NULL;
335+
}
132336

133-
if (rd < 0 || (uint32_t)rd != size) {
134-
kfree(image);
337+
uint64_t phdr_bytes = (uint64_t)header.e_phnum * header.e_phentsize;
338+
Elf64_Phdr* program_headers = kmalloc(phdr_bytes);
339+
if (!program_headers) {
340+
eprintf("elf: failed to allocate program header table");
341+
vfs_close(&file);
342+
return NULL;
343+
}
344+
345+
if (elf_vfs_read_exact_path(path, (uint32_t)header.e_phoff, program_headers, (uint32_t)phdr_bytes) != 0) {
346+
eprintf("elf: failed to read program headers");
347+
kfree(program_headers);
348+
vfs_close(&file);
135349
return NULL;
136350
}
137351

138-
void* entry = elf_load_from_memory(image, size);
139-
kfree(image);
352+
vfs_close(&file);
353+
354+
for (uint16_t i = 0; i < header.e_phnum; ++i) {
355+
if (elf_map_program_header_from_vfs(&program_headers[i], path, size, i) != 0) {
356+
kfree(program_headers);
357+
return NULL;
358+
}
359+
}
360+
361+
if (info) {
362+
info->entry = header.e_entry;
363+
info->phdr_addr = elf_stage_phdrs_for_user(program_headers, phdr_bytes);
364+
if (info->phdr_addr == 0)
365+
info->phdr_addr = elf_runtime_addr_for_offset(program_headers, header.e_phnum, header.e_phoff);
366+
info->phentsize = header.e_phentsize;
367+
info->phnum = header.e_phnum;
368+
}
369+
370+
kfree(program_headers);
371+
void* entry = (void*)header.e_entry;
140372
return entry;
141373
}
374+
375+
void* elf_load_from_vfs(const char* path)
376+
{
377+
return elf_load_from_vfs_ex(path, NULL);
378+
}

0 commit comments

Comments
 (0)