[DTrace-devel] [External] : [PATCH 3/3] Create the strtab map read-only for BPF programs

Eslam Almorshdy via B4 Relay devnull+ealmorshdy.d-matrix.ai at kernel.org
Sun Oct 18 02:50:09 UTC 2026


From: Eslam Almorshdy <ealmorshdy at d-matrix.ai>

The strtab map holds the string table, the read-only data and the
block of zeros, and every BPF reader assumes they never change.  Now
that strlen() uses a temporary string, no BPF code writes to the map,
but nothing enforced that, which is how the strlen() overwrite went
unnoticed.

Create the map with BPF_F_RDONLY_PROG, so that the verifier rejects a
program that writes to it.  User space still fills the map, which the
flag does not restrict.  BPF_F_RDONLY_PROG has been supported since
Linux 5.2.

The miscompiled strjoin() in codegen/tst.reg_spilling7.d (XFAIL) is an
example: it is now rejected at its first write into strtab, instead of
only when a later write runs past the end of the map.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Eslam Almorshdy <ealmorshdy at d-matrix.ai>
---
 libdtrace/dt_bpf.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 146a66e3..349f864a 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -548,8 +548,8 @@ map_create_error(dtrace_hdl_t *dtp, const char *name, int err)
 }
 
 static int
-create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
-	    size_t ksz, size_t vsz, size_t size)
+create_gmap_flags(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
+		  size_t ksz, size_t vsz, size_t size, uint32_t flags)
 {
 	int		fd, err;
 	dt_ident_t	*idp;
@@ -561,7 +561,7 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
 		fd = -1;
 		err = E2BIG;
 	} else {
-		fd = dt_bpf_map_create(type, name, ksz, vsz, size, 0);
+		fd = dt_bpf_map_create(type, name, ksz, vsz, size, flags);
 		err = errno;
 	}
 
@@ -584,6 +584,13 @@ create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
 	return fd;
 }
 
+static int
+create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
+	    size_t ksz, size_t vsz, size_t size)
+{
+	return create_gmap_flags(dtp, name, type, ksz, vsz, size, 0);
+}
+
 static int
 create_gmap_of_maps(dtrace_hdl_t *dtp, const char *name,
 		    enum bpf_map_type otype, size_t oksz, size_t osize,
@@ -848,7 +855,7 @@ gmap_create_scratchmem(dtrace_hdl_t *dtp)
  * from the DTrace consumer handle (dt_strlen).
  *
  * The read-only data is appended to the string table, as is a memory block of
- * zeros for initializing memory regions.
+ * zeros for initializing memory regions.  BPF programs may only read this map.
  *
  * In order to ensure the BPF verifier can validate all access requests for
  * dynamic references to string constants, the size of the read-only data plus
@@ -914,8 +921,8 @@ gmap_create_strtab(dtrace_hdl_t *dtp)
 	dt_rodata_write(dtp->dt_rodata, (dt_rodata_copy_f *)dt_rodata_copy,
 			strtab + dtp->dt_rooffset);
 
-	fd = create_gmap(dtp, "strtab", BPF_MAP_TYPE_ARRAY, sizeof(uint32_t),
-			 sz, 1);
+	fd = create_gmap_flags(dtp, "strtab", BPF_MAP_TYPE_ARRAY,
+			       sizeof(uint32_t), sz, 1, BPF_F_RDONLY_PROG);
 	if (fd == -1)
 		return -1;
 

-- 
2.55.0





More information about the DTrace-devel mailing list