Message ID | 20240127044124.57594-2-jinghao7@illinois.edu |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-41071-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2395:b0:106:343:edcb with SMTP id gw21csp321739dyb; Fri, 26 Jan 2024 21:17:19 -0800 (PST) X-Google-Smtp-Source: AGHT+IEeEmyvskhT8ld9Pcb5fTIatUBjY2WSMY4GG6OZxtdPOg/QOusOpaXdEmEb0e+iMdZcx5dp X-Received: by 2002:a17:907:10c4:b0:a31:8944:2cf6 with SMTP id rv4-20020a17090710c400b00a3189442cf6mr1558809ejb.8.1706332639390; Fri, 26 Jan 2024 21:17:19 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1706332639; cv=pass; d=google.com; s=arc-20160816; b=OYujydypv+sbtvjDwmEjx9rSoSvgx68rTKEFTUhx0UYqOkdOEoYOjmM2InLCbAxiHc 5H0dvCPKr7d8urtXEQNVtuMr7qStAZjXGIOSWW+UWgejFLRh3CZpk7FJ9/TwTgIMn+Rh akwBPZzmGtziEgb8aiHp9PzEeuZQ/csCCBDN+6Zw1TtchMXsZHckF0TJuKNAx6EpVarL c7fPGKENbxcjBRPL+DQHnuk7iVmXp+L9xI6/cyo+6MvIpmBG8IMRgcQHy6vVu02ar/v1 YVil2t4q9ldoEwreVdJ2wOgcbQxgTNIc8cBAgjo31Lx1XhABIlpHJgnCkJRfEOpGUMJF YESg== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=LfUQSwHCxqCuC+PAruuCClPENWlIgNi29wcXxn4Mv64=; fh=ihYqxaSOeWkOf/TXzhQINhK9J+TBcUU0y3bPV7PZkzo=; b=mciXMAXugAreRVcBla0ROH0TOewmreL7mryLD8JkMZEXF1aqwTRwN474uQuOTX3+tU PBqaHnJe/Lrc6IA1cIV9h1/i52FpY0gHbhIFX6BzypwhjEzZhq3dQvXz0yuHmyaB5Kj0 aGOJSnC8x2lKT8nfa/weapXbG0VEPtb+J/JTbNlJd74ckXOvYxNb000d7iPkwnOMg3bt oRlwfnSGE/wBUfma3mAZi54+AqTTYPNANI6OKrRIwsIkr+lU+4hruF+3JFU6XncsrRVs W6M+BXS9SZNP3h9Cw1YyWxq/VKfsznudxHsV79Xf84p2V+G0Hl/JA+TuUMbz1f8u6R0S V6HQ== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@illinois.edu header.s=campusrelays header.b=K23S8VkV; arc=pass (i=1 spf=pass spfdomain=illinois.edu dkim=pass dkdomain=illinois.edu dmarc=pass fromdomain=illinois.edu); spf=pass (google.com: domain of linux-kernel+bounces-41071-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-41071-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=illinois.edu Received: from am.mirrors.kernel.org (am.mirrors.kernel.org. [2604:1380:4601:e00::3]) by mx.google.com with ESMTPS id r19-20020a1709067fd300b00a32c31a2846si1257004ejs.473.2024.01.26.21.17.19 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Jan 2024 21:17:19 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-41071-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) client-ip=2604:1380:4601:e00::3; Authentication-Results: mx.google.com; dkim=pass header.i=@illinois.edu header.s=campusrelays header.b=K23S8VkV; arc=pass (i=1 spf=pass spfdomain=illinois.edu dkim=pass dkdomain=illinois.edu dmarc=pass fromdomain=illinois.edu); spf=pass (google.com: domain of linux-kernel+bounces-41071-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:4601:e00::3 as permitted sender) smtp.mailfrom="linux-kernel+bounces-41071-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=illinois.edu Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by am.mirrors.kernel.org (Postfix) with ESMTPS id 0420F1F24BC5 for <ouuuleilei@gmail.com>; Sat, 27 Jan 2024 05:17:19 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3E5BA14A8D; Sat, 27 Jan 2024 05:17:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=illinois.edu header.i=@illinois.edu header.b="K23S8VkV" Received: from mx0b-00007101.pphosted.com (mx0b-00007101.pphosted.com [148.163.139.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCE5C7F; Sat, 27 Jan 2024 05:16:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.139.28 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706332621; cv=none; b=A3LQX9NADomKeEjvakIGt1PzX3MsgZyjvy3yKJwCyq2CuE3rqzEDjZP11yfy6j86njTXEQ5G0PQ5GKO6DJat+i+4reT+n6ewZoNx+ZYqyY/zJSHBkoy87VpZQm4+Bp+0h/YQAdvzh29+Z1bxSMip2on6aOep3Xqg6F9BT+gD88A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706332621; c=relaxed/simple; bh=2oy7FXJoc1dYh+Zik8b/XfAW1rAHXWBj27ZopQY1g/0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EX2g2DFqCyc8nFLyG+LpUW8eGxR80J0DTSDHGn8HQZSpEGeNLMJvRAN6KqR8mhmOg4rVBa6juO4yfMXaAusH3yOvqEhBM8eIPGVlnzn0NFuvq3lqAA0peamKap3w4G/H4R/ByL5rjlWhE6WGwLRC3uv2sr4QNQa0esJ1eQzhr54= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=illinois.edu; spf=pass smtp.mailfrom=illinois.edu; dkim=pass (2048-bit key) header.d=illinois.edu header.i=@illinois.edu header.b=K23S8VkV; arc=none smtp.client-ip=148.163.139.28 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=illinois.edu Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=illinois.edu Received: from pps.filterd (m0166258.ppops.net [127.0.0.1]) by mx0b-00007101.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 40R4DcXU003200; Sat, 27 Jan 2024 04:41:44 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=illinois.edu; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding; s=campusrelays; bh=LfUQSwHCxqCuC+PAruuCClPENWlIgNi29wcXxn4Mv64=; b=K23S8VkVEdyFCCxuhO5+cp457qW1pUtxhAVhXYi8gPmbUu1xtMhyiN0TyUpQT3BiE1AF LFvsSi3FkWNDmQmvLobHEInf7UXmhbIe2jNj4gMNkIc6Z/5LcQxTrCmfdkeRER1vEpHs 3dTA2T0MDzs8GqAtNRkKkZ8UztimTaxNePA+kzDPny9nQgNZzPheMdGGce1Enc4Q4qKE 23fNmhSBR8HSWfFUrBtxW/BNu7VMDidRSzOizP7uc1e8bNu+pV5SJp02I3OoFHlyN25v /99odRmHw3OTJPQwc3j99/0VGRjVXUNhhF1TzNkrvH6jQ5Ro0psHpW/rZwSBodYzo8rK ug== Received: from pps.reinject (localhost [127.0.0.1]) by mx0b-00007101.pphosted.com (PPS) with ESMTPS id 3vvr6sgk2q-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 27 Jan 2024 04:41:43 +0000 Received: from m0166258.ppops.net (m0166258.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 40R4fZW9019561; Sat, 27 Jan 2024 04:41:43 GMT Received: from localhost.localdomain (oasis.cs.illinois.edu [130.126.137.13]) by mx0b-00007101.pphosted.com (PPS) with ESMTP id 3vvr6sgk26-2; Sat, 27 Jan 2024 04:41:43 +0000 From: Jinghao Jia <jinghao7@illinois.edu> To: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>, Thomas Gleixner <tglx@linutronix.de>, Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>, Dave Hansen <dave.hansen@linux.intel.com>, x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>, Peter Zijlstra <peterz@infradead.org> Cc: linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org, Jinghao Jia <jinghao7@illinois.edu> Subject: [RFC PATCH 1/2] x86/kprobes: Prohibit kprobing on INT and UD Date: Fri, 26 Jan 2024 22:41:23 -0600 Message-ID: <20240127044124.57594-2-jinghao7@illinois.edu> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240127044124.57594-1-jinghao7@illinois.edu> References: <20240127044124.57594-1-jinghao7@illinois.edu> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Proofpoint-GUID: 6AcGzVALhN6jMOtlsY4LV4ujrRjLfrRA X-Proofpoint-ORIG-GUID: ZskEOsMGNoEg_vC6oFkBJuWgxorMRFdc X-Spam-Details: rule=cautious_plus_nq_notspam policy=cautious_plus_nq score=0 impostorscore=0 spamscore=0 malwarescore=0 priorityscore=1501 clxscore=1015 mlxlogscore=789 phishscore=0 suspectscore=0 lowpriorityscore=0 mlxscore=0 bulkscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2311290000 definitions=main-2401270033 X-Spam-Score: 0 X-Spam-OrigSender: jinghao7@illinois.edu X-Spam-Bar: X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1789219453983231434 X-GMAIL-MSGID: 1789219453983231434 |
Series |
x86/kprobes: add exception opcode detector and boost more opcodes
|
|
Commit Message
Jinghao Jia
Jan. 27, 2024, 4:41 a.m. UTC
Both INTs (INT n, INT1, INT3, INTO) and UDs (UD0, UD1, UD2) serve
special purposes in the kernel, e.g., INT3 is used by KGDB and UD2 is
involved in LLVM-KCFI instrumentation. At the same time, attaching
kprobes on these instructions (particularly UDs) will pollute the stack
trace dumped in the kernel ring buffer, since the exception is triggered
in the copy buffer rather than the original location.
Check for INTs and UDs in can_probe and reject any kprobes trying to
attach to these instructions.
Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Jinghao Jia <jinghao7@illinois.edu>
---
arch/x86/kernel/kprobes/core.c | 33 ++++++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)
Comments
On 1/26/2024 8:41 PM, Jinghao Jia wrote: > Both INTs (INT n, INT1, INT3, INTO) and UDs (UD0, UD1, UD2) serve > special purposes in the kernel, e.g., INT3 is used by KGDB and UD2 is > involved in LLVM-KCFI instrumentation. At the same time, attaching > kprobes on these instructions (particularly UDs) will pollute the stack > trace dumped in the kernel ring buffer, since the exception is triggered > in the copy buffer rather than the original location. > > Check for INTs and UDs in can_probe and reject any kprobes trying to > attach to these instructions. > > Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> > Signed-off-by: Jinghao Jia <jinghao7@illinois.edu> > --- > arch/x86/kernel/kprobes/core.c | 33 ++++++++++++++++++++++++++------- > 1 file changed, 26 insertions(+), 7 deletions(-) > > diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c > index e8babebad7b8..792b38d22126 100644 > --- a/arch/x86/kernel/kprobes/core.c > +++ b/arch/x86/kernel/kprobes/core.c > @@ -252,6 +252,22 @@ unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long add > return __recover_probed_insn(buf, addr); > } > > +static inline int is_exception_insn(struct insn *insn) s/int/bool > +{ > + if (insn->opcode.bytes[0] == 0x0f) { > + /* UD0 / UD1 / UD2 */ > + return insn->opcode.bytes[1] == 0xff || > + insn->opcode.bytes[1] == 0xb9 || > + insn->opcode.bytes[1] == 0x0b; > + } else { > + /* INT3 / INT n / INTO / INT1 */ > + return insn->opcode.bytes[0] == 0xcc || > + insn->opcode.bytes[0] == 0xcd || > + insn->opcode.bytes[0] == 0xce || > + insn->opcode.bytes[0] == 0xf1; > + } > +} > + > /* Check if paddr is at an instruction boundary */ > static int can_probe(unsigned long paddr) > { > @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) > #endif > addr += insn.length; > } > + __addr = recover_probed_instruction(buf, addr); > + if (!__addr) > + return 0; > + > + if (insn_decode_kernel(&insn, (void *)__addr) < 0) > + return 0; > + > + if (is_exception_insn(&insn)) > + return 0; > + > if (IS_ENABLED(CONFIG_CFI_CLANG)) { > /* > * The compiler generates the following instruction sequence > @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) > * Also, these movl and addl are used for showing expected > * type. So those must not be touched. > */ > - __addr = recover_probed_instruction(buf, addr); > - if (!__addr) > - return 0; > - > - if (insn_decode_kernel(&insn, (void *)__addr) < 0) > - return 0; > - > if (insn.opcode.value == 0xBA) > offset = 12; > else if (insn.opcode.value == 0x3)
On Fri, 26 Jan 2024 22:41:23 -0600 Jinghao Jia <jinghao7@illinois.edu> wrote: > Both INTs (INT n, INT1, INT3, INTO) and UDs (UD0, UD1, UD2) serve > special purposes in the kernel, e.g., INT3 is used by KGDB and UD2 is > involved in LLVM-KCFI instrumentation. At the same time, attaching > kprobes on these instructions (particularly UDs) will pollute the stack > trace dumped in the kernel ring buffer, since the exception is triggered > in the copy buffer rather than the original location. > > Check for INTs and UDs in can_probe and reject any kprobes trying to > attach to these instructions. > Thanks for implement this check! > Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> > Signed-off-by: Jinghao Jia <jinghao7@illinois.edu> > --- > arch/x86/kernel/kprobes/core.c | 33 ++++++++++++++++++++++++++------- > 1 file changed, 26 insertions(+), 7 deletions(-) > > diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c > index e8babebad7b8..792b38d22126 100644 > --- a/arch/x86/kernel/kprobes/core.c > +++ b/arch/x86/kernel/kprobes/core.c > @@ -252,6 +252,22 @@ unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long add > return __recover_probed_insn(buf, addr); > } > > +static inline int is_exception_insn(struct insn *insn) > +{ > + if (insn->opcode.bytes[0] == 0x0f) { > + /* UD0 / UD1 / UD2 */ > + return insn->opcode.bytes[1] == 0xff || > + insn->opcode.bytes[1] == 0xb9 || > + insn->opcode.bytes[1] == 0x0b; > + } else { If "else" block just return, you don't need this "else". bool func() { if (cond) return ... return ... } Is preferrable because this puts "return val" always at the end of non-void function. > + /* INT3 / INT n / INTO / INT1 */ > + return insn->opcode.bytes[0] == 0xcc || > + insn->opcode.bytes[0] == 0xcd || > + insn->opcode.bytes[0] == 0xce || > + insn->opcode.bytes[0] == 0xf1; > + } > +} > + > /* Check if paddr is at an instruction boundary */ > static int can_probe(unsigned long paddr) > { > @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) > #endif > addr += insn.length; > } > + __addr = recover_probed_instruction(buf, addr); > + if (!__addr) > + return 0; > + > + if (insn_decode_kernel(&insn, (void *)__addr) < 0) > + return 0; > + > + if (is_exception_insn(&insn)) > + return 0; > + Please don't put this outside of decoding loop. You should put these in the loop which decodes the instruction from the beginning of the function. Since the x86 instrcution is variable length, can_probe() needs to check whether that the address is instruction boundary and decodable. Thank you, > if (IS_ENABLED(CONFIG_CFI_CLANG)) { > /* > * The compiler generates the following instruction sequence > @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) > * Also, these movl and addl are used for showing expected > * type. So those must not be touched. > */ > - __addr = recover_probed_instruction(buf, addr); > - if (!__addr) > - return 0; > - > - if (insn_decode_kernel(&insn, (void *)__addr) < 0) > - return 0; > - > if (insn.opcode.value == 0xBA) > offset = 12; > else if (insn.opcode.value == 0x3) > -- > 2.43.0 >
On 1/27/24 13:47, Xin Li wrote: > On 1/26/2024 8:41 PM, Jinghao Jia wrote: >> Both INTs (INT n, INT1, INT3, INTO) and UDs (UD0, UD1, UD2) serve >> special purposes in the kernel, e.g., INT3 is used by KGDB and UD2 is >> involved in LLVM-KCFI instrumentation. At the same time, attaching >> kprobes on these instructions (particularly UDs) will pollute the stack >> trace dumped in the kernel ring buffer, since the exception is triggered >> in the copy buffer rather than the original location. >> >> Check for INTs and UDs in can_probe and reject any kprobes trying to >> attach to these instructions. >> >> Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> >> Signed-off-by: Jinghao Jia <jinghao7@illinois.edu> >> --- >> arch/x86/kernel/kprobes/core.c | 33 ++++++++++++++++++++++++++------- >> 1 file changed, 26 insertions(+), 7 deletions(-) >> >> diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c >> index e8babebad7b8..792b38d22126 100644 >> --- a/arch/x86/kernel/kprobes/core.c >> +++ b/arch/x86/kernel/kprobes/core.c >> @@ -252,6 +252,22 @@ unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long add >> return __recover_probed_insn(buf, addr); >> } >> +static inline int is_exception_insn(struct insn *insn) > > s/int/bool > Oh yes, the return type should be bool. Thanks for pointing out! --Jinghao >> +{ >> + if (insn->opcode.bytes[0] == 0x0f) { >> + /* UD0 / UD1 / UD2 */ >> + return insn->opcode.bytes[1] == 0xff || >> + insn->opcode.bytes[1] == 0xb9 || >> + insn->opcode.bytes[1] == 0x0b; >> + } else { >> + /* INT3 / INT n / INTO / INT1 */ >> + return insn->opcode.bytes[0] == 0xcc || >> + insn->opcode.bytes[0] == 0xcd || >> + insn->opcode.bytes[0] == 0xce || >> + insn->opcode.bytes[0] == 0xf1; >> + } >> +} >> + >> /* Check if paddr is at an instruction boundary */ >> static int can_probe(unsigned long paddr) >> { >> @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) >> #endif >> addr += insn.length; >> } >> + __addr = recover_probed_instruction(buf, addr); >> + if (!__addr) >> + return 0; >> + >> + if (insn_decode_kernel(&insn, (void *)__addr) < 0) >> + return 0; >> + >> + if (is_exception_insn(&insn)) >> + return 0; >> + >> if (IS_ENABLED(CONFIG_CFI_CLANG)) { >> /* >> * The compiler generates the following instruction sequence >> @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) >> * Also, these movl and addl are used for showing expected >> * type. So those must not be touched. >> */ >> - __addr = recover_probed_instruction(buf, addr); >> - if (!__addr) >> - return 0; >> - >> - if (insn_decode_kernel(&insn, (void *)__addr) < 0) >> - return 0; >> - >> if (insn.opcode.value == 0xBA) >> offset = 12; >> else if (insn.opcode.value == 0x3) >
On 1/27/24 19:19, Masami Hiramatsu (Google) wrote: > On Fri, 26 Jan 2024 22:41:23 -0600 > Jinghao Jia <jinghao7@illinois.edu> wrote: > >> Both INTs (INT n, INT1, INT3, INTO) and UDs (UD0, UD1, UD2) serve >> special purposes in the kernel, e.g., INT3 is used by KGDB and UD2 is >> involved in LLVM-KCFI instrumentation. At the same time, attaching >> kprobes on these instructions (particularly UDs) will pollute the stack >> trace dumped in the kernel ring buffer, since the exception is triggered >> in the copy buffer rather than the original location. >> >> Check for INTs and UDs in can_probe and reject any kprobes trying to >> attach to these instructions. >> > > Thanks for implement this check! > You are very welcome :) > >> Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> >> Signed-off-by: Jinghao Jia <jinghao7@illinois.edu> >> --- >> arch/x86/kernel/kprobes/core.c | 33 ++++++++++++++++++++++++++------- >> 1 file changed, 26 insertions(+), 7 deletions(-) >> >> diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c >> index e8babebad7b8..792b38d22126 100644 >> --- a/arch/x86/kernel/kprobes/core.c >> +++ b/arch/x86/kernel/kprobes/core.c >> @@ -252,6 +252,22 @@ unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long add >> return __recover_probed_insn(buf, addr); >> } >> >> +static inline int is_exception_insn(struct insn *insn) >> +{ >> + if (insn->opcode.bytes[0] == 0x0f) { >> + /* UD0 / UD1 / UD2 */ >> + return insn->opcode.bytes[1] == 0xff || >> + insn->opcode.bytes[1] == 0xb9 || >> + insn->opcode.bytes[1] == 0x0b; >> + } else { > > If "else" block just return, you don't need this "else". > > bool func() > { > if (cond) > return ... > > return ... > } > > Is preferrable because this puts "return val" always at the end of non-void > function. > I will fix this in the v2. >> + /* INT3 / INT n / INTO / INT1 */ >> + return insn->opcode.bytes[0] == 0xcc || >> + insn->opcode.bytes[0] == 0xcd || >> + insn->opcode.bytes[0] == 0xce || >> + insn->opcode.bytes[0] == 0xf1; >> + } >> +} >> + >> /* Check if paddr is at an instruction boundary */ >> static int can_probe(unsigned long paddr) >> { >> @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) >> #endif >> addr += insn.length; >> } >> + __addr = recover_probed_instruction(buf, addr); >> + if (!__addr) >> + return 0; >> + >> + if (insn_decode_kernel(&insn, (void *)__addr) < 0) >> + return 0; >> + >> + if (is_exception_insn(&insn)) >> + return 0; >> + > > Please don't put this outside of decoding loop. You should put these in > the loop which decodes the instruction from the beginning of the function. > Since the x86 instrcution is variable length, can_probe() needs to check > whether that the address is instruction boundary and decodable. > > Thank you, If my understanding is correct then this is trying to decode the kprobe target instruction, given that it is after the main decoding loop. Here I hoisted the decoding logic out of the if(IS_ENABLED(CONFIG_CFI_CLANG)) block so that we do not need to decode the same instruction twice. I left the main decoding loop unchanged so it is still decoding the function from the start and should handle instruction boundaries. Are there any caveats that I missed? --Jinghao > >> if (IS_ENABLED(CONFIG_CFI_CLANG)) { >> /* >> * The compiler generates the following instruction sequence >> @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) >> * Also, these movl and addl are used for showing expected >> * type. So those must not be touched. >> */ >> - __addr = recover_probed_instruction(buf, addr); >> - if (!__addr) >> - return 0; >> - >> - if (insn_decode_kernel(&insn, (void *)__addr) < 0) >> - return 0; >> - >> if (insn.opcode.value == 0xBA) >> offset = 12; >> else if (insn.opcode.value == 0x3) >> -- >> 2.43.0 >> > >
On Sun, 28 Jan 2024 15:25:59 -0600 Jinghao Jia <jinghao7@illinois.edu> wrote: > >> /* Check if paddr is at an instruction boundary */ > >> static int can_probe(unsigned long paddr) > >> { > >> @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) > >> #endif > >> addr += insn.length; > >> } > >> + __addr = recover_probed_instruction(buf, addr); > >> + if (!__addr) > >> + return 0; > >> + > >> + if (insn_decode_kernel(&insn, (void *)__addr) < 0) > >> + return 0; > >> + > >> + if (is_exception_insn(&insn)) > >> + return 0; > >> + > > > > Please don't put this outside of decoding loop. You should put these in > > the loop which decodes the instruction from the beginning of the function. > > Since the x86 instrcution is variable length, can_probe() needs to check > > whether that the address is instruction boundary and decodable. > > > > Thank you, > > If my understanding is correct then this is trying to decode the kprobe > target instruction, given that it is after the main decoding loop. Here I > hoisted the decoding logic out of the if(IS_ENABLED(CONFIG_CFI_CLANG)) > block so that we do not need to decode the same instruction twice. I left > the main decoding loop unchanged so it is still decoding the function from > the start and should handle instruction boundaries. Are there any caveats > that I missed? Ah, sorry I misread the patch. You're correct! This is a good place to do that. But hmm, I think we should add another patch to check the addr == paddr soon after the loop so that we will avoid decoding. Thank you, > > --Jinghao > > > > >> if (IS_ENABLED(CONFIG_CFI_CLANG)) { > >> /* > >> * The compiler generates the following instruction sequence > >> @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) > >> * Also, these movl and addl are used for showing expected > >> * type. So those must not be touched. > >> */ > >> - __addr = recover_probed_instruction(buf, addr); > >> - if (!__addr) > >> - return 0; > >> - > >> - if (insn_decode_kernel(&insn, (void *)__addr) < 0) > >> - return 0; > >> - > >> if (insn.opcode.value == 0xBA) > >> offset = 12; > >> else if (insn.opcode.value == 0x3) > >> -- > >> 2.43.0 > >> > > > >
On 1/29/24 19:44, Masami Hiramatsu (Google) wrote: > On Sun, 28 Jan 2024 15:25:59 -0600 > Jinghao Jia <jinghao7@illinois.edu> wrote: > >>>> /* Check if paddr is at an instruction boundary */ >>>> static int can_probe(unsigned long paddr) >>>> { >>>> @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) >>>> #endif >>>> addr += insn.length; >>>> } >>>> + __addr = recover_probed_instruction(buf, addr); >>>> + if (!__addr) >>>> + return 0; >>>> + >>>> + if (insn_decode_kernel(&insn, (void *)__addr) < 0) >>>> + return 0; >>>> + >>>> + if (is_exception_insn(&insn)) >>>> + return 0; >>>> + >>> >>> Please don't put this outside of decoding loop. You should put these in >>> the loop which decodes the instruction from the beginning of the function. >>> Since the x86 instrcution is variable length, can_probe() needs to check >>> whether that the address is instruction boundary and decodable. >>> >>> Thank you, >> >> If my understanding is correct then this is trying to decode the kprobe >> target instruction, given that it is after the main decoding loop. Here I >> hoisted the decoding logic out of the if(IS_ENABLED(CONFIG_CFI_CLANG)) >> block so that we do not need to decode the same instruction twice. I left >> the main decoding loop unchanged so it is still decoding the function from >> the start and should handle instruction boundaries. Are there any caveats >> that I missed? > > Ah, sorry I misread the patch. You're correct! > This is a good place to do that. > > But hmm, I think we should add another patch to check the addr == paddr > soon after the loop so that we will avoid decoding. > > Thank you, > Yes, that makes sense to me. At the same time, I'm also thinking about changing the return type of can_probe() to bool, since we are just using int as bool in this context. --Jinghao >> >> --Jinghao >> >>> >>>> if (IS_ENABLED(CONFIG_CFI_CLANG)) { >>>> /* >>>> * The compiler generates the following instruction sequence >>>> @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) >>>> * Also, these movl and addl are used for showing expected >>>> * type. So those must not be touched. >>>> */ >>>> - __addr = recover_probed_instruction(buf, addr); >>>> - if (!__addr) >>>> - return 0; >>>> - >>>> - if (insn_decode_kernel(&insn, (void *)__addr) < 0) >>>> - return 0; >>>> - >>>> if (insn.opcode.value == 0xBA) >>>> offset = 12; >>>> else if (insn.opcode.value == 0x3) >>>> -- >>>> 2.43.0 >>>> >>> >>> > >
On Mon, 29 Jan 2024 20:50:39 -0600 Jinghao Jia <jinghao7@illinois.edu> wrote: > On 1/29/24 19:44, Masami Hiramatsu (Google) wrote: > > On Sun, 28 Jan 2024 15:25:59 -0600 > > Jinghao Jia <jinghao7@illinois.edu> wrote: > > > >>>> /* Check if paddr is at an instruction boundary */ > >>>> static int can_probe(unsigned long paddr) > >>>> { > >>>> @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) > >>>> #endif > >>>> addr += insn.length; > >>>> } > >>>> + __addr = recover_probed_instruction(buf, addr); > >>>> + if (!__addr) > >>>> + return 0; > >>>> + > >>>> + if (insn_decode_kernel(&insn, (void *)__addr) < 0) > >>>> + return 0; > >>>> + > >>>> + if (is_exception_insn(&insn)) > >>>> + return 0; > >>>> + > >>> > >>> Please don't put this outside of decoding loop. You should put these in > >>> the loop which decodes the instruction from the beginning of the function. > >>> Since the x86 instrcution is variable length, can_probe() needs to check > >>> whether that the address is instruction boundary and decodable. > >>> > >>> Thank you, > >> > >> If my understanding is correct then this is trying to decode the kprobe > >> target instruction, given that it is after the main decoding loop. Here I > >> hoisted the decoding logic out of the if(IS_ENABLED(CONFIG_CFI_CLANG)) > >> block so that we do not need to decode the same instruction twice. I left > >> the main decoding loop unchanged so it is still decoding the function from > >> the start and should handle instruction boundaries. Are there any caveats > >> that I missed? > > > > Ah, sorry I misread the patch. You're correct! > > This is a good place to do that. > > > > But hmm, I think we should add another patch to check the addr == paddr > > soon after the loop so that we will avoid decoding. > > > > Thank you, > > > > Yes, that makes sense to me. At the same time, I'm also thinking about > changing the return type of can_probe() to bool, since we are just using > int as bool in this context. Yes, that is also a good change :) Thank you, > > --Jinghao > > >> > >> --Jinghao > >> > >>> > >>>> if (IS_ENABLED(CONFIG_CFI_CLANG)) { > >>>> /* > >>>> * The compiler generates the following instruction sequence > >>>> @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) > >>>> * Also, these movl and addl are used for showing expected > >>>> * type. So those must not be touched. > >>>> */ > >>>> - __addr = recover_probed_instruction(buf, addr); > >>>> - if (!__addr) > >>>> - return 0; > >>>> - > >>>> - if (insn_decode_kernel(&insn, (void *)__addr) < 0) > >>>> - return 0; > >>>> - > >>>> if (insn.opcode.value == 0xBA) > >>>> offset = 12; > >>>> else if (insn.opcode.value == 0x3) > >>>> -- > >>>> 2.43.0 > >>>> > >>> > >>> > > > >
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index e8babebad7b8..792b38d22126 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -252,6 +252,22 @@ unsigned long recover_probed_instruction(kprobe_opcode_t *buf, unsigned long add return __recover_probed_insn(buf, addr); } +static inline int is_exception_insn(struct insn *insn) +{ + if (insn->opcode.bytes[0] == 0x0f) { + /* UD0 / UD1 / UD2 */ + return insn->opcode.bytes[1] == 0xff || + insn->opcode.bytes[1] == 0xb9 || + insn->opcode.bytes[1] == 0x0b; + } else { + /* INT3 / INT n / INTO / INT1 */ + return insn->opcode.bytes[0] == 0xcc || + insn->opcode.bytes[0] == 0xcd || + insn->opcode.bytes[0] == 0xce || + insn->opcode.bytes[0] == 0xf1; + } +} + /* Check if paddr is at an instruction boundary */ static int can_probe(unsigned long paddr) { @@ -294,6 +310,16 @@ static int can_probe(unsigned long paddr) #endif addr += insn.length; } + __addr = recover_probed_instruction(buf, addr); + if (!__addr) + return 0; + + if (insn_decode_kernel(&insn, (void *)__addr) < 0) + return 0; + + if (is_exception_insn(&insn)) + return 0; + if (IS_ENABLED(CONFIG_CFI_CLANG)) { /* * The compiler generates the following instruction sequence @@ -308,13 +334,6 @@ static int can_probe(unsigned long paddr) * Also, these movl and addl are used for showing expected * type. So those must not be touched. */ - __addr = recover_probed_instruction(buf, addr); - if (!__addr) - return 0; - - if (insn_decode_kernel(&insn, (void *)__addr) < 0) - return 0; - if (insn.opcode.value == 0xBA) offset = 12; else if (insn.opcode.value == 0x3)