SerenityOS / serenity

The Serenity Operating System 🐞
https://serenityos.org
BSD 2-Clause "Simplified" License
30.56k stars 3.19k forks source link

DynamicLoader+LibELF: Executes unaligned memory accesses on aarch64 #17516

Open FireFox317 opened 1 year ago

FireFox317 commented 1 year ago

We currently build all of userspace and kernel with the -mstrict-align flag to enforce the compiler to emit aligned memory accesses: https://github.com/SerenityOS/serenity/blob/ba5df46a49b3f026e67924fb262db81ce311e8f6/Meta/CMake/serenity_compile_options.cmake#L56-L61

We do this because we set up the aarch64 CPU to enforce aligned memory accesses: https://github.com/SerenityOS/serenity/blob/ba5df46a49b3f026e67924fb262db81ce311e8f6/Kernel/Arch/aarch64/Exceptions.cpp#L77

However, the compiler still emits code in the DynamicLoader (or to be more specific in LibELF/Validation.cpp) that will do unaligned memory accesses:

Backtrace (exception happens in ELF::validate_program_headers(Elf64_Ehdr const&, unsigned long, AK::Span<unsigned char const>, AK::StringBuilder*, bool):

void AK::Variant<bool, AK::Error>::set<bool, bool>(bool&&, AK::Detail::VariantNoClearTag) at ./Build/aarch64/././AK/Variant.h:376
ELF::Image::parse() at ./Build/aarch64/./Userland/Libraries/LibELF/Image.cpp:131
ELF::DynamicLoader::DynamicLoader(int, AK::DeprecatedString, void*, unsigned long) at ./Build/aarch64/./Userland/Libraries/LibELF/DynamicLoader.cpp:71
ELF::DynamicLoader::try_create(int, AK::DeprecatedString) at ./Build/aarch64/./Userland/Libraries/LibELF/DynamicLoader.cpp:59
ELF::map_library(AK::DeprecatedString const&, int) at ./Build/aarch64/./Userland/Libraries/LibELF/DynamicLinker.cpp:94
ELF::DynamicLinker::linker_main(AK::DeprecatedString&&, int, bool, int, char**, char**) at ./Build/aarch64/./Userland/Libraries/LibELF/DynamicLinker.cpp:642
_entry at ./Build/aarch64/./Userland/DynamicLoader/main.cpp:112
_start at ./Build/aarch64/./Userland/DynamicLoader/main.cpp:66
Output ``` ➜ aarch64 git:(aarch64-alignment-exception) ✗ ninja Kernel && ../../Meta/run.sh [0/2] Re-checking globbed directories... [1/2] Re-running CMake... -- Configuring done -- Generating done -- Build files have been written to: /Users/timon/serenity/Build/aarch64 [0/2] Re-checking globbed directories... [0/6] cd /Users/timon/serenity/Build/aarch64 && /opt/homebrew/Cellar/cmake/3....LCHAIN=GNU LLVM_VERSION=12.2.0 /Users/timon/serenity/Meta/build-image-qemu.sh Password: checking existing image e2fsck 1.46.5 (30-Dec-2021) Stap 1: Controle van inodes, blokken, en groottes Stap 2: Controle van mappenstructuur Stap 3: Controle van verbindingen tussen mappen Stap 4: Controle van verwijzingsaantallen Stap 5: Controle van groepssamenvattingen _disk_image: 5024/6240 bestanden (0.4% niet-aaneengesloten), 110581/488272 blokken done mounting filesystem... done installing base system... done creating initial filesystem structure... done creating utmp file... done setting up device nodes folder... done setting up sysfs folder... done installing users... done adding some desktop icons... done installing shortcuts... done installing 'checksum' variants... done unmounting filesystem... done [6/6] Linking CXX executable Kernel/Kernel /Users/timon/serenity/Toolchain/Local/aarch64/lib/gcc/aarch64-pc-serenity/12.2.0/../../../../aarch64-pc-serenity/bin/ld: warning: -z relro ignored /Users/timon/serenity/Toolchain/Local/aarch64/lib/gcc/aarch64-pc-serenity/12.2.0/../../../../aarch64-pc-serenity/bin/ld: warning: -z pack-relative-relocs ignored [Kernel]: Welcome to Serenity OS! [Kernel]: Imagine this being your ideal operating system. [Kernel]: Observed deviations from that ideal are shortcomings of your imagination. [Kernel]: [Kernel]: CPU[0]: Supports PMULL DoubleLock SHA1 SHA256 CRC32 BBM PMUv3 [Kernel]: CPU[0]: Physical address bit width: 40 [Kernel]: CPU[0]: Virtual address bit width: 48 [Kernel]: CPU[0]: Random number generator not detected, randomness will be poor [Kernel]: Loading kernel symbol table... [Kernel]: Kernel Commandline: [Kernel]: Starting SerenityOS... [Kernel]: Initialize MMU [Kernel]: MM: Multiboot mmap: address=0x0000000000000000, length=1056964608, type=1 [Kernel]: MM: boot_pml4t @ P00000000024bf000 [Kernel]: MM: boot_pdpt @ P00000000024c0000 [Kernel]: MM: boot_pd0 @ P0000000000000000 [Kernel]: MM: boot_pd_kernel @ P00000000024e1000 [Kernel]: MM: Physical page entries: 0x0000002002e00000 - 0x0000002002ff8fff (size 0x00000000001f9000) [Kernel]: MM: Kernel range @ P0000000000080000 - P0000000002cbefff (size 0x2c3f000) [Kernel]: MM: Boot module range @ P0000000002cbf000 - P00000000209955ff (size 0x1dcd6600) [Kernel]: MM: Physical Pages range @ P0000000020996000 - P0000000020b8ffff (size 0x1fa000) [Kernel]: MM: User physical region: P0000000000000000 - P000000000007efff (size 0x7f000) [Kernel]: MM: User physical region: P0000000020b90000 - P000000003effffff (size 0x1e470000) [Kernel]: * 30x PhysicalZone (16 MiB) @ 0000000020b90000-000000003db8ffff [Kernel]: * 4x PhysicalZone (1 MiB) @ 000000003eb90000-000000003ee8ffff [Kernel]: Initialized framebuffer: 1280 x 720 @ 32 bits [Kernel]: PAT is not supported, implement MTRR fallback if available [Kernel]: Boot logo size: 274351 (205 x 446) 0.500 [Kernel]: KernelRng: Using bad entropy source TimeManagement 0.551 [#0 colonel(0:0)]: Scheduler[0]: idle loop running 0.557 [init_stage2(1:1)]: Firmware version: 4294967295 0.563 [init_stage2(1:1)]: Ramdisk: Device #0 @ V0x0000002007e30000, Capacity=500002816 0.830 [#0 init_stage2(1:1)]: Master Boot Record: invalid signature 0.830 [#0 init_stage2(1:1)]: Master Boot Record: invalid signature 0.881 [init_stage2(1:1)]: VirtualFileSystem: mounted root(1) from Ext2FS (device:6,0) 1.040 [#0 SystemServer(2:2)]: Unknown DFSC: Alignment fault 1.040 [SystemServer(2:2)]: CRASH: CPU #0 Unknown page fault in userspace 1.040 [#0 SystemServer(2:2)]: Exception Syndrome: EC(0b100100) IL(0b1) ISS(0b1100001) ISS2(0b0) 1.040 [#0 SystemServer(2:2)]: Class: Data Abort exception from a lower Exception level 1.045 [#0 SystemServer(2:2)]: Data Fault Status Code: Alignment fault 1.045 [#0 SystemServer(2:2)]: Faulting Virtual Address: 0x945c7a449 1.045 [#0 SystemServer(2:2)]: Saved Program Status: (NZCV(0b110) DAIF(0b0) M(0b0)) / 0x60000000 1.045 [#0 SystemServer(2:2)]: Exception Link Register: 0x12631174 1.045 [#0 SystemServer(2:2)]: Stack Pointer (EL0): 0x945c7a260 1.045 [#0 SystemServer(2:2)]: x0=0x0000000945c7a449 x1=0x0000000000000001 x2=0x00000000000001c8 x3=0x0000000000000008 x4=0x000000006474e550 1.049 [#0 SystemServer(2:2)]: x5=0x000000006474e552 x6=0x000000006474e551 x7=0x000000006474e551 x8=0x0000000000000003 x9=0x0000000000000012 1.049 [#0 SystemServer(2:2)]: x10=0x0000000000012890 x11=0x0000000945c7a340 x12=0x00000000126b7f40 x13=0x0000000000000040 x14=0x0000000000000040 1.049 [#0 SystemServer(2:2)]: x15=0xffffffffffffffc0 x16=0x0000000000000000 x17=0x0000000000000000 x18=0x0000000000000000 x19=0x0000000000130000 1.049 [#0 SystemServer(2:2)]: x20=0x0000000945c7a448 x21=0x00000000126c2000 x22=0x0000000000130000 x23=0x0000000000063540 x24=0x0000000000000040 1.055 [#0 SystemServer(2:2)]: x25=0x0000000000000008 x26=0x0000000000063540 x27=0x0000000000000000 x28=0x0000000000000001 x29=0x0000000945c7a260 1.055 [#0 SystemServer(2:2)]: x30=0x000000001262eb60 1.055 [#0 SystemServer(2:2)]: 0x0000000012631174 (?) 1.055 [#0 SystemServer(2:2)]: Userspace backtrace: 1.055 [#0 SystemServer(2:2)]: 0x000000001262eb60 (next: 0x0000000945c7a3c0) 1.055 [#0 SystemServer(2:2)]: 0x0000000012629f5c (next: 0x0000000945c7a470) 1.055 [#0 SystemServer(2:2)]: 0x000000001262a274 (next: 0x0000000945c7a500) 1.060 [#0 SystemServer(2:2)]: 0x00000000126226a8 (next: 0x0000000945c7a640) 1.060 [#0 SystemServer(2:2)]: 0x0000000012624834 (next: 0x0000000945c7a6f0) 1.060 [#0 SystemServer(2:2)]: 0x00000000125e63dc (next: 0x0000000945c7a900) 1.060 [#0 SystemServer(2:2)]: 0x00000000125e6224 (next: 0x0000000000000000) 1.060 [#0 SystemServer(2:2)]: Kernel backtrace: 1.060 [#0 SystemServer(2:2)]: Kernel + 0x0000000000a1a57c Kernel::Process::crash(int, AK::Optional, bool) +0x2ac 1.060 [#0 SystemServer(2:2)]: Kernel + 0x00000000001756c8 Kernel::handle_crash(Kernel::RegisterState const&, char const*, int, bool) +0x568 1.060 [#0 SystemServer(2:2)]: Kernel + 0x0000000000de3c18 exception_common +0x2a8 1.066 [#0 SystemServer(2:2)]: Kernel + 0x0000000000dfa6bc synchronous_lower_el +0x74 1.066 [#0 SystemServer(2:2)]: Process regions: 1.066 [#0 SystemServer(2:2)]: BEGIN END SIZE ACCESS NAME 1.066 [#0 SystemServer(2:2)]: 0x0000000000110000 -- 0x000000000011ffff 0x0000000000010000 RW malloc: ChunkedBlock(64) 1.066 [#0 SystemServer(2:2)]: 0x0000000000120000 -- 0x000000000012ffff 0x0000000000010000 RW malloc: ChunkedBlock(32) 1.066 [#0 SystemServer(2:2)]: 0x0000000000130000 -- 0x0000000000193fff 0x0000000000064000 R S ELF_DYN: /bin/SystemServer 1.066 [#0 SystemServer(2:2)]: 0x00000000001a0000 -- 0x00000000001affff 0x0000000000010000 RW malloc: ChunkedBlock(256) 1.066 [#0 SystemServer(2:2)]: 0x00000000125d7000 -- 0x00000000125e0fff 0x000000000000a000 R S C /usr/lib/Loader.so 1.066 [#0 SystemServer(2:2)]: 0x00000000125e1000 -- 0x0000000012672fff 0x0000000000092000 R XS C /usr/lib/Loader.so 1.066 [#0 SystemServer(2:2)]: 0x0000000012673000 -- 0x00000000126bcfff 0x000000000004a000 R S C /usr/lib/Loader.so 1.066 [#0 SystemServer(2:2)]: 0x00000000126bd000 -- 0x00000000126c4fff 0x0000000000008000 RW /usr/lib/Loader.so (data-rw) 1.066 [#0 SystemServer(2:2)]: 0x0000000945b7b000 -- 0x0000000945c7afff 0x0000000000100000 RW T Stack (Main thread) 1.066 [#0 SystemServer(2:2)]: 0x00000011282b7000 -- 0x00000011282b7fff 0x0000000000001000 R XS C Signal trampoline 1.066 [#0 SystemServer(2:2)]: Kernel regions: 1.066 [#0 SystemServer(2:2)]: BEGIN END SIZE ACCESS NAME 1.066 [#0 SystemServer(2:2)]: 0x0000002000000000 -- 0x0000002002dfffff 0x0000000002e00000 1.066 [#0 SystemServer(2:2)]: 0x0000002002e00000 -- 0x0000002002ff8fff 0x00000000001f9000 1.066 [#0 SystemServer(2:2)]: 0x0000002002ff9000 -- 0x0000002002ff9fff 0x0000000000001000 RW Time page 1.066 [#0 SystemServer(2:2)]: 0x0000002002ffa000 -- 0x0000002002ffafff 0x0000000000001000 R C Signal trampolines 1.066 [#0 SystemServer(2:2)]: 0x0000002002ffb000 -- 0x0000002002ffbfff 0x0000000000001000 RW Ext2FS: Block group descriptors 1.066 [#0 SystemServer(2:2)]: 0x0000002002ffc000 -- 0x0000002002ffcfff 0x0000000000001000 RW Ext2FS: Cached bitmap block 1.066 [#0 SystemServer(2:2)]: 0x0000002002ffd000 -- 0x0000002002ffdfff 0x0000000000001000 RW Ext2FS: Cached bitmap block 1.066 [#0 SystemServer(2:2)]: 0x0000002002ffe000 -- 0x0000002002ffefff 0x0000000000001000 RW Ext2FS: Cached bitmap block 1.066 [#0 SystemServer(2:2)]: 0x0000002003000000 -- 0x0000002006ffffff 0x0000000004000000 1.066 [#0 SystemServer(2:2)]: 0x0000002007000000 -- 0x0000002007e0ffff 0x0000000000e10000 RW Boot Framebuffer 1.066 [#0 SystemServer(2:2)]: 0x0000002007e10000 -- 0x0000002007e1ffff 0x0000000000010000 RW T Kernel stack (thread 0) 1.066 [#0 SystemServer(2:2)]: 0x0000002007e20000 -- 0x0000002007e2ffff 0x0000000000010000 RW T Kernel stack (thread 1) 1.066 [#0 SystemServer(2:2)]: 0x0000002007e30000 -- 0x0000002025b06fff 0x000000001dcd7000 RW Ramdisk 1.066 [#0 SystemServer(2:2)]: 0x0000002025b07000 -- 0x00000020264cafff 0x00000000009c4000 RW BlockBasedFS: Cache blocks 1.066 [#0 SystemServer(2:2)]: 0x00000020264cb000 -- 0x0000002026540fff 0x0000000000076000 RW BlockBasedFS: Cache entries 1.066 [#0 SystemServer(2:2)]: 0x0000002026541000 -- 0x0000002026550fff 0x0000000000010000 RW T Kernel stack (thread 2) 1.066 [#0 SystemServer(2:2)]: 0x0000002026551000 -- 0x0000002026551fff 0x0000000000001000 RW Ext2FS: Cached bitmap block ```
BertalanD commented 1 year ago

IMO, the best way forward would be to disable the memory access alignment check altogether, and build the kernel only with -mstrict-align. The only reason were alignment matters on modern arm64 hardware is when you are doing MMIO. Thus, the kernel should be alignment-safe, but there is no point in burdening the userland with worse codegen & having to retrofit strict alignment into ports/etc.

supercomputer7 commented 1 year ago

IMO, the best way forward would be to disable the memory access alignment check altogether, and build the kernel only with -mstrict-align. The only reason were alignment matters on modern arm64 hardware is when you are doing MMIO. Thus, the kernel should be alignment-safe, but there is no point in burdening the userland with worse codegen & having to retrofit strict alignment into ports/etc.

I agree with this. Some piece of hardware requires you to do aligned memory access on its MMIO range. This happens to be this way for at least one piece of hardware (ASMedia USB3 XHCI Controller on PCIe card I have) I tested - unaligned memory access caused a complete lockup for that card and only a reset fixed it. We should be able to allow user space to do unaligned memory access in the cost of performance degradation. Ofc, for programs that map MMIO, the kernel should be able to emulate unaligned access, otherwise it should terminate the program.