Received: by 2002:a05:6358:9144:b0:117:f937:c515 with SMTP id r4csp3759579rwr; Sat, 22 Apr 2023 11:06:39 -0700 (PDT) X-Google-Smtp-Source: AKy350bvwGyxNAuk+DWB99pXLeg7V6beHWdNiH2+kgp1aC0dn/Rv30kEL8BnMEzQiHovurMxXnjL X-Received: by 2002:a05:6a00:1d0b:b0:624:bf7e:9d8c with SMTP id a11-20020a056a001d0b00b00624bf7e9d8cmr9647000pfx.1.1682186799251; Sat, 22 Apr 2023 11:06:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1682186799; cv=none; d=google.com; s=arc-20160816; b=cY03WoSbqdzPxevvPaHNipWx02Wvx5xMomjLda/z1ikgOiMn0lrgtLbeiaNRsuWZkB Aaesdqzwvrw6MSJcktKtUETpDIajW6i8vohBxUgygiEK4DVPzP4ma6S4+ugXjcTFxtHV p0hbtbNVnmbyxU1wgS+fts1sj51A0puQKbtJRX79ZLVe/++69WOT46XK+hEYPrM8HSSI JpbFYlJ0gqZVAAshtTAaGzfH7xqCEJFtBOV+s6KV8bMBpX6IsLg5dVDq5aI8eyO9NUSa Veu4z8WnvvUENvA9VPYfDw9lRMGD1DQzA7X9hOoOFv7KF8yB/EkGTeRn01c/vqxDPvPo GZqg== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=YY6llu7mmMflmKLFThNvzd63wJV2sXho9hlM/VlENPQ=; b=nOIoAGfn0/RMT6d2saxSfJUMvIqqKL9rCI7Ad/Lu9m6ZFBN0mAaKKzDKO2Sa69u0UM 9E/sB7Dg47jWN8FFxrjYcDia/IMFQWI/XCW+DWlV/WENRXSiuvf0cKWgtGUe95VNJkny 2UKONvEiDEj0lVEzA69wkfZwfnuUm3j0mmRyjce9DJfd2+TyngbEzOeOW/7dk6YPnBbo +Q9uIm1TnsGnNkYUWqRVSN2dh9ScYDI8SCCoYEevtnB6RJJPxeXETe7xW0ss/V1Fh5Rb +g2WExadW7YIslCBwsIRjJ5bITk5yQz2nj5dclPFumgAD6bUqUV3NYlc1/QGyCifKn6z vNsg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@xen0n.name header.s=mail header.b=xP4n34ya; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id p28-20020aa79e9c000000b00625559a78a2si7393675pfq.107.2023.04.22.11.06.25; Sat, 22 Apr 2023 11:06:39 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@xen0n.name header.s=mail header.b=xP4n34ya; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229812AbjDVR52 (ORCPT + 99 others); Sat, 22 Apr 2023 13:57:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44350 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229751AbjDVR5Z (ORCPT ); Sat, 22 Apr 2023 13:57:25 -0400 Received: from mailbox.box.xen0n.name (mail.xen0n.name [115.28.160.31]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59456269A; Sat, 22 Apr 2023 10:57:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=xen0n.name; s=mail; t=1682186243; bh=HXXYuFEBmSyKsiMJlNx/0TnAcXA/avZNHLVfmtY016E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=xP4n34yalLfIFyUVVY7/xam3g64taijI94UojDjyoleVPF/PTsufkN8SM2Ajp/A38 5ZfSlJAjq0R4nDRfNVOpwuo057dJ7/uG1IsT83BnShQ9CTTARy6JPQ62fMCiV7hqXA 9iGl2QgCYw8Aar8f1cnzvZhEBizck9V+J5vMsOjM= Received: from ld50.lan (unknown [101.228.138.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mailbox.box.xen0n.name (Postfix) with ESMTPSA id 2203060B16; Sun, 23 Apr 2023 01:57:22 +0800 (CST) From: WANG Xuerui To: loongarch@lists.linux.dev Cc: WANG Xuerui , Huacai Chen , Xi Ruoyao , Eric Biederman , Al Viro , Arnd Bergmann , linux-api@vger.kernel.org, linux-arch@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] LoongArch: Relay BCE exceptions to userland as SIGSEGVs with si_code=SEGV_BNDERR Date: Sun, 23 Apr 2023 01:57:05 +0800 Message-Id: <20230422175705.3444561-3-kernel@xen0n.name> X-Mailer: git-send-email 2.40.0 In-Reply-To: <20230422175705.3444561-1-kernel@xen0n.name> References: <20230422175705.3444561-1-kernel@xen0n.name> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: WANG Xuerui SEGV_BNDERR was introduced initially for supporting the Intel MPX, but fell into disuse after the MPX support was removed. The LoongArch bounds-checking instructions behave very differently than MPX, but overall the interface is still kind of suitable for conveying the information to userland when bounds-checking assertions trigger, so we wouldn't have to invent more UAPI. Specifically, when the BCE triggers, a SEGV_BNDERR is sent to userland, with si_addr set to the out-of-bounds address or value (in asrt{gt,le}'s case), and one of si_lower or si_upper set to the configured bound depending on the faulting instruction. The other bound is set to either 0 or ULONG_MAX to resemble a range with both lower and upper bounds. Note that it is possible to have si_addr == si_lower in case of a failing asrtgt or {ld,st}gt, because those instructions test for strict greater-than relationship. This should not pose a problem for userland, though, because the faulting PC is available for the application to associate back to the exact instruction for figuring out the expectation. Somewhat contrary to the v1.03 ISA manual's wording, CSR.BADV does not seem to contain the out-of-bounds value when BCE occurs in my experiments. So we have to resort to pattern-matching the instruction word to pull out the appropriate operand ourselves from the context. Example exception context generated by a faulting `asrtgt.d t0, t1` (assert t0 > t1 or BCE) with t0=100 and t1=200: > pc 00005555558206a4 ra 00007ffff2d854fc tp 00007ffff2f2f180 sp 00007ffffbf9fb80 > a0 0000000000000002 a1 00007ffffbf9fce8 a2 00007ffffbf9fd00 a3 00007ffff2ed4558 > a4 0000000000000000 a5 00007ffff2f044c8 a6 00007ffffbf9fce0 a7 fffffffffffff000 > t0 0000000000000064 t1 00000000000000c8 t2 00007ffffbfa2d5e t3 00007ffff2f12aa0 > t4 00007ffff2ed6158 t5 00007ffff2ed6158 t6 000000000000002e t7 0000000003d8f538 > t8 0000000000000005 u0 0000000000000000 s9 0000000000000000 s0 00007ffffbf9fce8 > s1 0000000000000002 s2 0000000000000000 s3 00007ffff2f2c038 s4 0000555555820610 > s5 00007ffff2ed5000 s6 0000555555827e38 s7 00007ffffbf9fd00 s8 0000555555827e38 > ra: 00007ffff2d854fc > ERA: 00005555558206a4 > CRMD: 000000b0 (PLV0 -IE -DA +PG DACF=CC DACM=CC -WE) > PRMD: 00000007 (PPLV3 +PIE -PWE) > EUEN: 00000000 (-FPE -SXE -ASXE -BTE) > ECFG: 0007181c (LIE=2-4,11-12 VS=7) > ESTAT: 000a0000 [BCE] (IS= ECode=10 EsubCode=0) > PRID: 0014c010 (Loongson-64bit, Loongson-3A5000) Signed-off-by: WANG Xuerui --- arch/loongarch/kernel/genex.S | 1 + arch/loongarch/kernel/traps.c | 99 +++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S index 44ff1ff64260..78f066384657 100644 --- a/arch/loongarch/kernel/genex.S +++ b/arch/loongarch/kernel/genex.S @@ -82,6 +82,7 @@ SYM_FUNC_END(except_vec_cex) BUILD_HANDLER ade ade badv BUILD_HANDLER ale ale badv + BUILD_HANDLER bce bce none BUILD_HANDLER bp bp none BUILD_HANDLER fpe fpe fcsr BUILD_HANDLER fpu fpu none diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index 8b268c133b92..5b3bb6b55e05 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ extern asmlinkage void handle_ade(void); extern asmlinkage void handle_ale(void); +extern asmlinkage void handle_bce(void); extern asmlinkage void handle_sys(void); extern asmlinkage void handle_bp(void); extern asmlinkage void handle_ri(void); @@ -585,6 +587,102 @@ static void bug_handler(struct pt_regs *regs) } } +asmlinkage void noinstr do_bce(struct pt_regs *regs) +{ + irqentry_state_t state = irqentry_enter(regs); + bool user = user_mode(regs); + unsigned long era = exception_era(regs); + union loongarch_instruction insn; + u64 badv = 0, lower = 0, upper = ULONG_MAX; + + if (regs->csr_prmd & CSR_PRMD_PIE) + local_irq_enable(); + + current->thread.trap_nr = read_csr_excode(); + + die_if_kernel("Bounds check error in kernel code", regs); + + /* + * Pull out the address that failed bounds checking, and the lower / + * upper bound, by minimally looking at the faulting instruction word + * and reading from the correct register. + * + * Somewhat counter-intuitively (but kinds of makes sense), BCEs + * during checked memory accesses *do not* update CSR.BADV. So badv + * still comes from regs[rj] in these cases. + */ + if (__get_inst(&insn.word, (u32 *)era, user)) + goto bad_era; + + switch (insn.reg3_format.opcode) { + case asrtle_op: + if (insn.reg3_format.rd != 0) + /* not asrtle */ + break; + badv = regs->regs[insn.reg3_format.rj]; + upper = regs->regs[insn.reg3_format.rk]; + break; + + case asrtgt_op: + if (insn.reg3_format.rd != 0) + /* not asrtgt */ + break; + badv = regs->regs[insn.reg3_format.rj]; + lower = regs->regs[insn.reg3_format.rk]; + break; + + case fldles_op: + case fldled_op: + case fstles_op: + case fstled_op: + case ldleb_op: + case ldleh_op: + case ldlew_op: + case ldled_op: + case stleb_op: + case stleh_op: + case stlew_op: + case stled_op: + badv = regs->regs[insn.reg3_format.rj]; + upper = regs->regs[insn.reg3_format.rk]; + break; + + case fldgts_op: + case fldgtd_op: + case fstgts_op: + case fstgtd_op: + case ldgtb_op: + case ldgth_op: + case ldgtw_op: + case ldgtd_op: + case stgtb_op: + case stgth_op: + case stgtw_op: + case stgtd_op: + badv = regs->regs[insn.reg3_format.rj]; + lower = regs->regs[insn.reg3_format.rk]; + break; + } + + force_sig_bnderr((void __user *)badv, (void __user *)lower, + (void __user *)upper); + +out: + if (regs->csr_prmd & CSR_PRMD_PIE) + local_irq_disable(); + + irqentry_exit(regs, state); + return; + +bad_era: + /* + * Cannot pull out the instruction word, hence cannot provide more + * info than a regular SIGSEGV in this case. + */ + force_sig(SIGSEGV); + goto out; +} + asmlinkage void noinstr do_bp(struct pt_regs *regs) { bool user = user_mode(regs); @@ -952,6 +1050,7 @@ void __init trap_init(void) set_handler(EXCCODE_ADE * VECSIZE, handle_ade, VECSIZE); set_handler(EXCCODE_ALE * VECSIZE, handle_ale, VECSIZE); + set_handler(EXCCODE_OOB * VECSIZE, handle_bce, VECSIZE); set_handler(EXCCODE_SYS * VECSIZE, handle_sys, VECSIZE); set_handler(EXCCODE_BP * VECSIZE, handle_bp, VECSIZE); set_handler(EXCCODE_INE * VECSIZE, handle_ri, VECSIZE); -- 2.40.0