From f8d5eb488a3b50c33097e37af0b60602580b2195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9F=83=E5=8D=9A=E6=8B=89=E9=85=B1?= Date: Tue, 14 Apr 2026 22:49:17 +0800 Subject: [PATCH] Align pushed argv table before execve on AArch64 When shebang expansion rewrites argv[] through push_array_of_xpointers(), the copied pointer table can land at a misaligned stack address on AArch64. The kernel then rejects execve() with EFAULT even though argv, envp and the strings remain readable. Compute padding from the current stack pointer before alloc_mem() so the copied block stays 16-byte aligned on AArch64 and word aligned on other architectures. The padding stays above the copied block, so the previously computed pointee offsets remain valid. --- src/execve/aoxp.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/execve/aoxp.c b/src/execve/aoxp.c index b1103a60..1595826c 100644 --- a/src/execve/aoxp.c +++ b/src/execve/aoxp.c @@ -356,7 +356,9 @@ int push_array_of_xpointers(ArrayOfXPointers *array, Reg reg) struct iovec *local; size_t local_count; size_t total_size; + size_t padding_size; word_t *pod_array; + word_t stack_pointer; word_t tracee_ptr; int status; size_t i; @@ -411,6 +413,22 @@ int push_array_of_xpointers(ArrayOfXPointers *array, Reg reg) return 0; assert(local_count < array->length + 1); + /* Keep the base address of the pushed pointer table aligned. + * Without this padding, AArch64 shebang execve can place argv[] at an + * odd stack address (for example 0x...989), and the kernel then rejects + * execve with EFAULT even though argv[], envp[], and the strings are all + * readable. The padding stays above the copied data, so the offsets that + * were computed for each pointee remain valid and only the allocation base + * moves downward. */ + stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER); + padding_size = (stack_pointer - total_size) +#ifdef ARCH_ARM64 + % 16; +#else + % sizeof_word(tracee); +#endif + total_size += padding_size; + /* Modified pointees and the pod array are stored in a tracee's * memory block. */ tracee_ptr = alloc_mem(tracee, total_size);