2023-04-16 17:34:41

by WANG Xuerui

[permalink] [raw]
Subject: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

From: WANG Xuerui <[email protected]>

Hi,

The LoongArch-64 base architecture is capable of performing
bounds-checking either before memory accesses or alone, with specialized
instructions generating BCEs (bounds-checking error) in case of failed
assertions (ISA manual Volume 1, Sections 2.2.6.1 [1] and 2.2.10.3 [2]).
This could be useful for managed runtimes, but the exception is not
being handled so far, resulting in SIGSYSes in these cases, which is
incorrect and warrants a fix in itself.

During experimentation, it was discovered that there is already UAPI for
expressing such semantics: SIGSEGV with si_code=SEGV_BNDERR. This was
originally added for Intel MPX, and there is currently no user (!) after
the removal of MPX support a few years ago. Although the semantics is
not a 1:1 match to that of LoongArch, still it is better than
alternatives such as SIGTRAP or SIGBUS of BUS_OBJERR kind, due to being
able to convey both the value that failed assertion and the bound value.

This patch series implements just this approach: translating BCEs into
SIGSEGVs with si_code=SEGV_BNDERR, si_value set to the offending value,
and si_lower and si_upper set to resemble a range with both lower and
upper bound while in fact there is only one.

The instructions are not currently used anywhere yet in the fledgling
LoongArch ecosystem, so it's not very urgent and we could take the time
to figure out the best way forward (should SEGV_BNDERR turn out not
suitable).

[1]: https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#bound-check-memory-access-instructions
[2]: https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_asrtlegt_d

WANG Xuerui (2):
LoongArch: Add opcodes of bounds-checking instructions
LoongArch: Relay BCE exceptions to userland as SIGSEGVs with
si_code=SEGV_BNDERR

arch/loongarch/include/asm/inst.h | 26 +++++++
arch/loongarch/include/asm/kdebug.h | 1 +
arch/loongarch/kernel/genex.S | 1 +
arch/loongarch/kernel/traps.c | 107 ++++++++++++++++++++++++++++
4 files changed, 135 insertions(+)

--
2.40.0


2023-04-16 17:34:54

by WANG Xuerui

[permalink] [raw]
Subject: [PATCH 1/2] LoongArch: Add opcodes of bounds-checking instructions

From: WANG Xuerui <[email protected]>

To be used later for extracting operands from faulting instructions that
fall under this category.

Signed-off-by: WANG Xuerui <[email protected]>
---
arch/loongarch/include/asm/inst.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h
index a04fe755d719..829646f633d2 100644
--- a/arch/loongarch/include/asm/inst.h
+++ b/arch/loongarch/include/asm/inst.h
@@ -121,6 +121,8 @@ enum reg2bstrd_op {
};

enum reg3_op {
+ asrtle_op = 0x2,
+ asrtgt_op = 0x3,
addw_op = 0x20,
addd_op = 0x21,
subw_op = 0x22,
@@ -176,6 +178,30 @@ enum reg3_op {
amord_op = 0x70c7,
amxorw_op = 0x70c8,
amxord_op = 0x70c9,
+ fldgts_op = 0x70e8,
+ fldgtd_op = 0x70e9,
+ fldles_op = 0x70ea,
+ fldled_op = 0x70eb,
+ fstgts_op = 0x70ec,
+ fstgtd_op = 0x70ed,
+ fstles_op = 0x70ee,
+ fstled_op = 0x70ef,
+ ldgtb_op = 0x70f0,
+ ldgth_op = 0x70f1,
+ ldgtw_op = 0x70f2,
+ ldgtd_op = 0x70f3,
+ ldleb_op = 0x70f4,
+ ldleh_op = 0x70f5,
+ ldlew_op = 0x70f6,
+ ldled_op = 0x70f7,
+ stgtb_op = 0x70f8,
+ stgth_op = 0x70f9,
+ stgtw_op = 0x70fa,
+ stgtd_op = 0x70fb,
+ stleb_op = 0x70fc,
+ stleh_op = 0x70fd,
+ stlew_op = 0x70fe,
+ stled_op = 0x70ff,
};

enum reg3sa2_op {
--
2.40.0

2023-04-16 17:35:49

by WANG Xuerui

[permalink] [raw]
Subject: [PATCH 2/2] LoongArch: Relay BCE exceptions to userland as SIGSEGVs with si_code=SEGV_BNDERR

From: WANG Xuerui <[email protected]>

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 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 ISA manual's wording, CSR.BADV does not seem to
contain the out-of-bounds value when BCE occurs, 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:

> 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
> era: 00005555558206a4
> ra: 00007ffff2d854fc
> crmd: 000000b0 (-WE DACM=CC DACF=CC +PG -DA -IE PLV0)
> prmd: 00000007 (-PWE +PIE PPLV3)
> euen: 00000000 (-BTE -ASXE -SXE -FPE)
> ecfg: 0007181c (VS=7 LIE=2-4,11-12)
> estat: 000a0000 [BCE] (EsubCode=0 ECode=10 IS=)
> prid: 0014c010 (Loongson-64bit)

Signed-off-by: WANG Xuerui <[email protected]>
---
arch/loongarch/include/asm/kdebug.h | 1 +
arch/loongarch/kernel/genex.S | 1 +
arch/loongarch/kernel/traps.c | 107 ++++++++++++++++++++++++++++
3 files changed, 109 insertions(+)

diff --git a/arch/loongarch/include/asm/kdebug.h b/arch/loongarch/include/asm/kdebug.h
index d721b4b82fae..793a8fdfeb90 100644
--- a/arch/loongarch/include/asm/kdebug.h
+++ b/arch/loongarch/include/asm/kdebug.h
@@ -18,6 +18,7 @@ enum die_val {
DIE_SSTEPBP,
DIE_UPROBE,
DIE_UPROBE_XOL,
+ DIE_BOUNDS_CHECK,
};

#endif /* _ASM_LOONGARCH_KDEBUG_H */
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 a060481198af..c6fc421a5983 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -36,6 +36,7 @@
#include <asm/break.h>
#include <asm/cpu.h>
#include <asm/fpu.h>
+#include <asm/inst.h>
#include <asm/loongarch.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
@@ -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);
@@ -589,6 +591,110 @@ 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();
+
+ /*
+ * notify the kprobe handlers, if instruction is likely to
+ * pertain to them.
+ */
+ if (notify_die(DIE_BOUNDS_CHECK, "Bounds check error", regs, 0,
+ current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
+ goto out;
+
+ __show_regs(regs);
+ 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);
@@ -1032,6 +1138,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

2023-04-16 17:57:24

by WANG Xuerui

[permalink] [raw]
Subject: Re: [PATCH 2/2] LoongArch: Relay BCE exceptions to userland as SIGSEGVs with si_code=SEGV_BNDERR

On 4/17/23 01:33, WANG Xuerui wrote:
> <snip>
> @@ -589,6 +591,110 @@ 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();
> +
> + /*
> + * notify the kprobe handlers, if instruction is likely to
> + * pertain to them.
> + */
> + if (notify_die(DIE_BOUNDS_CHECK, "Bounds check error", regs, 0,
> + current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
> + goto out;
> +
> + __show_regs(regs);

Ah, remnant of debug code. Please ignore this line; I'm not resending
for now because I fully anticipate a v2 (and possibly even more). Lack
of coffee/tea and presence of beer during weekends aren't going to help...

--
WANG "xen0n" Xuerui

Linux/LoongArch mailing list: https://lore.kernel.org/loongarch/

2023-04-17 06:48:03

by Xi Ruoyao

[permalink] [raw]
Subject: Re: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

On Mon, 2023-04-17 at 01:33 +0800, WANG Xuerui wrote:
> From: WANG Xuerui <[email protected]>
>
> Hi,
>
> The LoongArch-64 base architecture is capable of performing
> bounds-checking either before memory accesses or alone, with specialized
> instructions generating BCEs (bounds-checking error) in case of failed
> assertions (ISA manual Volume 1, Sections 2.2.6.1 [1] and 2.2.10.3 [2]).
> This could be useful for managed runtimes, but the exception is not
> being handled so far, resulting in SIGSYSes in these cases, which is
> incorrect and warrants a fix in itself.
>
> During experimentation, it was discovered that there is already UAPI for
> expressing such semantics: SIGSEGV with si_code=SEGV_BNDERR. This was
> originally added for Intel MPX, and there is currently no user (!) after
> the removal of MPX support a few years ago. Although the semantics is
> not a 1:1 match to that of LoongArch, still it is better than
> alternatives such as SIGTRAP or SIGBUS of BUS_OBJERR kind, due to being
> able to convey both the value that failed assertion and the bound value.
>
> This patch series implements just this approach: translating BCEs into
> SIGSEGVs with si_code=SEGV_BNDERR, si_value set to the offending value,
> and si_lower and si_upper set to resemble a range with both lower and
> upper bound while in fact there is only one.
>
> The instructions are not currently used anywhere yet in the fledgling
> LoongArch ecosystem, so it's not very urgent and we could take the time
> to figure out the best way forward (should SEGV_BNDERR turn out not
> suitable).

I don't think these instructions can be used in any systematic way
within a Linux userspace in 2023. IMO they should not exist in
LoongArch at all because they have all the same disadvantages of Intel
MPX; MPX has been removed by Intel in 2019, and LoongArch is designed
after 2019.

If we need some hardware assisted memory safety facility, an extension
similar to ARM TBI or Intel LAM would be much more useful.


Back in the old MIPS-based Loongson CPUs, similar instructions (GSLE,
GSGT, etc.) were included in LoongISA extension and the manual says they
raises "address error" when assert fails. So SIGSEGV seems the
"backward compatible" (quoted because we absolutely don't need to
maintain any backward compatibility with old MIPS-based implementations)
thing to do.

--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University

2023-04-17 07:58:57

by WANG Xuerui

[permalink] [raw]
Subject: Re: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

On 2023/4/17 14:47, Xi Ruoyao wrote:
> On Mon, 2023-04-17 at 01:33 +0800, WANG Xuerui wrote:
>> From: WANG Xuerui <[email protected]>
>>
>> Hi,
>>
>> The LoongArch-64 base architecture is capable of performing
>> bounds-checking either before memory accesses or alone, with specialized
>> instructions generating BCEs (bounds-checking error) in case of failed
>> assertions (ISA manual Volume 1, Sections 2.2.6.1 [1] and 2.2.10.3 [2]).
>> This could be useful for managed runtimes, but the exception is not
>> being handled so far, resulting in SIGSYSes in these cases, which is
>> incorrect and warrants a fix in itself.
>>
>> During experimentation, it was discovered that there is already UAPI for
>> expressing such semantics: SIGSEGV with si_code=SEGV_BNDERR. This was
>> originally added for Intel MPX, and there is currently no user (!) after
>> the removal of MPX support a few years ago. Although the semantics is
>> not a 1:1 match to that of LoongArch, still it is better than
>> alternatives such as SIGTRAP or SIGBUS of BUS_OBJERR kind, due to being
>> able to convey both the value that failed assertion and the bound value.
>>
>> This patch series implements just this approach: translating BCEs into
>> SIGSEGVs with si_code=SEGV_BNDERR, si_value set to the offending value,
>> and si_lower and si_upper set to resemble a range with both lower and
>> upper bound while in fact there is only one.
>>
>> The instructions are not currently used anywhere yet in the fledgling
>> LoongArch ecosystem, so it's not very urgent and we could take the time
>> to figure out the best way forward (should SEGV_BNDERR turn out not
>> suitable).
>
> I don't think these instructions can be used in any systematic way
> within a Linux userspace in 2023. IMO they should not exist in
> LoongArch at all because they have all the same disadvantages of Intel
> MPX; MPX has been removed by Intel in 2019, and LoongArch is designed
> after 2019.

Well, the difference is IMO significant enough to make LoongArch
bounds-checking more useful, at least for certain use cases. For
example, the bounds were a separate register bank in Intel MPX, but in
LoongArch they are just values in GPRs. This fits naturally into
JIT-ting or other managed runtimes (e.g. Go) whose slice indexing ops
already bounds-check with a temporary register per bound anyway, so it's
just a matter of this snippet (or something like it)

- calculate element address
- if address < base: goto fail
- load/calculate upper bound
- if address >= upper bound: goto fail
- access memory

becoming

- calculate element address
- asrtgt address, base - 1
- load/calculate upper bound
- {ld,st}le address, upper bound

then in SIGSEGV handler, check PC to associate the signal back with the
exact access op; in this case, the only big problem is that LoongArch
doesn't provide idiomatic "lower <= val" and "val < upper" semantics for
the checked loads/stores. I've not benchmarked such memory accesses
against plain unchecked variants, though, but I guess latency should not
get too bad (just an extra comparison and an unlikely trap per op).

I've also looked at the other limitations described in the Wikipedia
page for Intel MPX, and it seems majority of them are due to its use of
a new register bank (i.e. ISA state). So I'd say the LoongArch feature
is probably better in that regard. Other than that, I agree they are
less useful for general memory safety that doesn't require
application-level cooperation.

>
> If we need some hardware assisted memory safety facility, an extension
> similar to ARM TBI or Intel LAM would be much more useful.
>
>
> Back in the old MIPS-based Loongson CPUs, similar instructions (GSLE,
> GSGT, etc.) were included in LoongISA extension and the manual says they
> raises "address error" when assert fails. So SIGSEGV seems the
> "backward compatible" (quoted because we absolutely don't need to
> maintain any backward compatibility with old MIPS-based implementations)
> thing to do.

IMO we don't need to even try to keep consistency between Loongson/MIPS
and Loongson/LoongArch UAPIs. Loongson/MIPS is effectively "on life
support" due to non-technical reasons we have zero influence, so there's
no reason ISVs would put out new software for it. And SIGSEGV is IMO
appropriate no matter what the arch is (the HW exception indicates a
real/supposed *access to the wrong location* after all), and it's
important that we do the right thing for a new architecture.

--
WANG "xen0n" Xuerui

Linux/LoongArch mailing list: https://lore.kernel.org/loongarch/

2023-04-17 09:59:50

by Xi Ruoyao

[permalink] [raw]
Subject: Re: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

On Mon, 2023-04-17 at 15:54 +0800, WANG Xuerui wrote:
> On 2023/4/17 14:47, Xi Ruoyao wrote:
> > On Mon, 2023-04-17 at 01:33 +0800, WANG Xuerui wrote:
> > > From: WANG Xuerui <[email protected]>
> > >
> > > Hi,
> > >
> > > The LoongArch-64 base architecture is capable of performing
> > > bounds-checking either before memory accesses or alone, with specialized
> > > instructions generating BCEs (bounds-checking error) in case of failed
> > > assertions (ISA manual Volume 1, Sections 2.2.6.1 [1] and 2.2.10.3 [2]).
> > > This could be useful for managed runtimes, but the exception is not
> > > being handled so far, resulting in SIGSYSes in these cases, which is
> > > incorrect and warrants a fix in itself.
> > >
> > > During experimentation, it was discovered that there is already UAPI for
> > > expressing such semantics: SIGSEGV with si_code=SEGV_BNDERR. This was
> > > originally added for Intel MPX, and there is currently no user (!) after
> > > the removal of MPX support a few years ago. Although the semantics is
> > > not a 1:1 match to that of LoongArch, still it is better than
> > > alternatives such as SIGTRAP or SIGBUS of BUS_OBJERR kind, due to being
> > > able to convey both the value that failed assertion and the bound value.
> > >
> > > This patch series implements just this approach: translating BCEs into
> > > SIGSEGVs with si_code=SEGV_BNDERR, si_value set to the offending value,
> > > and si_lower and si_upper set to resemble a range with both lower and
> > > upper bound while in fact there is only one.
> > >
> > > The instructions are not currently used anywhere yet in the fledgling
> > > LoongArch ecosystem, so it's not very urgent and we could take the time
> > > to figure out the best way forward (should SEGV_BNDERR turn out not
> > > suitable).
> >
> > I don't think these instructions can be used in any systematic way
> > within a Linux userspace in 2023.  IMO they should not exist in
> > LoongArch at all because they have all the same disadvantages of Intel
> > MPX; MPX has been removed by Intel in 2019, and LoongArch is designed
> > after 2019.
>
> Well, the difference is IMO significant enough to make LoongArch
> bounds-checking more useful, at least for certain use cases. For
> example, the bounds were a separate register bank in Intel MPX, but in
> LoongArch they are just values in GPRs. This fits naturally into
> JIT-ting or other managed runtimes (e.g. Go) whose slice indexing ops
> already bounds-check with a temporary register per bound anyway, so it's
> just a matter of this snippet (or something like it)
>
> - calculate element address
> - if address < base: goto fail
> - load/calculate upper bound
> - if address >= upper bound: goto fail
> - access memory
>
> becoming
>
> - calculate element address
> - asrtgt address, base - 1
> - load/calculate upper bound
> - {ld,st}le address, upper bound
>
> then in SIGSEGV handler, check PC to associate the signal back with the
> exact access op;

I remember using the signal handler for "usual" error handling can be a
very bad idea but I can't remember where I've read about it. Is there
any managed environments doing so in practice?

If we redefine new_ldle/new_stle as "if [[likely]] the address is in-
bound, do the load/store and skip the next instruction; otherwise do
nothing", we can say:

blt address, base, 1f
new_ldle.d rd, address, upperbound
1:b panic_oob_access
xor rd, rd, 42 // use rd to do something

This is more versatile, and useful for building a loop as well:

or a0, r0, r0
0:new_ldle.d t1, t0, t2
b 1f
add.d a0, t1, a0
add.d t0, t0, 8
b 0b
1:bl do_something_with_the_sum

Yes it's "non-RISC", but at least more RISC than the current ldle: if
you want a trap anyway you can say

blt address, base, 1f
new_ldle.d rd, address, upperbound
1:break {a code defined for OOB}
xor rd, rd, 42 // use rd

--
Xi Ruoyao <[email protected]>
School of Aerospace Science and Technology, Xidian University

2023-04-20 08:48:59

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

Hi, Xuerui,

I hope V2 can be applied cleanly without the patch series "LoongArch:
Better backtraces", thanks.

Huacai

On Mon, Apr 17, 2023 at 5:50 PM Xi Ruoyao <[email protected]> wrote:
>
> On Mon, 2023-04-17 at 15:54 +0800, WANG Xuerui wrote:
> > On 2023/4/17 14:47, Xi Ruoyao wrote:
> > > On Mon, 2023-04-17 at 01:33 +0800, WANG Xuerui wrote:
> > > > From: WANG Xuerui <[email protected]>
> > > >
> > > > Hi,
> > > >
> > > > The LoongArch-64 base architecture is capable of performing
> > > > bounds-checking either before memory accesses or alone, with specialized
> > > > instructions generating BCEs (bounds-checking error) in case of failed
> > > > assertions (ISA manual Volume 1, Sections 2.2.6.1 [1] and 2.2.10.3 [2]).
> > > > This could be useful for managed runtimes, but the exception is not
> > > > being handled so far, resulting in SIGSYSes in these cases, which is
> > > > incorrect and warrants a fix in itself.
> > > >
> > > > During experimentation, it was discovered that there is already UAPI for
> > > > expressing such semantics: SIGSEGV with si_code=SEGV_BNDERR. This was
> > > > originally added for Intel MPX, and there is currently no user (!) after
> > > > the removal of MPX support a few years ago. Although the semantics is
> > > > not a 1:1 match to that of LoongArch, still it is better than
> > > > alternatives such as SIGTRAP or SIGBUS of BUS_OBJERR kind, due to being
> > > > able to convey both the value that failed assertion and the bound value.
> > > >
> > > > This patch series implements just this approach: translating BCEs into
> > > > SIGSEGVs with si_code=SEGV_BNDERR, si_value set to the offending value,
> > > > and si_lower and si_upper set to resemble a range with both lower and
> > > > upper bound while in fact there is only one.
> > > >
> > > > The instructions are not currently used anywhere yet in the fledgling
> > > > LoongArch ecosystem, so it's not very urgent and we could take the time
> > > > to figure out the best way forward (should SEGV_BNDERR turn out not
> > > > suitable).
> > >
> > > I don't think these instructions can be used in any systematic way
> > > within a Linux userspace in 2023. IMO they should not exist in
> > > LoongArch at all because they have all the same disadvantages of Intel
> > > MPX; MPX has been removed by Intel in 2019, and LoongArch is designed
> > > after 2019.
> >
> > Well, the difference is IMO significant enough to make LoongArch
> > bounds-checking more useful, at least for certain use cases. For
> > example, the bounds were a separate register bank in Intel MPX, but in
> > LoongArch they are just values in GPRs. This fits naturally into
> > JIT-ting or other managed runtimes (e.g. Go) whose slice indexing ops
> > already bounds-check with a temporary register per bound anyway, so it's
> > just a matter of this snippet (or something like it)
> >
> > - calculate element address
> > - if address < base: goto fail
> > - load/calculate upper bound
> > - if address >= upper bound: goto fail
> > - access memory
> >
> > becoming
> >
> > - calculate element address
> > - asrtgt address, base - 1
> > - load/calculate upper bound
> > - {ld,st}le address, upper bound
> >
> > then in SIGSEGV handler, check PC to associate the signal back with the
> > exact access op;
>
> I remember using the signal handler for "usual" error handling can be a
> very bad idea but I can't remember where I've read about it. Is there
> any managed environments doing so in practice?
>
> If we redefine new_ldle/new_stle as "if [[likely]] the address is in-
> bound, do the load/store and skip the next instruction; otherwise do
> nothing", we can say:
>
> blt address, base, 1f
> new_ldle.d rd, address, upperbound
> 1:b panic_oob_access
> xor rd, rd, 42 // use rd to do something
>
> This is more versatile, and useful for building a loop as well:
>
> or a0, r0, r0
> 0:new_ldle.d t1, t0, t2
> b 1f
> add.d a0, t1, a0
> add.d t0, t0, 8
> b 0b
> 1:bl do_something_with_the_sum
>
> Yes it's "non-RISC", but at least more RISC than the current ldle: if
> you want a trap anyway you can say
>
> blt address, base, 1f
> new_ldle.d rd, address, upperbound
> 1:break {a code defined for OOB}
> xor rd, rd, 42 // use rd
>
> --
> Xi Ruoyao <[email protected]>
> School of Aerospace Science and Technology, Xidian University

2023-04-20 10:05:04

by WANG Xuerui

[permalink] [raw]
Subject: Re: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

On 2023/4/20 16:36, Huacai Chen wrote:
> Hi, Xuerui,
>
> I hope V2 can be applied cleanly without the patch series "LoongArch:
> Better backtraces", thanks.

I believe it's already the case (just try; I've moved the BADV printing
for BCE into the better backtraces series before sending this).

I'm only waiting for comments from the other UAPI maintainers on the CC
list.

--
WANG "xen0n" Xuerui

Linux/LoongArch mailing list: https://lore.kernel.org/loongarch/

2023-04-22 08:42:36

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 0/2] LoongArch: Make bounds-checking instructions useful

On Thu, Apr 20, 2023 at 5:38 PM WANG Xuerui <[email protected]> wrote:
>
> On 2023/4/20 16:36, Huacai Chen wrote:
> > Hi, Xuerui,
> >
> > I hope V2 can be applied cleanly without the patch series "LoongArch:
> > Better backtraces", thanks.
>
> I believe it's already the case (just try; I've moved the BADV printing
> for BCE into the better backtraces series before sending this).
>
> I'm only waiting for comments from the other UAPI maintainers on the CC
> list.
You changed arch/loongarch/include/asm/kdebug.h, does it have
something to do with UAPI?
On the other hand, kprobe has dropped the notifier mechanism, so this
piece should be changed, I think.

+ /*
+ * notify the kprobe handlers, if instruction is likely to
+ * pertain to them.
+ */
+ if (notify_die(DIE_BOUNDS_CHECK, "Bounds check error", regs, 0,
+ current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
+ goto out;

Huacai

>
> --
> WANG "xen0n" Xuerui
>
> Linux/LoongArch mailing list: https://lore.kernel.org/loongarch/
>