[PATCH] lib: sbi_dbtr: fix shared memory double-fetch in install_trig
liutong
liutong at iscas.ac.cn
Tue Jun 23 03:02:25 PDT 2026
sbi_dbtr_install_trig() reads trigger configuration from S-mode shared
memory in two separate loops: first to validate, then to install. Since
the shared memory remains writable by S-mode between the two reads, the
data used for installation may differ from what was validated.
Fix this by taking a snapshot of the shared memory into a local buffer
and performing both validation and installation against that snapshot.
Also add a bounds check on trig_count against RV_MAX_TRIGGERS to prevent
out-of-bounds access on the local buffer.
Additionally, fix a redundant read in dbtr_trigger_setup() where tdata1
was read from the message pointer a second time instead of using the
value already saved in trig->tdata1, which could lead to inconsistency
between the CSR write and the trigger state setup.
Signed-off-by: liutong <liutong at iscas.ac.cn>
---
lib/sbi/sbi_dbtr.c | 52 +++++++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 24 deletions(-)
diff --git a/lib/sbi/sbi_dbtr.c b/lib/sbi/sbi_dbtr.c
index 01047969..8bad2d95 100644
--- a/lib/sbi/sbi_dbtr.c
+++ b/lib/sbi/sbi_dbtr.c
@@ -327,7 +327,7 @@ static void dbtr_trigger_setup(struct sbi_dbtr_trigger *trig,
trig->tdata2 = lle_to_cpu(recv->tdata2);
trig->tdata3 = lle_to_cpu(recv->tdata3);
- tdata1 = lle_to_cpu(recv->tdata1);
+ tdata1 = trig->tdata1;
trig->state = 0;
@@ -603,14 +603,15 @@ int sbi_dbtr_read_trig(unsigned long smode,
int sbi_dbtr_install_trig(unsigned long smode,
unsigned long trig_count, unsigned long *out)
{
+ struct sbi_dbtr_data_msg local_data[RV_MAX_TRIGGERS];
void *shmem_base = NULL;
union sbi_dbtr_shmem_entry *entry;
- struct sbi_dbtr_data_msg *recv;
struct sbi_dbtr_id_msg *xmit;
unsigned long ctrl;
struct sbi_dbtr_trigger *trig;
struct sbi_dbtr_hart_triggers_state *hs = NULL;
bool tdata2_impl, tdata3_impl;
+ int i;
hs = dbtr_thishart_state_ptr();
if (!hs)
@@ -619,9 +620,22 @@ int sbi_dbtr_install_trig(unsigned long smode,
if (sbi_dbtr_shmem_disabled(hs))
return SBI_ERR_NO_SHMEM;
+ if (trig_count > RV_MAX_TRIGGERS)
+ return SBI_ERR_INVALID_PARAM;
+
shmem_base = hart_shmem_base(hs);
+
+ /*
+ * Snapshot trigger data from shared memory into a local buffer so
+ * that S-mode cannot modify the data between validation and use.
+ */
sbi_hart_protection_map_range((unsigned long)shmem_base,
trig_count * sizeof(*entry));
+ for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
+ local_data[_idx] = entry->data;
+ }
+ sbi_hart_protection_unmap_range((unsigned long)shmem_base,
+ trig_count * sizeof(*entry));
/*
* SBI v3.0 sec 19.4 requires SBI_ERR_NOT_SUPPORTED when a trigger
@@ -632,42 +646,35 @@ int sbi_dbtr_install_trig(unsigned long smode,
tdata2_impl = tdata_implemented(CSR_TDATA2);
tdata3_impl = tdata_implemented(CSR_TDATA3);
- /* Check requested triggers configuration */
- for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
- recv = (struct sbi_dbtr_data_msg *)(&entry->data);
- ctrl = recv->tdata1;
+ /* Validate triggers from the local snapshot */
+ for (i = 0; i < (int)trig_count; i++) {
+ ctrl = local_data[i].tdata1;
if (!dbtr_trigger_supported(TDATA1_GET_TYPE(ctrl))) {
- *out = _idx;
- sbi_hart_protection_unmap_range((unsigned long)shmem_base,
- trig_count * sizeof(*entry));
+ *out = i;
return SBI_ERR_FAILED;
}
if (!dbtr_trigger_valid(TDATA1_GET_TYPE(ctrl), ctrl)) {
- *out = _idx;
- sbi_hart_protection_unmap_range((unsigned long)shmem_base,
- trig_count * sizeof(*entry));
+ *out = i;
return SBI_ERR_FAILED;
}
- if ((recv->tdata2 && !tdata2_impl) ||
- (recv->tdata3 && !tdata3_impl)) {
- *out = _idx;
- sbi_hart_protection_unmap_range((unsigned long)shmem_base,
- trig_count * sizeof(*entry));
+ if ((local_data[i].tdata2 && !tdata2_impl) ||
+ (local_data[i].tdata3 && !tdata3_impl)) {
+ *out = i;
return SBI_ERR_NOT_SUPPORTED;
}
}
if (hs->available_trigs < trig_count) {
*out = hs->available_trigs;
- sbi_hart_protection_unmap_range((unsigned long)shmem_base,
- trig_count * sizeof(*entry));
return SBI_ERR_FAILED;
}
- /* Install triggers */
+ /* Install triggers from the validated local snapshot */
+ sbi_hart_protection_map_range((unsigned long)shmem_base,
+ trig_count * sizeof(*entry));
for_each_trig_entry(shmem_base, trig_count, typeof(*entry), entry) {
/*
* Since we have already checked if enough triggers are
@@ -675,15 +682,12 @@ int sbi_dbtr_install_trig(unsigned long smode,
*/
trig = sbi_alloc_trigger();
- recv = (struct sbi_dbtr_data_msg *)(&entry->data);
xmit = (struct sbi_dbtr_id_msg *)(&entry->id);
- dbtr_trigger_setup(trig, recv);
+ dbtr_trigger_setup(trig, &local_data[_idx]);
dbtr_trigger_enable(trig);
xmit->idx = cpu_to_lle(trig->index);
-
}
-
sbi_hart_protection_unmap_range((unsigned long)shmem_base,
trig_count * sizeof(*entry));
--
2.34.1
More information about the opensbi
mailing list