Fix unaligned word accesses

This commit is contained in:
Mark
2020-06-12 17:30:41 +03:00
parent 6ebf440b60
commit f5d6370403
6 changed files with 70 additions and 42 deletions
+1 -37
View File
@@ -86,43 +86,7 @@ void kernel_early_init(void) {
cpuid_init();
if (multiboot_tag_sections) {
kinfo("Loading kernel symbols\n");
kinfo("%u section headers:\n", multiboot_tag_sections->num);
size_t string_section_offset = multiboot_tag_sections->shndx * multiboot_tag_sections->entsize;
Elf64_Shdr *string_section_hdr = (Elf64_Shdr *) &multiboot_tag_sections->sections[string_section_offset];
const char *shstrtab = (const char *) MM_VIRTUALIZE(string_section_hdr->sh_addr);
Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;
for (size_t i = 0; i < multiboot_tag_sections->num; ++i) {
Elf64_Shdr *shdr = (Elf64_Shdr *) &multiboot_tag_sections->sections[i * multiboot_tag_sections->entsize];
const char *name = &shstrtab[shdr->sh_name];
switch (shdr->sh_type) {
case SHT_SYMTAB:
if (symtab_shdr) {
panic("Kernel image has 2+ symbol tables\n");
}
symtab_shdr = shdr;
break;
case SHT_STRTAB:
if (strcmp(name, ".strtab")) {
break;
}
if (strtab_shdr) {
panic("kernel image has 2+ string tables\n");
}
strtab_shdr = shdr;
break;
default:
break;
}
}
if (symtab_shdr && strtab_shdr) {
uintptr_t symtab_ptr = MM_VIRTUALIZE(symtab_shdr->sh_addr);
uintptr_t strtab_ptr = MM_VIRTUALIZE(strtab_shdr->sh_addr);
debug_symbol_table_set(symtab_ptr, strtab_ptr, symtab_shdr->sh_size, strtab_shdr->sh_size);
}
debug_symbol_table_multiboot2(multiboot_tag_sections);
}
if (multiboot_tag_cmdline) {
+3
View File
@@ -38,7 +38,10 @@
#define kfatal(f, ...) debugf(DEBUG_FATAL, "\033[41m" DEBUG_BASE_FMT f "\033[0m", DEBUG_BASE_ARGS, ##__VA_ARGS__)
#define kprint(l, f, ...) debugf(l, DEBUG_BASE_FMT f, DEBUG_BASE_ARGS, ##__VA_ARGS__)
struct multiboot_tag_elf_sections;
void debug_symbol_table_set(uintptr_t symtab, uintptr_t strtab, size_t symtab_size, size_t strtab_size);
void debug_symbol_table_multiboot2(struct multiboot_tag_elf_sections *tag);
int debug_symbol_find(uintptr_t addr, const char **name, uintptr_t *base);
int debug_symbol_find_by_name(const char *name, uintptr_t *value);
void debug_backtrace(uintptr_t rbp, int depth, int limit);
+8
View File
@@ -5,6 +5,14 @@
#pragma once
#include "sys/types.h"
// A macro to properly read data from misaligned pointers, byte by byte
// May be slower, but at least UBSan doesn't complain
#define realigned(base, field) ({ \
typeof(base->field) __v0; \
memcpy(&__v0, (void *) (base) + offsetof(typeof(*base), field), sizeof(__v0)); \
__v0; \
})
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
+49
View File
@@ -1,3 +1,4 @@
#include "arch/amd64/multiboot2.h"
#include "sys/string.h"
#include "sys/debug.h"
#include "sys/ctype.h"
@@ -6,6 +7,8 @@
#include "sys/config.h"
#include "sys/elf.h"
#include "sys/assert.h"
#include "sys/mm.h"
#include <stdint.h>
#if defined(ARCH_AMD64)
@@ -20,6 +23,52 @@ static uintptr_t g_strtab_ptr = 0;
static size_t g_symtab_size = 0;
static size_t g_strtab_size = 0;
// Multiboot2-loaded sections are misaligned for some reason
void debug_symbol_table_multiboot2(struct multiboot_tag_elf_sections *tag) {
kinfo("Loading kernel symbols\n");
kinfo("%u section headers:\n", tag->num);
size_t string_section_offset = tag->shndx * tag->entsize;
Elf64_Shdr *string_section_hdr = (Elf64_Shdr *) &tag->sections[string_section_offset];
const char *shstrtab = (const char *) MM_VIRTUALIZE(realigned(string_section_hdr, sh_addr));
Elf64_Shdr *symtab_shdr = NULL, *strtab_shdr = NULL;
for (size_t i = 0; i < tag->num; ++i) {
Elf64_Shdr *shdr = (Elf64_Shdr *) &tag->sections[i * tag->entsize];
const char *name = &shstrtab[realigned(shdr, sh_name)];
switch (realigned(shdr, sh_type)) {
case SHT_SYMTAB:
if (symtab_shdr) {
panic("Kernel image has 2+ symbol tables\n");
}
symtab_shdr = shdr;
break;
case SHT_STRTAB:
if (strcmp(name, ".strtab")) {
break;
}
if (strtab_shdr) {
panic("kernel image has 2+ string tables\n");
}
strtab_shdr = shdr;
break;
default:
break;
}
}
if (symtab_shdr && strtab_shdr) {
uintptr_t symtab_ptr = MM_VIRTUALIZE(realigned(symtab_shdr, sh_addr));
uintptr_t strtab_ptr = MM_VIRTUALIZE(realigned(strtab_shdr, sh_addr));
debug_symbol_table_set(symtab_ptr,
strtab_ptr,
realigned(symtab_shdr, sh_size),
realigned(strtab_shdr, sh_size));
}
}
void debug_symbol_table_set(uintptr_t s0, uintptr_t s1, size_t z0, size_t z1) {
g_symtab_ptr = s0;
g_symtab_size = z0;
+5 -1
View File
@@ -143,7 +143,11 @@ static int elf_rela_apply(void *image, uintptr_t base, Elf64_Shdr *shdrs, Elf64_
switch (ELF64_R_TYPE(rela->r_info)) {
case R_X86_64_64:
*((uint64_t *) value_ptr) = (uint64_t) (value + (intptr_t) rela->r_addend);
{
uint64_t src = (uint64_t) (value + (intptr_t) rela->r_addend);
// value_ptr most likely will be unaligned
memcpy(value_ptr, &src, sizeof(uint64_t));
}
break;
case R_X86_64_PLT32: // Treat this the same as PC32
case R_X86_64_PC32:
+4 -4
View File
@@ -2,8 +2,8 @@
#include "sys/panic.h"
#include "sys/debug.h"
//#define UBSAN_ABORT 1
#undef UBSAN_ABORT
#define UBSAN_ABORT 1
//#undef UBSAN_ABORT
struct source_location {
const char *file;
@@ -123,7 +123,7 @@ void __ubsan_handle_vla_bound_not_positive(void *data_raw,
struct type_mismatch_info {
struct source_location location;
struct type_descriptor *type;
uintptr_t alignment;
uint8_t alignment;
uint8_t type_check_kind;
};
void __ubsan_handle_type_mismatch_v1(struct type_mismatch_info *type_mismatch,
@@ -135,7 +135,7 @@ void __ubsan_handle_type_mismatch_v1(struct type_mismatch_info *type_mismatch,
} else if (type_mismatch->alignment != 0 &&
is_aligned(pointer, type_mismatch->alignment)) {
// Most useful on architectures with stricter memory alignment requirements, like ARM.
kfatal("Unaligned memory access\n");
kfatal("Unaligned memory access: %p\n", pointer);
} else {
kfatal("Insufficient size:\n");
if (type_mismatch->type_check_kind < sizeof(Type_Check_Kinds) / sizeof(Type_Check_Kinds[0])) {