From: Sean Anderson <seanga2@gmail.com>
To: u-boot@lists.denx.de
Subject: [PATCH v3 6/7] riscv: Ensure gp is NULL or points to valid data
Date: Mon, 21 Sep 2020 07:51:40 -0400 [thread overview]
Message-ID: <20200921115141.70598-7-seanga2@gmail.com> (raw)
In-Reply-To: <20200921115141.70598-1-seanga2@gmail.com>
This ensures constructs like `if (gd & gd->...) { ... }` work when
accessing the global data pointer. Without this change, it was possible for
a very early trap to cause _exit_trap to directly or indirectly (through
printf) to read arbitrary memory. This could cause a second trap,
preventing show_regs from being printed.
printf (and specifically puts) uses gd to determine what function to print
with. These functions in turn use gd to find the serial device, etc.
However, before accessing gd, puts first checks to see if it is non-NULL.
This indicates an existing (perhaps undocumented) assumption that either gd
is NULL or it is completely valid.
Before this patch, gd either points to unexpected data (because it retains
the value it did from the prior-stage) or points to uninitialized data
(because it has not yet been initialized by board_init_f_init_reserve)
until the hart has acquired available_harts_lock. This can cause two
problems, depending on the value of gd->flags. If GD_FLG_SERIAL_READY is
unset, then some garbage data will be printed to stdout, but there will not
be a second trap. However, if GD_FLG_SERIAL_READY is set, then puts will
try to print with serial_puts, which will likely cause a second trap.
After this patch, gd is zero up until either a hart has set it in
wait_for_gd_init, or until it is set by arch_init_gd. This prevents its
usage before its data is initialized because both handle_trap and puts
ensure that gd is nonzero before using it. After gd has been set, it is OK
to access it because its data has been cleared (and so flags is valid).
XIP cannot use locks because flash is not writable. This leaves it
vulnerable to the same class of bugs regarding already-pending IPIs as
before this series. Fixing that would require finding another method of
synchronization, which is outside the scope of this series.
Fixes: 7c6ca03eae ("riscv: additional crash information")
Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Bin Meng <bin.meng@windriver.com>
---
Changes in v3:
- Clarify XIP comment
Changes in v2:
- Set gp early with XIP
arch/riscv/cpu/start.S | 28 +++++++++++++++++++++++++---
arch/riscv/lib/interrupts.c | 3 ++-
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 66ca1c7020..eb852538ca 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -47,6 +47,13 @@ _start:
mv tp, a0
mv s1, a1
+ /*
+ * Set the global data pointer to a known value in case we get a very
+ * early trap. The global data pointer will be set its actual value only
+ * after it has been initialized.
+ */
+ mv gp, zero
+
la t0, trap_entry
csrw MODE_PREFIX(tvec), t0
@@ -85,10 +92,10 @@ call_board_init_f_0:
jal board_init_f_alloc_reserve
/*
- * Set global data pointer here for all harts, uninitialized at this
- * point.
+ * Save global data pointer for later. We don't set it here because it
+ * is not initialized yet.
*/
- mv gp, a0
+ mv s0, a0
/* setup stack */
#if CONFIG_IS_ENABLED(SMP)
@@ -109,6 +116,14 @@ call_board_init_f_0:
amoswap.w s2, t1, 0(t0)
bnez s2, wait_for_gd_init
#else
+ /*
+ * FIXME: gp is set before it is initialized. If an XIP U-Boot ever
+ * encounters a pending IPI on boot it is liable to jump to whatever
+ * memory happens to be in ipi_data.addr on boot. It may also run into
+ * problems if it encounters an exception too early (because printf/puts
+ * accesses gd).
+ */
+ mv gp, s0
bnez tp, secondary_hart_loop
#endif
@@ -133,6 +148,13 @@ wait_for_gd_init:
1: amoswap.w.aq t1, t1, 0(t0)
bnez t1, 1b
+ /*
+ * Set the global data pointer only when gd_t has been initialized.
+ * This was already set by arch_setup_gd on the boot hart, but all other
+ * harts' global data pointers gets set here.
+ */
+ mv gp, s0
+
/* register available harts in the available_harts mask */
li t1, 1
sll t1, t1, tp
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index cd47e64487..ad870e98d8 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -78,7 +78,8 @@ static void _exit_trap(ulong code, ulong epc, ulong tval, struct pt_regs *regs)
printf("EPC: " REG_FMT " RA: " REG_FMT " TVAL: " REG_FMT "\n",
epc, regs->ra, tval);
- if (gd->flags & GD_FLG_RELOC)
+ /* Print relocation adjustments, but only if gd is initialized */
+ if (gd && gd->flags & GD_FLG_RELOC)
printf("EPC: " REG_FMT " RA: " REG_FMT " reloc adjusted\n\n",
epc - gd->reloc_off, regs->ra - gd->reloc_off);
--
2.28.0
next prev parent reply other threads:[~2020-09-21 11:51 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-21 11:51 [PATCH v3 0/7] riscv: Correctly handle IPIs already pending upon boot Sean Anderson
2020-09-21 11:51 ` [PATCH v3 1/7] Revert "riscv: Clear pending interrupts before enabling IPIs" Sean Anderson
2020-09-22 0:56 ` Rick Chen
2020-09-21 11:51 ` [PATCH v3 2/7] riscv: Match memory barriers between send_ipi_many and handle_ipi Sean Anderson
2020-09-21 11:51 ` [PATCH v3 3/7] riscv: Use a valid bit to ignore already-pending IPIs Sean Anderson
2020-09-21 11:51 ` [PATCH v3 4/7] riscv: Clear pending IPIs on initialization Sean Anderson
2020-09-22 0:58 ` Rick Chen
2020-09-21 11:51 ` [PATCH v3 5/7] riscv: Consolidate fences into AMOs for available_harts_lock Sean Anderson
2020-09-21 11:51 ` Sean Anderson [this message]
2020-09-22 1:05 ` [PATCH v3 6/7] riscv: Ensure gp is NULL or points to valid data Rick Chen
2020-09-21 11:51 ` [PATCH v3 7/7] riscv: Add some comments to start.S Sean Anderson
2020-09-21 16:23 ` Heinrich Schuchardt
2020-09-21 16:40 ` Sean Anderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200921115141.70598-7-seanga2@gmail.com \
--to=seanga2@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox