From patchwork Wed Sep 16 15:08:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Madhavan T. Venkataraman" X-Patchwork-Id: 11779863 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 146326CA for ; Wed, 16 Sep 2020 15:10:28 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C3CAE206B7 for ; Wed, 16 Sep 2020 15:10:27 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="TT0jUYj+"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="jlXuHOKX" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C3CAE206B7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linux.microsoft.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:MIME-Version:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:References:In-Reply-To:Message-Id:Date:Subject:To: From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Y5YyY9BjXtWuWvhsweoeooS7VhpxewWkLXGfH77l5To=; b=TT0jUYj+aUbSnGTD1fJaf6oXRc +rWFX5u6LgSBNVZ/QAMK263MixQY12SrmeiEUMWKRChyDzgqToQJq7onLLgZpeLFuwETo1db+Y7Xx LYgrgkDDdDwxcoaRsjKYQaszu+uHCCrBc30UiwDBwVzfs/4BfAhrjjGb5KYEzzDxww5ZfOwksiNL1 P/bCmAMF9it3IVY9Jve8Vmhb3dahl8M7q3qWcIXCBTPdHOmwk6uUXer49T5Ma8GTpSu/yW8g470fE 4cJqWLzrrlZ0Lm6LZm8/y1BVoeMoV0M74yLTiceARhpw9WJLS9wmHo+qb6SPWxt0BDRZAQPluTiBi W5+EZKFg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kIZ3D-0004D4-IK; Wed, 16 Sep 2020 15:08:51 +0000 Received: from linux.microsoft.com ([13.77.154.182]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kIZ35-00048J-0O for linux-arm-kernel@lists.infradead.org; Wed, 16 Sep 2020 15:08:45 +0000 Received: from localhost.localdomain (unknown [47.187.206.220]) by linux.microsoft.com (Postfix) with ESMTPSA id 7A40A20B36E7; Wed, 16 Sep 2020 08:08:35 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7A40A20B36E7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1600268916; bh=3qfx1/3d8ADHXgnKcsbkjWTPFHnk11ORotWaBTL6O08=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jlXuHOKXyISz8deDWkQh2eBSekwkIt4UwS7NyYPJK36DGbmb6ffleqjN8b6FhCOr2 AnuvAVQJP23C5+aNy5gJ9189tTya06ZQwHQ20hmsp383uD+yDN8vEK2Ap0XPeWgJZI zezzesbaBB6mxSMWqnE8qAQBKJSAel/tHzXIhZlI= From: madvenka@linux.microsoft.com To: kernel-hardening@lists.openwall.com, linux-api@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-fsdevel@vger.kernel.org, linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, oleg@redhat.com, x86@kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v2 2/4] [RFC] x86/trampfd: Provide support for the trampoline file descriptor Date: Wed, 16 Sep 2020 10:08:24 -0500 Message-Id: <20200916150826.5990-3-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200916150826.5990-1-madvenka@linux.microsoft.com> References: <210d7cd762d5307c2aa1676705b392bd445f1baa> <20200916150826.5990-1-madvenka@linux.microsoft.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200916_110843_357541_64521C4D X-CRM114-Status: GOOD ( 19.48 ) X-Spam-Score: -17.9 (-----------------) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-17.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [13.77.154.182 listed in list.dnswl.org] -7.5 USER_IN_DEF_DKIM_WL From: address is in the default DKIM white-list -7.5 USER_IN_DEF_SPF_WL From: address is in the default SPF white-list -0.0 SPF_PASS SPF: sender matches SPF record -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.5 ENV_AND_HDR_SPF_MATCH Env and Hdr From used in default SPF WL Match X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: "Madhavan T. Venkataraman" - Define architecture specific register names - Architecture specific functions for: - system call init - code descriptor check - data descriptor check - Fill a page with a trampoline table for: - 32-bit user process - 64-bit user process Signed-off-by: Madhavan T. Venkataraman --- arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/entry/syscalls/syscall_64.tbl | 1 + arch/x86/include/uapi/asm/ptrace.h | 38 ++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/trampfd.c | 238 +++++++++++++++++++++++++ 5 files changed, 279 insertions(+) create mode 100644 arch/x86/kernel/trampfd.c diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index d8f8a1a69ed1..d4f17806c9ab 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -443,3 +443,4 @@ 437 i386 openat2 sys_openat2 438 i386 pidfd_getfd sys_pidfd_getfd 439 i386 faccessat2 sys_faccessat2 +440 i386 trampfd sys_trampfd diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 78847b32e137..91b37bc4b6f0 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -360,6 +360,7 @@ 437 common openat2 sys_openat2 438 common pidfd_getfd sys_pidfd_getfd 439 common faccessat2 sys_faccessat2 +440 common trampfd sys_trampfd # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/arch/x86/include/uapi/asm/ptrace.h b/arch/x86/include/uapi/asm/ptrace.h index 85165c0edafc..b4be362929b3 100644 --- a/arch/x86/include/uapi/asm/ptrace.h +++ b/arch/x86/include/uapi/asm/ptrace.h @@ -9,6 +9,44 @@ #ifndef __ASSEMBLY__ +/* + * These register names are to be used by 32-bit applications. + */ +enum reg_32_name { + x32_min = 0, + x32_eax = x32_min, + x32_ebx, + x32_ecx, + x32_edx, + x32_esi, + x32_edi, + x32_ebp, + x32_max, +}; + +/* + * These register names are to be used by 64-bit applications. + */ +enum reg_64_name { + x64_min = x32_max, + x64_rax = x64_min, + x64_rbx, + x64_rcx, + x64_rdx, + x64_rsi, + x64_rdi, + x64_rbp, + x64_r8, + x64_r9, + x64_r10, + x64_r11, + x64_r12, + x64_r13, + x64_r14, + x64_r15, + x64_max, +}; + #ifdef __i386__ /* this struct defines the way the registers are stored on the stack during a system call. */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index e77261db2391..feb7f4f311fd 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -157,3 +157,4 @@ ifeq ($(CONFIG_X86_64),y) endif obj-$(CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT) += ima_arch.o +obj-$(CONFIG_TRAMPFD) += trampfd.o diff --git a/arch/x86/kernel/trampfd.c b/arch/x86/kernel/trampfd.c new file mode 100644 index 000000000000..7b812c200d01 --- /dev/null +++ b/arch/x86/kernel/trampfd.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Trampoline FD - X86 support. + * + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (c) 2020, Microsoft Corporation. + */ + +#include +#include + +#define TRAMPFD_CODE_32_SIZE 24 +#define TRAMPFD_CODE_64_SIZE 40 + +static inline bool is_compat(void) +{ + return (IS_ENABLED(CONFIG_X86_32) || + (IS_ENABLED(CONFIG_COMPAT) && test_thread_flag(TIF_ADDR32))); +} + +/* + * trampfd syscall. + */ +void trampfd_arch(struct trampfd_info *info) +{ + if (is_compat()) + info->code_size = TRAMPFD_CODE_32_SIZE; + else + info->code_size = TRAMPFD_CODE_64_SIZE; + info->ntrampolines = PAGE_SIZE / info->code_size; + info->code_offset = TRAMPFD_CODE_PGOFF << PAGE_SHIFT; + info->reserved = 0; +} + +/* + * trampfd code descriptor check. + */ +int trampfd_code_arch(struct trampfd_code *code) +{ + int ntrampolines; + int min, max; + + if (is_compat()) { + min = x32_min; + max = x32_max; + ntrampolines = PAGE_SIZE / TRAMPFD_CODE_32_SIZE; + } else { + min = x64_min; + max = x64_max; + ntrampolines = PAGE_SIZE / TRAMPFD_CODE_64_SIZE; + } + + if (code->reg < min || code->reg >= max) + return -EINVAL; + + if (!code->ntrampolines || code->ntrampolines > ntrampolines) + return -EINVAL; + return 0; +} + +/* + * trampfd data descriptor check. + */ +int trampfd_data_arch(struct trampfd_data *data) +{ + int min, max; + + if (is_compat()) { + min = x32_min; + max = x32_max; + } else { + min = x64_min; + max = x64_max; + } + + if (data->reg < min || data->reg >= max) + return -EINVAL; + return 0; +} + +/* + * X32 register encodings. + */ +static unsigned char reg_32[] = { + 0, /* x32_eax */ + 3, /* x32_ebx */ + 1, /* x32_ecx */ + 2, /* x32_edx */ + 6, /* x32_esi */ + 7, /* x32_edi */ + 5, /* x32_ebp */ +}; + +static void trampfd_code_fill_32(struct trampfd *trampfd, char *addr) +{ + char *eaddr = addr + PAGE_SIZE; + int creg = trampfd->code_reg - x32_min; + int dreg = trampfd->data_reg - x32_min; + u32 *code = trampfd->code; + u32 *data = trampfd->data; + int i; + + for (i = 0; i < trampfd->ntrampolines; i++, code++, data++) { + /* endbr32 */ + addr[0] = 0xf3; + addr[1] = 0x0f; + addr[2] = 0x1e; + addr[3] = 0xfb; + + /* mov code, %creg */ + addr[4] = 0xB8 | reg_32[creg]; /* opcode+reg */ + memcpy(&addr[5], &code, sizeof(u32)); /* imm32 */ + + /* mov (%creg), %creg */ + addr[9] = 0x8B; /* opcode */ + addr[10] = 0x00 | /* MODRM.mode */ + reg_32[creg] << 3 | /* MODRM.reg */ + reg_32[creg]; /* MODRM.r/m */ + + /* mov data, %dreg */ + addr[11] = 0xB8 | reg_32[dreg]; /* opcode+reg */ + memcpy(&addr[12], &data, sizeof(u32)); /* imm32 */ + + /* mov (%dreg), %dreg */ + addr[16] = 0x8B; /* opcode */ + addr[17] = 0x00 | /* MODRM.mode */ + reg_32[dreg] << 3 | /* MODRM.reg */ + reg_32[dreg]; /* MODRM.r/m */ + + /* jmp *%creg */ + addr[18] = 0xff; /* opcode */ + addr[19] = 0xe0 | reg_32[creg]; /* MODRM.r/m */ + + /* nopl (%eax) */ + addr[20] = 0x0f; + addr[21] = 0x1f; + addr[22] = 0x00; + + /* pad to 4-byte boundary */ + memset(&addr[23], 0, TRAMPFD_CODE_32_SIZE - 23); + addr += TRAMPFD_CODE_32_SIZE; + } + memset(addr, 0, eaddr - addr); +} + +/* + * X64 register encodings. + */ +static unsigned char reg_64[] = { + 0, /* x64_rax */ + 3, /* x64_rbx */ + 1, /* x64_rcx */ + 2, /* x64_rdx */ + 6, /* x64_rsi */ + 7, /* x64_rdi */ + 5, /* x64_rbp */ + 8, /* x64_r8 */ + 9, /* x64_r9 */ + 10, /* x64_r10 */ + 11, /* x64_r11 */ + 12, /* x64_r12 */ + 13, /* x64_r13 */ + 14, /* x64_r14 */ + 15, /* x64_r15 */ +}; + +static void trampfd_code_fill_64(struct trampfd *trampfd, char *addr) +{ + char *eaddr = addr + PAGE_SIZE; + int creg = trampfd->code_reg - x64_min; + int dreg = trampfd->data_reg - x64_min; + u64 *code = trampfd->code; + u64 *data = trampfd->data; + int i; + + for (i = 0; i < trampfd->ntrampolines; i++, code++, data++) { + /* endbr64 */ + addr[0] = 0xf3; + addr[1] = 0x0f; + addr[2] = 0x1e; + addr[3] = 0xfa; + + /* movabs code, %creg */ + addr[4] = 0x48 | /* REX.W */ + ((reg_64[creg] & 0x8) >> 3); /* REX.B */ + addr[5] = 0xB8 | (reg_64[creg] & 0x7); /* opcode+reg */ + memcpy(&addr[6], &code, sizeof(u64)); /* imm64 */ + + /* movq (%creg), %creg */ + addr[14] = 0x48 | /* REX.W */ + ((reg_64[creg] & 0x8) >> 1) | /* REX.R */ + ((reg_64[creg] & 0x8) >> 3); /* REX.B */ + addr[15] = 0x8B; /* opcode */ + addr[16] = 0x00 | /* MODRM.mode */ + ((reg_64[creg] & 0x7)) << 3 | /* MODRM.reg */ + ((reg_64[creg] & 0x7)); /* MODRM.r/m */ + + /* movabs data, %dreg */ + addr[17] = 0x48 | /* REX.W */ + ((reg_64[dreg] & 0x8) >> 3); /* REX.B */ + addr[18] = 0xB8 | (reg_64[dreg] & 0x7); /* opcode+reg */ + memcpy(&addr[19], &data, sizeof(u64)); /* imm64 */ + + /* movq (%dreg), %dreg */ + addr[27] = 0x48 | /* REX.W */ + ((reg_64[dreg] & 0x8) >> 1) | /* REX.R */ + ((reg_64[dreg] & 0x8) >> 3); /* REX.B */ + addr[28] = 0x8B; /* opcode */ + addr[29] = 0x00 | /* MODRM.mode */ + ((reg_64[dreg] & 0x7)) << 3 | /* MODRM.reg */ + ((reg_64[dreg] & 0x7)); /* MODRM.r/m */ + + /* jmpq *%creg */ + addr[30] = 0x40 | /* REX.W */ + ((reg_64[creg] & 0x8) >> 3); /* REX.B */ + addr[31] = 0xff; /* opcode */ + addr[32] = 0xe0 | (reg_64[creg] & 0x7); /* MODRM.r/m */ + + /* nopl (%rax) */ + addr[33] = 0x0f; + addr[34] = 0x1f; + addr[35] = 0x00; + + /* pad to 8-byte boundary */ + memset(&addr[36], 0, TRAMPFD_CODE_64_SIZE - 36); + addr += TRAMPFD_CODE_64_SIZE; + } + memset(addr, 0, eaddr - addr); +} + +void trampfd_code_fill(struct trampfd *trampfd, char *addr) +{ + if (is_compat()) + trampfd_code_fill_32(trampfd, addr); + else + trampfd_code_fill_64(trampfd, addr); +}