Linux DTrace development list
 help / color / mirror / Atom feed
* [PATCH 2/6] usdt_parser: harden DOF and note bounds checks
@ 2026-06-12 16:22 Kris Van Hees
  0 siblings, 0 replies; only message in thread
From: Kris Van Hees @ 2026-06-12 16:22 UTC (permalink / raw)
  To: dtrace, dtrace-devel

Validate DOF section metadata before use, require ELF note strings to
terminate within their declared payloads, and check parsed DOF record
sizes before DTrace consumes them.  This keeps malformed parser input
or stash data from driving out-of-bounds reads in either the parser or
the host.

Orabug: 39352038
Orabug: 39352051
Orabug: 39351967
CVE: CVE-2026-46831
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
---
 include/dtrace/pid.h          |   2 +-
 libcommon/usdt_parser.h       |  10 ++-
 libcommon/usdt_parser_dof.c   |  25 +++---
 libcommon/usdt_parser_notes.c | 106 +++++++++++++++++++------
 libdtrace/dt_pid.c            | 142 ++++++++++++++++++++++++++++++----
 5 files changed, 233 insertions(+), 52 deletions(-)

diff --git a/include/dtrace/pid.h b/include/dtrace/pid.h
index 4a239b07..88f9366c 100644
--- a/include/dtrace/pid.h
+++ b/include/dtrace/pid.h
@@ -45,7 +45,7 @@ typedef struct pid_probespec {
 	size_t pps_nargvlen;			/* (high estimate of) length of array */
 	char *pps_xargv;			/* array of xlated args */
 	size_t pps_xargvlen;			/* (high estimate of) length of array */
-	int8_t *pps_argmap;			/* mapped arg indexes */
+	uint8_t *pps_argmap;			/* mapped arg indexes */
 	char *pps_sargv;			/* list of arg sources */
 	int pps_flags;				/* flags */
 
diff --git a/libcommon/usdt_parser.h b/libcommon/usdt_parser.h
index b11207d1..99fc3033 100644
--- a/libcommon/usdt_parser.h
+++ b/libcommon/usdt_parser.h
@@ -136,7 +136,7 @@ typedef struct dof_parsed {
 			 * Mapping from native arg index to xlated arg index.
 			 * xargc in length.
 			 */
-			int8_t argmap[1];
+			uint8_t argmap[1];
 		} argmap;
 
 		struct dpi_tracepoint_info {
@@ -171,6 +171,14 @@ typedef struct dof_parsed {
 	};
 } dof_parsed_t;
 
+#define DIT_PROVIDER_HEADSZ	offsetof(dof_parsed_t, provider.name)
+#define DIT_PROBE_HEADSZ	offsetof(dof_parsed_t, probe.name)
+#define DIT_TRACEPOINT_HEADSZ	offsetof(dof_parsed_t, tracepoint.args)
+#define DIT_ERR_HEADSZ		offsetof(dof_parsed_t, err.err)
+#define DIT_ARGS_NATIVE_HEADSZ	offsetof(dof_parsed_t, nargs.args)
+#define DIT_ARGS_XLAT_HEADSZ	offsetof(dof_parsed_t, xargs.args)
+#define DIT_ARGS_MAP_HEADSZ	offsetof(dof_parsed_t, argmap.argmap)
+
 /*
  * Host-side: in usdt_parser_host.c.
  * The host is the non-jailed process that talks to the jailed parser.
diff --git a/libcommon/usdt_parser_dof.c b/libcommon/usdt_parser_dof.c
index bc8e185a..e2166985 100644
--- a/libcommon/usdt_parser_dof.c
+++ b/libcommon/usdt_parser_dof.c
@@ -275,8 +275,8 @@ dof_slurp(int out, dof_hdr_t *dof, uint64_t ubase)
 		return -1;
 	}
 
-	if (dof->dofh_secsize == 0) {
-		usdt_error(out, EINVAL, "zero section header size");
+	if (dof->dofh_secsize != sizeof(dof_sec_t)) {
+		usdt_error(out, EINVAL, "incorrect section header size");
 		return -1;
 	}
 
@@ -462,7 +462,7 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec)
 		return -1;
 	}
 
-	if (prb_sec->dofs_entsize == 0 ||
+	if (prb_sec->dofs_entsize < sizeof(dof_probe_t) ||
 	    prb_sec->dofs_entsize > prb_sec->dofs_size) {
 		usdt_error(out, EINVAL, "invalid entry size %x, max %lx",
 			   prb_sec->dofs_entsize, prb_sec->dofs_size);
@@ -615,11 +615,11 @@ validate_provider(int out, dof_hdr_t *dof, dof_sec_t *sec)
 		typeidx = prb->dofpr_xargv;
 		typestr = strtab + prb->dofpr_xargv;
 		for (k = 0; k < prb->dofpr_xargc; k++) {
-			if (arg[prb->dofpr_argidx + k] > prb->dofpr_nargc) {
+			if (arg[prb->dofpr_argidx + k] >= prb->dofpr_nargc) {
 				usdt_error(out, EINVAL, "bad native argument index "
 					   "for arg %i: %i (max %i)", k,
 					   arg[prb->dofpr_argidx + k],
-					   prb->dofpr_nargc);
+					   prb->dofpr_nargc - 1);
 				return -1;
 			}
 
@@ -748,7 +748,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb)
 	 * flags.
 	 */
 
-	msg_size = offsetof(dof_parsed_t, probe.name) +
+	msg_size = DIT_PROBE_HEADSZ +
 		   strlen(dhpb->dthpb_mod) + 1 +
 		   strlen(dhpb->dthpb_func) + 1 +
 		   strlen(dhpb->dthpb_name) + 1;
@@ -786,7 +786,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb)
 		size_t	nargs_size;
 
 		nargs_size = strings_len(dhpb->dthpb_ntypes, dhpb->dthpb_nargc);
-		msg_size = offsetof(dof_parsed_t, nargs.args) + nargs_size;
+		msg_size = DIT_ARGS_NATIVE_HEADSZ + nargs_size;
 
 		msg = malloc(msg_size);
 		if (!msg)
@@ -808,8 +808,7 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb)
 
 			xargs_size = strings_len(dhpb->dthpb_xtypes,
 						 dhpb->dthpb_xargc);
-			msg_size = offsetof(dof_parsed_t, xargs.args) +
-				   xargs_size;
+			msg_size = DIT_ARGS_XLAT_HEADSZ + xargs_size;
 
 			msg = malloc(msg_size);
 			if (!msg)
@@ -826,9 +825,8 @@ emit_probe(int out, dtrace_helper_probedesc_t *dhpb)
 
 			/* Then the mapping table. */
 
-			map_size = dhpb->dthpb_xargc * sizeof(int8_t);
-			msg_size = offsetof(dof_parsed_t, argmap.argmap) +
-				   map_size;
+			map_size = dhpb->dthpb_xargc * sizeof(uint8_t);
+			msg_size = DIT_ARGS_MAP_HEADSZ + map_size;
 
 			msg = malloc(msg_size);
 			if (!msg)
@@ -922,8 +920,7 @@ emit_provider(int out, dof_helper_t *dhp,
 	}
 
 	dhpb.dthpb_prov = strtab + prov->dofpv_name;
-	provider_msg_size = offsetof(dof_parsed_t, provider.name) +
-	    strlen(dhpb.dthpb_prov) + 1;
+	provider_msg_size = DIT_PROVIDER_HEADSZ + strlen(dhpb.dthpb_prov) + 1;
 
 	provider_msg = malloc(provider_msg_size);
 	if (!provider_msg) {
diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c
index c98c9fb0..7742024e 100644
--- a/libcommon/usdt_parser_notes.c
+++ b/libcommon/usdt_parser_notes.c
@@ -73,6 +73,10 @@ get_note(int out, usdt_data_t *data, ssize_t off, usdt_note_t *note)
 	}
 
 	note->name = (char *)data->buf + off;
+	if (memchr(note->name, '\0', sz) == NULL) {
+		usdt_error(out, EINVAL, "Unterminated name");
+		return -1;
+	}
 	off += ALIGN(sz, 4);
 
 	dt_dbg_usdt("ELF note '%s' (%d bytes)\n",
@@ -272,6 +276,25 @@ static dt_htab_ops_t pmap_htab_ops = {
         .next = (htab_next_fn)prb_next
 };
 
+/*
+ * Return the length of string 'str' (excluding the terminating NUL, if it
+ * terminates before the supplied 'end', and -1 otherwise.
+ */
+static ssize_t
+cstrlen(const char *str, const char *end)
+{
+	const char	*p;
+
+	if (str >= end)
+		return -1;
+
+	p = memchr(str, '\0', end - str);
+	if (p == NULL)
+		return -1;
+
+	return p - str;
+}
+
 /*
  * Return the cummulative string length of 'cnt' consecutive 0-terminated
  * strings.  If skip > 0, it indicates how many extra bytes are to be skipped
@@ -284,10 +307,12 @@ strarray_size(uint8_t cnt, const char *str, const char *end, size_t skip)
 	const char	*p = str;
 
 	while (cnt-- > 0) {
-		if (p >= end)
+		ssize_t	len = cstrlen(p, end);
+
+		if (len < 0 || skip > (size_t)(end - (p + len + 1)))
 			return -1;
 
-		p += strlen(p) + 1 + skip;
+		p += len + 1 + skip;
 	}
 
 	return p - str;
@@ -298,14 +323,21 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		usdt_note_t *note)
 {
 	const char	*p = note->desc;
+	const char	*end = p + note->hdr->n_descsz;
 	dt_provider_t	prvt, *pvp;
 	const uint32_t	*vals;
 	uint32_t	probec;
+	ssize_t		len;
 	int		i;
 
+	len = cstrlen(p, end);
+	if (len == -1) {
+		usdt_error(out, EINVAL, "Unterminated provider name");
+		return -1;
+	}
 	prvt.name = p;
-	p += ALIGN(strlen(p) + 1, 4);
-	if (p + 6 * sizeof(uint32_t) - note->desc > note->hdr->n_descsz) {
+	p += ALIGN(len + 1, 4);
+	if (p + 6 * sizeof(uint32_t) > end) {
 		usdt_error(out, EINVAL, "Incomplete note data");
 		return -1;
 	}
@@ -342,13 +374,18 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		ssize_t		len;
 
 		p = (const char *)ALIGN((uintptr_t)p, 4);
+		len = cstrlen(p, end);
+		if (len == -1) {
+			usdt_error(out, EINVAL, "Unterminated probe name");
+			return -1;
+		}
 		prbt.prv = pvp->name;
 		prbt.mod = dhp->dofhp_mod;
 		prbt.fun = NULL;
 		prbt.prb = p;
 		prbt.off = 0;
-		p += strlen(p) + 1;
-		if (p + 2 * sizeof(uint8_t) - note->desc > note->hdr->n_descsz) {
+		p += len + 1;
+		if (p + 2 * sizeof(uint8_t) > end) {
 			usdt_error(out, EINVAL, "Incomplete note data");
 			return -1;
 		}
@@ -374,8 +411,7 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		prp->ntp = 0;
 		prp->is_enabled = 0;
 		prp->nargc = argc = *(uint8_t *)p++;
-		len = strarray_size(argc, p, note->desc + note->hdr->n_descsz,
-				    0);
+		len = strarray_size(argc, p, end, 0);
 		if (len == -1) {
 			usdt_error(out, EINVAL, "Incomplete note data");
 			return -1;
@@ -384,7 +420,7 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		prp->nargs = p;
 
 		p += len;
-		if (p - note->desc > note->hdr->n_descsz) {
+		if (p >= end) {
 			usdt_error(out, EINVAL, "Incomplete note data");
 			return -1;
 		}
@@ -411,6 +447,11 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 				q = stpcpy(q, p);
 				q++;
 				p += strlen(p) + 1;
+				if (*(uint8_t *)p >= prp->nargc) {
+					usdt_error(out, EINVAL,
+						   "bad native argument index");
+					return -1;
+				}
 				prp->xmap[j] = *p;
 				p++;
 			}
@@ -432,7 +473,9 @@ parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		usdt_note_t *note)
 {
 	const char	*p = note->desc;
+	const char	*end = p + note->hdr->n_descsz;
 	uint64_t	off, fno;
+	ssize_t		len;
 	dt_probe_t	prbt, *prp;
 
 	data = data->next;
@@ -441,7 +484,7 @@ parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		return -1;
 	}
 
-	if (p + 2 * sizeof(uint64_t) - note->desc > note->hdr->n_descsz) {
+	if (p + 2 * sizeof(uint64_t) >= end) {
 		usdt_error(out, EINVAL, "Incomplete note data");
 		return -1;
 	}
@@ -450,10 +493,15 @@ parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 	p += sizeof(uint64_t);
 	fno = *(uint64_t *)p;
 	p += sizeof(uint64_t);
+	len = cstrlen(p, end);
+	if (len == -1) {
+		usdt_error(out, EINVAL, "Unterminated provider name");
+		return -1;
+	}
 
 	prbt.prv = p;
-	p += strlen(p) + 1;
-	if (p - note->desc > note->hdr->n_descsz) {
+	p += len + 1;
+	if (p >= end) {
 		usdt_error(out, EINVAL, "Incomplete note data");
 		return -1;
 	}
@@ -463,9 +511,18 @@ parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 		return -1;
 	}
 	prbt.fun = (char *)data->buf + fno;
+	if (cstrlen(prbt.fun, (char *)data->buf + data->size) == -1) {
+		usdt_error(out, EINVAL, "Unterminated function name");
+		return -1;
+	}
+	len = cstrlen(p, end);
+	if (len == -1) {
+		usdt_error(out, EINVAL, "Unterminated probe name");
+		return -1;
+	}
 	prbt.prb = p;
-	p += strlen(p) + 1;
-	if (p - note->desc > note->hdr->n_descsz) {
+	p += len + 1;
+	if (p >= end) {
 		usdt_error(out, EINVAL, "Incomplete note data");
 		return -1;
 	}
@@ -510,9 +567,14 @@ parse_usdt_note(int out, dof_helper_t *dhp, usdt_data_t *data,
 	prp->is_enabled = (note->hdr->n_type == _USDT_EN_NOTE_TYPE ? 1 : 0);
 	prp->ntp = 0;
 	prp->sargc = *p++;
+	len = cstrlen(p, end);
+	if (len == -1) {
+		usdt_error(out, EINVAL, "Unterminated argument string");
+		return -1;
+	}
 	prp->sargs = p;
-	p += strlen(p) + 1;
-	if (p - note->desc > note->hdr->n_descsz) {
+	p += len + 1;
+	if (p > end) {
 		usdt_error(out, EINVAL, "Incomplete note data");
 		return -1;
 	}
@@ -537,22 +599,22 @@ alloc_msg(int out, dof_parsed_info_t type, size_t len)
 
 	switch (type) {
 	case DIT_PROVIDER:
-		len += offsetof(dof_parsed_t, provider.name);
+		len += DIT_PROVIDER_HEADSZ;
 		break;
 	case DIT_PROBE:
-		len += offsetof(dof_parsed_t, probe.name);
+		len += DIT_PROBE_HEADSZ;
 		break;
 	case DIT_ARGS_NATIVE:
-		len += offsetof(dof_parsed_t, nargs.args);
+		len += DIT_ARGS_NATIVE_HEADSZ;
 		break;
 	case DIT_ARGS_XLAT:
-		len += offsetof(dof_parsed_t, xargs.args);
+		len += DIT_ARGS_XLAT_HEADSZ;
 		break;
 	case DIT_ARGS_MAP:
-		len += offsetof(dof_parsed_t, argmap.argmap);
+		len += DIT_ARGS_MAP_HEADSZ;
 		break;
 	case DIT_TRACEPOINT:
-		len += offsetof(dof_parsed_t, tracepoint.args);
+		len += DIT_TRACEPOINT_HEADSZ;
 		break;
 	default:
 		usdt_error(out, EINVAL, "Unknown dof_parsed_t type: %d", type);
diff --git a/libdtrace/dt_pid.c b/libdtrace/dt_pid.c
index 7e6e5d90..e20bc82b 100644
--- a/libdtrace/dt_pid.c
+++ b/libdtrace/dt_pid.c
@@ -782,25 +782,93 @@ err:
 }
 
 /*
- * A quick check that a parsed DOF record read hasn't incurred a buffer overrun
- * and is of the type expected.
+ * Ensure that the buffer has enough data to read the record of the expected
+ * type.  Ensure that all records have at least 1 byte of payload data.
  */
 static int
 validate_dof_record(const char *path, const dof_parsed_t *parsed,
-		    dof_parsed_info_t expected, size_t buf_size,
+		    dof_parsed_info_t type, size_t headsz, size_t buf_size,
 		    size_t seen_size)
 {
-	if (buf_size < seen_size) {
+	size_t	data_size;
+
+	/* If we have read more than there is, we must always fail. */
+	if (buf_size < seen_size)
+		data_size = 0;
+	else
+		data_size = buf_size - seen_size;
+
+	if (data_size < headsz || data_size < parsed->size) {
 		dt_dprintf("DOF too small when adding probes (seen %zi bytes)\n",
 			   seen_size);
 		return 0;
 	}
 
-	if (parsed->type != expected) {
+	if (parsed->size < headsz + 1) {
+		dt_dprintf("DOF record too small: expected %zi, got %zi\n",
+			   headsz, parsed->size);
+		return 0;
+	}
+
+	if (parsed->type != type) {
 		dt_dprintf("%s format invalid: expected %i, got %i\n", path,
-			   expected, parsed->type);
+			   type, parsed->type);
 		return 0;
 	}
+
+	return 1;
+}
+
+/*
+ * Validate a payload containing CNT consecutive NUL-terminated strings.
+ */
+static int
+validate_string_payload(const char *path, const char *payload,
+			size_t payload_size, size_t cnt)
+{
+	const char	*p = payload;
+	const char	*end = payload + payload_size;
+	size_t		i;
+
+	for (i = 0; i < cnt; i++) {
+		const char	*nul;
+
+		if (p >= end) {
+			dt_dprintf("%s string payload too small\n", path);
+			return 0;
+		}
+
+		nul = memchr(p, '\0', end - p);
+		if (nul == NULL) {
+			dt_dprintf("%s string payload unterminated\n", path);
+			return 0;
+		}
+
+		p = nul + 1;
+	}
+
+	return 1;
+}
+
+static int
+validate_argmap_payload(const char *path, const uint8_t *argmap,
+			size_t payload_size, size_t nargc, size_t xargc)
+{
+	size_t	i;
+
+	if (payload_size < xargc * sizeof(uint8_t)) {
+		dt_dprintf("%s argmap payload too small\n", path);
+		return 0;
+	}
+
+	for (i = 0; i < xargc; i++) {
+		if (argmap[i] >= nargc) {
+			dt_dprintf("%s argmap entry %zi invalid: %u >= %zi\n",
+				   path, i, argmap[i], nargc);
+			return 0;
+		}
+	}
+
 	return 1;
 }
 
@@ -908,13 +976,13 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 		char *dof_buf = NULL, *p;
 		struct stat s;
 		char *path;
-		size_t dof_buf_size, seen_size = 0;
+		size_t dof_buf_size, seen_size = 0, payload_size;
 		uint64_t *dof_version;
 		char *prv, *mod, *fun, *prb;
 		dof_parsed_t *provider, *probe;
 		ssize_t nargvlen = 0, xargvlen = 0;
 		char *nargv = NULL, *xargv = NULL;
-		int8_t *argmap = NULL;
+		uint8_t *argmap = NULL;
 
 		/*
 		 * Regular files only: in particular, skip . and ..,
@@ -929,7 +997,7 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 			goto per_mapping_err;
 
 		dof_buf = read_file(path, &dof_buf_size);
-		if (dof_buf == NULL)
+		if (dof_buf == NULL || dof_buf_size < sizeof(uint64_t))
 			goto per_mapping_err;
 		dof_version = (uint64_t *) dof_buf;
 		if (*dof_version != DOF_PARSED_VERSION) {
@@ -945,27 +1013,50 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 		 * probe.
 		 */
 		provider = (dof_parsed_t *) p;
-		if (!validate_dof_record(path, provider, DIT_PROVIDER, dof_buf_size,
+		if (!validate_dof_record(path, provider, DIT_PROVIDER,
+					 DIT_PROVIDER_HEADSZ, dof_buf_size,
 					 seen_size))
 			goto parse_err;
 
+		/*
+		 * Ensure that a validly terminated string follows the record
+		 * header.
+		 */
 		prv = provider->provider.name;
+		payload_size = provider->size - DIT_PROVIDER_HEADSZ;
+		if (memchr(prv, '\0', payload_size) == NULL)
+			goto parse_err;
 
 		p += provider->size;
 		seen_size += provider->size;
 
 		probe = (dof_parsed_t *) p;
-		if (!validate_dof_record(path, probe, DIT_PROBE, dof_buf_size,
+		if (!validate_dof_record(path, probe, DIT_PROBE,
+					 DIT_PROBE_HEADSZ, dof_buf_size,
 					 seen_size))
 			goto parse_err;
 
 		mod = probe->probe.name;
+		payload_size = probe->size - DIT_PROBE_HEADSZ;
+		if (memchr(mod, '\0', payload_size) == NULL)
+			goto parse_err;
+
 		fun = mod + strlen(mod) + 1;
+		payload_size -= strlen(mod) + 1;
+		if (memchr(fun, '\0', payload_size) == NULL)
+			goto parse_err;
 		prb = fun + strlen(fun) + 1;
+		payload_size -= strlen(fun) + 1;
+		if (memchr(prb, '\0', payload_size) == NULL)
+			goto parse_err;
 
 		p += probe->size;
 		seen_size += probe->size;
 
+		if (probe->probe.nargc > UINT8_MAX ||
+		    probe->probe.xargc > UINT8_MAX)
+			goto parse_err;
+
 		/*
 		 * Assume the order given in dof_parser.h, for simplicity.
 		 */
@@ -973,11 +1064,16 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 			dof_parsed_t *args = (dof_parsed_t *) p;
 
 			if (!validate_dof_record(path, args, DIT_ARGS_NATIVE,
+						 DIT_ARGS_NATIVE_HEADSZ,
 						 dof_buf_size, seen_size))
 				goto parse_err;
 
 			nargv = args->nargs.args;
-			nargvlen = args->size - offsetof(dof_parsed_t, nargs.args);
+			payload_size = args->size - DIT_ARGS_NATIVE_HEADSZ;
+			if (!validate_string_payload(path, nargv, payload_size,
+						     probe->probe.nargc))
+				goto parse_err;
+			nargvlen = payload_size;
 			assert(nargvlen >= 0);
 
 			p += args->size;
@@ -987,11 +1083,16 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 			dof_parsed_t *args = (dof_parsed_t *) p;
 
 			if (!validate_dof_record(path, args, DIT_ARGS_XLAT,
+						 DIT_ARGS_XLAT_HEADSZ,
 						 dof_buf_size, seen_size))
 				goto parse_err;
 
 			xargv = args->xargs.args;
-			xargvlen = args->size - offsetof(dof_parsed_t, xargs.args);
+			payload_size = args->size - DIT_ARGS_XLAT_HEADSZ;
+			if (!validate_string_payload(path, xargv, payload_size,
+						     probe->probe.xargc))
+				goto parse_err;
+			xargvlen = payload_size;
 			assert(xargvlen >= 0);
 
 			p += args->size;
@@ -999,10 +1100,16 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 			args = (dof_parsed_t *) p;
 
 			if (!validate_dof_record(path, args, DIT_ARGS_MAP,
+						 DIT_ARGS_MAP_HEADSZ,
 						 dof_buf_size, seen_size))
 				goto parse_err;
 
 			argmap = args->argmap.argmap;
+			payload_size = args->size - DIT_ARGS_MAP_HEADSZ;
+			if (!validate_argmap_payload(path, argmap, payload_size,
+						     probe->probe.nargc,
+						     probe->probe.xargc))
+				goto parse_err;
 
 			p += args->size;
 			seen_size += args->size;
@@ -1017,6 +1124,7 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 			const prmap_t *pmp;
 
 			if (!validate_dof_record(path, tp, DIT_TRACEPOINT,
+						 DIT_TRACEPOINT_HEADSZ,
 						 dof_buf_size, seen_size))
 				goto parse_err;
 
@@ -1073,9 +1181,15 @@ dt_pid_create_usdt_probes_proc(dtrace_hdl_t *dtp, pid_t pid, dt_proc_t *dpr,
 			if (argmap)
 				psp.pps_argmap = argmap;
 
-			if (tp->tracepoint.args[0] != 0)
+			if (tp->tracepoint.args[0] != 0) {
 				psp.pps_sargv = tp->tracepoint.args;
 
+				payload_size = tp->size - DIT_TRACEPOINT_HEADSZ;
+				if (memchr(psp.pps_sargv, '\0',
+					   payload_size) == NULL)
+					goto parse_err;
+			}
+
 			dt_dprintf("providing %s:%s:%s:%s for pid %d @ %lx\n",
 				   psp.pps_prv, psp.pps_mod, psp.pps_fun,
 				   psp.pps_prb, psp.pps_pid, psp.pps_off);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-06-12 16:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-12 16:22 [PATCH 2/6] usdt_parser: harden DOF and note bounds checks Kris Van Hees

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox