[DTrace-devel] [PATCH 09/12] Add BPF helper mapping

Kris Van Hees kris.van.hees at oracle.com
Wed Jul 13 19:17:56 UTC 2022


BPF helpers can be very specific to kernel versions, and the set of
available helpers may differ between the system where DTrace was
compiled and the system where it is being used.

We add runtime checking of specific BPF helpers, with support for
possible fallback hwlpers.  E.g. if probe_read_user() is not found,
we can use probe_read() instead (though that may not guarantee
successful execution).

This can also be used to check whether certain helpers exist.  By
convention, when the BPF helper function id maps to 0, the helper is
known not to be supported on the runtime system,

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
 libdtrace/dt_bpf.c  | 60 +++++++++++++++++++++++++++++++++++++++++++++
 libdtrace/dt_bpf.h  |  1 +
 libdtrace/dt_impl.h |  1 +
 libdtrace/dt_open.c |  3 +++
 4 files changed, 65 insertions(+)

diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index c008f624..269c6e1d 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -152,6 +152,66 @@ int dt_bpf_map_update(int fd, const void *key, const void *val)
 	return bpf(BPF_MAP_UPDATE_ELEM, &attr);
 }
 
+static int
+have_helper(uint32_t func_id)
+{
+	uint64_t	logsz = 4096;
+	char		log[logsz];
+	char		*ptr = &log[0];
+	struct bpf_insn	insns[] = {
+				BPF_CALL_HELPER(func_id),
+				BPF_RETURN()
+			};
+	dtrace_difo_t	dp;
+
+	dp.dtdo_buf = insns;
+	dp.dtdo_len = ARRAY_SIZE(insns);
+
+	/* If the program loads, we can use the helper. */
+	if (dt_bpf_prog_load(BPF_PROG_TYPE_KPROBE, &dp, 1, log, logsz) > 0)
+		return 1;
+
+	/* Permission denied -> helper not available to us */
+	if (errno == EPERM)
+		return 0;
+
+	/*
+	 * Skip past leading 0-bytes, but ensure there is a sentinel so that
+	 * the loop is guaranteed to end.
+	 */
+	log[logsz - 2] = 0;
+	log[logsz - 1] = ' ';
+	while (*ptr == 0)
+		ptr++;
+
+	/*
+	 * If an 'invalid func' or 'unknown func' failure is reported, we
+	 * cannot use the helper.
+	 */
+	return strstr(ptr, "invalid func") == NULL &&
+	       strstr(ptr, "unknown func") == NULL;;
+}
+
+void
+dt_bpf_init_helpers(dtrace_hdl_t *dtp)
+{
+	uint32_t	i;
+
+	/* Assume all helpers are available. */
+	for (i = 0; i < __BPF_FUNC_MAX_ID; i++)
+		dtp->dt_bpfhelper[i] = i;
+
+	/* Verify the existance of some specific helpers. */
+#define BPF_HELPER_MAP(orig, alt)	\
+	if (!have_helper(BPF_FUNC_##orig)) \
+			dtp->dt_bpfhelper[BPF_FUNC_##orig] = BPF_FUNC_##alt;
+	BPF_HELPER_MAP(probe_read_user, probe_read);
+	BPF_HELPER_MAP(probe_read_user_str, probe_read_str);
+	BPF_HELPER_MAP(probe_read_kernel, probe_read);
+	BPF_HELPER_MAP(probe_read_kernel_str, probe_read_str);
+#undef BPF_HELPER_MAP
+}
+
 static int
 create_gmap(dtrace_hdl_t *dtp, const char *name, enum bpf_map_type type,
 	    int ksz, int vsz, int size)
diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
index c4c6e717..fbff8437 100644
--- a/libdtrace/dt_bpf.h
+++ b/libdtrace/dt_bpf.h
@@ -48,6 +48,7 @@ extern int dt_bpf_map_lookup(int fd, const void *key, void *val);
 extern int dt_bpf_map_update(int fd, const void *key, const void *val);
 extern int dt_bpf_map_delete(int fd, const void *key);
 extern int dt_bpf_load_progs(struct dtrace_hdl *, uint_t);
+extern void dt_bpf_init_helpers(struct dtrace_hdl *dtp);
 
 #ifdef	__cplusplus
 }
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 747815ac..6e909dad 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -376,6 +376,7 @@ struct dtrace_hdl {
 	uint_t dt_treedump;	/* dtrace tree debug bitmap (see below) */
 	uint_t dt_disasm;	/* dtrace disassembler bitmap (see below) */
 	uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */
+	uint32_t dt_bpfhelper[__BPF_FUNC_MAX_ID]; /* BPF helper mapping */
 	int dt_version;		/* library version requested by client */
 	int dt_ctferr;		/* error resulting from last CTF failure */
 	int dt_errno;		/* error resulting from last failed operation */
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index deea0781..fa8aade8 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -28,6 +28,7 @@
 #include <libproc.h>
 
 #include <dt_impl.h>
+#include <dt_bpf.h>
 #include <dt_pcap.h>
 #include <dt_program.h>
 #include <dt_module.h>
@@ -1136,6 +1137,8 @@ dt_vopen(int version, int flags, int *errp,
 	if (dtrace_setopt(dtp, "libdir", _dtrace_libdir) != 0)
 		return set_open_errno(dtp, errp, dtp->dt_errno);
 
+	dt_bpf_init_helpers(dtp);
+
 	return dtp;
 }
 
-- 
2.34.1




More information about the DTrace-devel mailing list