Received: by 2002:a05:6a10:1287:0:0:0:0 with SMTP id d7csp3890169pxv; Mon, 19 Jul 2021 11:13:13 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyDThzT24+A6EyGzl8kTS9U7Ire82+eNGtZ6jzDeuTeZ9//0d9UxRf02+REc7buXDyahNS7 X-Received: by 2002:a6b:ba02:: with SMTP id k2mr15422477iof.164.1626718281905; Mon, 19 Jul 2021 11:11:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626718281; cv=none; d=google.com; s=arc-20160816; b=Sxi9Z4FJG1bNImASUFbXEnDY5JZz9Eaugx4vV01v0ifFpgwvnaJrBntQh+9l5XMudn 6h5+J3U2fg2S+gXExuEkapACiKLGjwXW05czR6jBJ01qUGS+86CB5ykgp/I9C3/Eu3LV sZTHw0JW+jGba6t2xWEjt+9uxvZ3dQXu/T6109uZM1ojZNECmkIrwMtG5su+KbooQVtH iodwLf9IuM8jTVzyG9FcxpaOcB9jJB29gW7Bsnl26BPHtxR6fCPlLsSx/IrLE+AOx/Gk UwtxlXadyGX5ezWDIfHIGrvHTyCxSIfLoYFKSwqVzXbvdxWf14QaykvD+px2LlDaUGGz Lebw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=gdS4DtrDE0jq9jk9mpaWROqrwpE7s6hxmtkjx6XEaYg=; b=HS+EbJFRVnJNXtPPUI32M6GRCyM/TbKpu6a3+eY9a97LtRJ6uLVl5d6ari/RunV8Po 2EMWNOBf6lSjrifF0T5WcKE0nVnMKZPlc/RsMJaCoc7P0rzYJ7YW20MVctDQSvnccOsn 8tT2wCyNYRWrO0OY6EH4uib1vJ+utfFTUy8jN6Q7lyx7t2K4Kz1C8lRK1kqZygFYUb+g KVmClze9iQTaGGnHwORPuTOOlpxmE3t2nG0TbooVj1bxAx24WdXlxpcpCER9j5ww0KaG g5oA/CBuRbJCwPECXr+8t289pUEqtTrUS+lOhKp1w+atxbBkFhbRo4405vC9G1qmIBkY FOCg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=M9yHdAQ6; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id j12si20919926jar.85.2021.07.19.11.11.10; Mon, 19 Jul 2021 11:11:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=M9yHdAQ6; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1380079AbhGSR1g (ORCPT + 99 others); Mon, 19 Jul 2021 13:27:36 -0400 Received: from mail.kernel.org ([198.145.29.99]:43678 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1349555AbhGSPpK (ORCPT ); Mon, 19 Jul 2021 11:45:10 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 1A88C61409; Mon, 19 Jul 2021 16:25:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1626711933; bh=+b1FT6sIZ/j2qD1KYh+WhRUaNVp0EPOv8Jc6wfGu2sM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=M9yHdAQ6Sud6tjdJ3NXFIWFtQdgtUZrZM6e0y9Irib/NEsn7Ow3EFcXBsZdBFYdWX aN4MR5+W5DoAMg7WsFFB5Wx3e89a0T/njW5/X1RureBFcHsnEnGt7Q9Nae/vA3HzpQ g4iPSqK6c6AuAh//nmOr/NoPSz9vnph5x/sGR044= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, YiFei Zhu , Johannes Berg , Richard Weinberger , Sasha Levin Subject: [PATCH 5.12 185/292] um: Fix stack pointer alignment Date: Mon, 19 Jul 2021 16:54:07 +0200 Message-Id: <20210719144948.574930317@linuxfoundation.org> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210719144942.514164272@linuxfoundation.org> References: <20210719144942.514164272@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: YiFei Zhu [ Upstream commit 558f9b2f94dbd2d5c5c8292aa13e081cc11ea7d9 ] GCC assumes that stack is aligned to 16-byte on call sites [1]. Since GCC 8, GCC began using 16-byte aligned SSE instructions to implement assignments to structs on stack. When CC_OPTIMIZE_FOR_PERFORMANCE is enabled, this affects os-Linux/sigio.c, write_sigio_thread: struct pollfds *fds, tmp; tmp = current_poll; Note that struct pollfds is exactly 16 bytes in size. GCC 8+ generates assembly similar to: movdqa (%rdi),%xmm0 movaps %xmm0,-0x50(%rbp) This is an issue, because movaps will #GP if -0x50(%rbp) is not aligned to 16 bytes [2], and how rbp gets assigned to is via glibc clone thread_start, then function prologue, going though execution trace similar to (showing only relevant instructions): sub $0x10,%rsi mov %rcx,0x8(%rsi) mov %rdi,(%rsi) syscall pop %rax pop %rdi callq *%rax push %rbp mov %rsp,%rbp The stack pointer always points to the topmost element on stack, rather then the space right above the topmost. On push, the pointer decrements first before writing to the memory pointed to by it. Therefore, there is no need to have the stack pointer pointer always point to valid memory unless the stack is poped; so the `- sizeof(void *)` in the code is unnecessary. On the other hand, glibc reserves the 16 bytes it needs on stack and pops itself, so by the call instruction the stack pointer is exactly the caller-supplied sp. It then push the 16 bytes of the return address and the saved stack pointer, so the base pointer will be 16-byte aligned if and only if the caller supplied sp is 16-byte aligned. Therefore, the caller must supply a 16-byte aligned pointer, which `stack + UM_KERN_PAGE_SIZE` already satisfies. On a side note, musl is unaffected by this issue because it forces 16 byte alignment via `and $-16,%rsi` in its clone wrapper. Similarly, glibc i386 is also unaffected because it has `andl $0xfffffff0, %ecx`. To reproduce this bug, enable CONFIG_UML_RTC and CC_OPTIMIZE_FOR_PERFORMANCE. uml_rtc will call add_sigio_fd which will then cause write_sigio_thread to either go into segfault loop or panic with "Segfault with no mm". Similarly, signal stacks will be aligned by the host kernel upon signal delivery. `- sizeof(void *)` to sigaltstack is unconventional and extraneous. On a related note, initialization of longjmp buffers do require `- sizeof(void *)`. This is to account for the return address that would have been pushed to the stack at the call site. The reason for uml to respect 16-byte alignment, rather than telling GCC to assume 8-byte alignment like the host kernel since commit d9b0cde91c60 ("x86-64, gcc: Use -mpreferred-stack-boundary=3 if supported"), is because uml links against libc. There is no reason to assume libc is also compiled with that flag and assumes 8-byte alignment rather than 16-byte. [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838 [2] https://c9x.me/x86/html/file_module_x86_id_180.html Signed-off-by: YiFei Zhu Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reviewed-by: Johannes Berg Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin --- arch/um/drivers/ubd_kern.c | 3 +-- arch/um/kernel/skas/clone.c | 2 +- arch/um/os-Linux/helper.c | 4 ++-- arch/um/os-Linux/signal.c | 2 +- arch/um/os-Linux/skas/process.c | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 8e0b43cf089f..cbd4f00fe77e 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1242,8 +1242,7 @@ static int __init ubd_driver_init(void){ * enough. So use anyway the io thread. */ } stack = alloc_stack(0, 0); - io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), - &thread_fd); + io_pid = start_io_thread(stack + PAGE_SIZE, &thread_fd); if(io_pid < 0){ printk(KERN_ERR "ubd : Failed to start I/O thread (errno = %d) - " diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c index 592cdb138441..5afac0fef24e 100644 --- a/arch/um/kernel/skas/clone.c +++ b/arch/um/kernel/skas/clone.c @@ -29,7 +29,7 @@ stub_clone_handler(void) long err; err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, - (unsigned long)data + UM_KERN_PAGE_SIZE / 2 - sizeof(void *)); + (unsigned long)data + UM_KERN_PAGE_SIZE / 2); if (err) { data->parent_err = err; goto done; diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 9fa6e4187d4f..32e88baf18dd 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -64,7 +64,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) goto out_close; } - sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE; data.pre_exec = pre_exec; data.pre_data = pre_data; data.argv = argv; @@ -120,7 +120,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, if (stack == 0) return -ENOMEM; - sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE; pid = clone(proc, (void *) sp, flags, arg); if (pid < 0) { err = -errno; diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index 96f511d1aabe..e283f130aadc 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -129,7 +129,7 @@ void set_sigstack(void *sig_stack, int size) stack_t stack = { .ss_flags = 0, .ss_sp = sig_stack, - .ss_size = size - sizeof(void *) + .ss_size = size }; if (sigaltstack(&stack, NULL) != 0) diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index fba674fac8b7..87d3129e7362 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -327,7 +327,7 @@ int start_userspace(unsigned long stub_stack) } /* set stack pointer to the end of the stack page, so it can grow downwards */ - sp = (unsigned long) stack + UM_KERN_PAGE_SIZE - sizeof(void *); + sp = (unsigned long)stack + UM_KERN_PAGE_SIZE; flags = CLONE_FILES | SIGCHLD; -- 2.30.2