Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp3855896imm; Tue, 29 May 2018 15:21:46 -0700 (PDT) X-Google-Smtp-Source: ADUXVKIUF6e+BVYZjcTLzxfQ9YeyJrf6X0o+CMCQSBeYS+r4pfhfctrnpKdXUcm1+G77BOR6D3A3 X-Received: by 2002:a63:9e42:: with SMTP id r2-v6mr180000pgo.436.1527632506144; Tue, 29 May 2018 15:21:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527632506; cv=none; d=google.com; s=arc-20160816; b=dLJmhKzh0VTUjwtIbdVhlXBjzuZjLeyvC3OJf8rOXNdobL77voOB3E7838Nap28Gm8 acvXmAp6SMu53qcQS+2j1sYzAZnlJ2L1N03RdtTIcIUnQOUwSId5glkBn+aX03bGDVrc wZ1zX9LaicGREv/3cnB36Ktg8Z+sIMYtNjtNhFYu9HQAo2Boxqu+deQdp83+hWzc/WhN bH1Cy4jgw+DTGetBL6lvI8yKcQq+NoTzE95fbfwhcQ4/6dlmkVfoLplJoBi+LLnRB+Jb oMm6VmTku+QbDJf8TqOYyhffPC9MAElQkqfArf8z1d8kfT+IK6VRuttHUbSFPcVcTDJ1 vR0A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=/vkAWNmKiS+L0lNA8E95nZJSwMhERLzb+qsfKNaU7no=; b=KvPPTAYuHX1tZ9nvqLTHmctupisvNHooQKmkOfi4LBeSTGDa4+HlIqk0Q+7cOIrzZw GjEzIZbZ6313aqFcsmHWFYgY5YmiXjw0S2E2EedZAo6Puv4Ag+Y1zBmEAh9GFgo2n9WN tMR68VHLUdPD6Z+TkDsQJ1+5j4hvi/zLyXb2QDe4vUDxzIntKwVIrerAg04aocBY6J5B 4TCoQpDS1R+nYdF7/+WlCNhfrpGD2ifKPH6k8mw0IeQD4v6IERjnvyU8Bo0iBrTPhjH2 TNB9abz415fPPXgVJ3JMjeuCh3z2IsTghtKmbftuO44E+ccAOXWFeRguuroJ+FzrZx0A XZyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=jwl1DugJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u28-v6si33169628pfl.143.2018.05.29.15.21.32; Tue, 29 May 2018 15:21:46 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=jwl1DugJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S968262AbeE2WUl (ORCPT + 99 others); Tue, 29 May 2018 18:20:41 -0400 Received: from mail-pf0-f196.google.com ([209.85.192.196]:41402 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030230AbeE2WR7 (ORCPT ); Tue, 29 May 2018 18:17:59 -0400 Received: by mail-pf0-f196.google.com with SMTP id v63-v6so7941496pfk.8 for ; Tue, 29 May 2018 15:17:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=/vkAWNmKiS+L0lNA8E95nZJSwMhERLzb+qsfKNaU7no=; b=jwl1DugJCJfvnZRj3YL57leKuU+LsAMSAL1TCBZE30elx6t9FXwbxPKpz/DDZ/gpWY aUaHoRsTkFetfZY7EXdY/f/0HIkTWoLwxDIt34M+bAPLdiVLaRooGqKantu1XcS60hex i5wCl1vYRV3nsfK+qoQwS51DcXkSkinu/wHQeO3MQ6hCg+Usr0yVYaHJzKA1PFQkvWaI USo1+lgXaogzhnVa0Sd+vKUOD6auaLIK+W2Nk5nk96gR5FJlMwhfZufRxMnROu51h4Sr h9GkYy8mq6r7Xo2kDzIL+BZuchxtP3YJyzBnohw6Fk0NSeHDak7HZMWjFM2FvyFwCBbp nHoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/vkAWNmKiS+L0lNA8E95nZJSwMhERLzb+qsfKNaU7no=; b=BcVw7P7UoPadY9jiJwEUSWJpXl5O1Bmnifjv9WgO+Mye/rxMwJInqShLl1w9HQPlvX K0pOFVf/32DlrsMgvo2/ay/OkB87nGHwnz+3FxdM3/cEV7r8tTO9EOFHXSJp/YQQ4/9w fI/MI5AoaUG3m8H7UlC9mACYpMHs2BgfFJl0WRRZS3JIp6AYq9O3l0IbZk3BGFOJ4Imr jyDGpoQmdGON012IMTf0zBnWQyYOn14TyU+afkR216nKvUsvyAMirvcfU4OgIRuJV/9U qXuiFGlsFT7wMcbfatv3fcC9C4m5/9nARnAzuvznr5N2WxzoZmWl4RIg9CLuJdqbK1I3 7jZw== X-Gm-Message-State: ALKqPwfKNUdz9LbSMiOijWs5m/mBW8covNyFe73SnAkynSrtv5InFHVd 95dXEYYX7fk99EQbNpkQohqQNQ== X-Received: by 2002:a62:4141:: with SMTP id o62-v6mr199828pfa.111.1527632277972; Tue, 29 May 2018 15:17:57 -0700 (PDT) Received: from skynet.sea.corp.google.com ([2620:15c:17:4:29de:3bb1:1270:e679]) by smtp.gmail.com with ESMTPSA id o84-v6sm78767935pfi.27.2018.05.29.15.17.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 May 2018 15:17:57 -0700 (PDT) From: Thomas Garnier To: kernel-hardening@lists.openwall.com Cc: Thomas Garnier , Steven Rostedt , Ingo Molnar , Thomas Gleixner , "H. Peter Anvin" , x86@kernel.org, Francis Deslauriers , Greg Kroah-Hartman , Andrew Morton , "Peter Zijlstra (Intel)" , Guenter Roeck , nixiaoming , James Hogan , linux-kernel@vger.kernel.org Subject: [PATCH v4 21/27] x86/ftrace: Adapt function tracing for PIE support Date: Tue, 29 May 2018 15:15:22 -0700 Message-Id: <20180529221625.33541-22-thgarnie@google.com> X-Mailer: git-send-email 2.17.0.921.gf22659ad46-goog In-Reply-To: <20180529221625.33541-1-thgarnie@google.com> References: <20180529221625.33541-1-thgarnie@google.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When using -fPIE/PIC with function tracing, the compiler generates a call through the GOT (call *__fentry__@GOTPCREL). This instruction takes 6 bytes instead of 5 on the usual relative call. If PIE is enabled, replace the 6th byte of the GOT call by a 1-byte nop so ftrace can handle the previous 5-bytes as before. Position Independent Executable (PIE) support will allow to extend the KASLR randomization range 0xffffffff80000000. Signed-off-by: Thomas Garnier --- arch/x86/include/asm/ftrace.h | 4 -- arch/x86/include/asm/sections.h | 4 ++ arch/x86/kernel/ftrace.c | 42 +++++++++++++++++- scripts/recordmcount.c | 79 ++++++++++++++++++++++----------- 4 files changed, 97 insertions(+), 32 deletions(-) diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index c18ed65287d5..b1eb3f6735fc 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -24,10 +24,6 @@ extern void __fentry__(void); static inline unsigned long ftrace_call_adjust(unsigned long addr) { - /* - * addr is the address of the mcount call instruction. - * recordmcount does the necessary offset calculation. - */ return addr; } diff --git a/arch/x86/include/asm/sections.h b/arch/x86/include/asm/sections.h index 5c019d23d06b..da3d98bb2bcb 100644 --- a/arch/x86/include/asm/sections.h +++ b/arch/x86/include/asm/sections.h @@ -13,4 +13,8 @@ extern char __end_rodata_hpage_align[]; extern char __entry_trampoline_start[], __entry_trampoline_end[]; #endif +#if defined(CONFIG_X86_PIE) +extern char __start_got[], __end_got[]; +#endif + #endif /* _ASM_X86_SECTIONS_H */ diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 01ebcb6f263e..73b3c30cb7a3 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c @@ -102,7 +102,7 @@ static const unsigned char *ftrace_nop_replace(void) static int ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code, - unsigned const char *new_code) + unsigned const char *new_code) { unsigned char replaced[MCOUNT_INSN_SIZE]; @@ -135,6 +135,44 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code, return 0; } +/* Bytes before call GOT offset */ +const unsigned char got_call_preinsn[] = { 0xff, 0x15 }; + +static int +ftrace_modify_initial_code(unsigned long ip, unsigned const char *old_code, + unsigned const char *new_code) +{ + unsigned char replaced[MCOUNT_INSN_SIZE + 1]; + + ftrace_expected = old_code; + + /* + * If PIE is not enabled or no GOT call was found, default to the + * original approach to code modification. + */ + if (!IS_ENABLED(CONFIG_X86_PIE) || + probe_kernel_read(replaced, (void *)ip, sizeof(replaced)) || + memcmp(replaced, got_call_preinsn, sizeof(got_call_preinsn))) + return ftrace_modify_code_direct(ip, old_code, new_code); + + /* + * Build a nop slide with a 5-byte nop and 1-byte nop to keep the ftrace + * hooking algorithm working with the expected 5 bytes instruction. + */ + memcpy(replaced, new_code, MCOUNT_INSN_SIZE); + replaced[MCOUNT_INSN_SIZE] = ideal_nops[1][0]; + + ip = text_ip_addr(ip); + + if (probe_kernel_write((void *)ip, replaced, sizeof(replaced))) + return -EPERM; + + sync_core(); + + return 0; + +} + int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { @@ -153,7 +191,7 @@ int ftrace_make_nop(struct module *mod, * just modify the code directly. */ if (addr == MCOUNT_ADDR) - return ftrace_modify_code_direct(rec->ip, old, new); + return ftrace_modify_initial_code(rec->ip, old, new); ftrace_expected = NULL; diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 895c40e8679f..aa71b912958d 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -171,33 +171,9 @@ umalloc(size_t size) return addr; } -static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; -static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; -static unsigned char *ideal_nop; - static char rel_type_nop; - static int (*make_nop)(void *map, size_t const offset); - -static int make_nop_x86(void *map, size_t const offset) -{ - uint32_t *ptr; - unsigned char *op; - - /* Confirm we have 0xe8 0x0 0x0 0x0 0x0 */ - ptr = map + offset; - if (*ptr != 0) - return -1; - - op = map + offset - 1; - if (*op != 0xe8) - return -1; - - /* convert to nop */ - ulseek(fd_map, offset - 1, SEEK_SET); - uwrite(fd_map, ideal_nop, 5); - return 0; -} +static unsigned char *ideal_nop; static unsigned char ideal_nop4_arm_le[4] = { 0x00, 0x00, 0xa0, 0xe1 }; /* mov r0, r0 */ static unsigned char ideal_nop4_arm_be[4] = { 0xe1, 0xa0, 0x00, 0x00 }; /* mov r0, r0 */ @@ -447,6 +423,50 @@ static void MIPS64_r_info(Elf64_Rel *const rp, unsigned sym, unsigned type) }).r_info; } +static unsigned char ideal_nop5_x86_64[5] = { 0x0f, 0x1f, 0x44, 0x00, 0x00 }; +static unsigned char ideal_nop6_x86_64[6] = { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 }; +static unsigned char ideal_nop5_x86_32[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 }; +static size_t ideal_nop_x86_size; + +static unsigned char stub_default_x86[2] = { 0xe8, 0x00 }; /* call relative */ +static unsigned char stub_got_x86[3] = { 0xff, 0x15, 0x00 }; /* call .got */ +static unsigned char *stub_x86; +static size_t stub_x86_size; + +static int make_nop_x86(void *map, size_t const offset) +{ + uint32_t *ptr; + size_t stub_offset = offset - stub_x86_size; + + /* confirm we have the expected stub */ + ptr = map + stub_offset; + if (memcmp(ptr, stub_x86, stub_x86_size)) { + return -1; + } + + /* convert to nop */ + ulseek(fd_map, stub_offset, SEEK_SET); + uwrite(fd_map, ideal_nop, ideal_nop_x86_size); + return 0; +} + +/* Swap the stub and nop for a got call if the binary is built with PIE */ +static int is_fake_mcount_x86_x64(Elf64_Rel const *rp) +{ + if (ELF64_R_TYPE(rp->r_info) == R_X86_64_GOTPCREL) { + ideal_nop = ideal_nop6_x86_64; + ideal_nop_x86_size = sizeof(ideal_nop6_x86_64); + stub_x86 = stub_got_x86; + stub_x86_size = sizeof(stub_got_x86); + mcount_adjust_64 = 1 - stub_x86_size; + } + + /* Once the relocation was checked, rollback to default */ + is_fake_mcount64 = fn_is_fake_mcount64; + return is_fake_mcount64(rp); +} + + static void do_file(char const *const fname) { @@ -509,6 +529,9 @@ do_file(char const *const fname) rel_type_nop = R_386_NONE; make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_32; + ideal_nop_x86_size = sizeof(ideal_nop5_x86_32); + stub_x86 = stub_default_x86; + stub_x86_size = sizeof(stub_default_x86); mcount_adjust_32 = -1; break; case EM_ARM: reltype = R_ARM_ABS32; @@ -533,9 +556,13 @@ do_file(char const *const fname) case EM_X86_64: make_nop = make_nop_x86; ideal_nop = ideal_nop5_x86_64; + ideal_nop_x86_size = sizeof(ideal_nop5_x86_64); + stub_x86 = stub_default_x86; + stub_x86_size = sizeof(stub_default_x86); reltype = R_X86_64_64; rel_type_nop = R_X86_64_NONE; - mcount_adjust_64 = -1; + is_fake_mcount64 = is_fake_mcount_x86_x64; + mcount_adjust_64 = 1 - stub_x86_size; break; } /* end switch */ -- 2.17.0.921.gf22659ad46-goog