All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eugene Loh <eugene.loh@oracle.com>
To: Kris Van Hees <kris.van.hees@oracle.com>,
	dtrace@lists.linux.dev, dtrace-devel@oss.oracle.com
Subject: Re: [DTrace-devel] [PATCH 4/4] rawfbt: selectively allow return() in clauses
Date: Tue, 15 Jul 2025 17:22:42 -0400	[thread overview]
Message-ID: <97ca9d19-12b9-a99e-4710-414d6dadbcbe@oracle.com> (raw)
In-Reply-To: <SJ0PR10MB5672917714933FF0262E814DC257A@SJ0PR10MB5672.namprd10.prod.outlook.com>

[-- Attachment #1: Type: text/plain, Size: 9311 bytes --]

I'm late to the party, sorry.

For usability, could an error message point to 
/sys/kernel/debug/error_injection/list?  Might as well provide useful 
information at the time of encounter.

When you parse the list, you expect the function name to be terminated 
with a space.  When I look at my list, only 7 (out of nearly 1000) are 
so terminated.  Shouldn't you check for a space *OR* a tab?

When I run the tests, I get an OL8 UEK6 failure on x86 for 
test/unittest/actions/return/tst.destructive.d:
dtrace: could not enable tracing: Failed to enable 
rawfbt:btrfs:open_ctree:entry: No such file or directory

Also, there should be a test to check that return() actually does the 
right thing.  I'm attaching a proposal.

Typos:  "injexction" in the commit msg and raa as Nick previously noted.

On 7/15/25 01:48, Kris Van Hees via DTrace-devel wrote:

> The return() action is only allowed in clauses associated with a rawfbt
> probe on a function listed in /sys/kernel/debug/error_injexction/list.
> Use a reject_clause() callback in the rawfbt provider to enforce this.
>
> The list of allowed function is only initialized the first time it is
> needed, and its content will be stored in a hashtable for faster
> lookup beyond the first.
>
> Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
> ---
>   libdtrace/dt_prov_fbt.c                       | 134 ++++++++++++++++++
>   .../actions/return/err.not_allowed-1.d        |  27 ++++
>   .../actions/return/err.not_allowed-1.r        |   2 +
>   .../actions/return/err.not_allowed-2.d        |  27 ++++
>   .../actions/return/err.not_allowed-2.r        |   2 +
>   .../actions/return/err.not_allowed-3.d        |  27 ++++
>   .../actions/return/err.not_allowed-3.r        |   2 +
>   7 files changed, 221 insertions(+)
>   create mode 100644 test/unittest/actions/return/err.not_allowed-1.d
>   create mode 100644 test/unittest/actions/return/err.not_allowed-1.r
>   create mode 100644 test/unittest/actions/return/err.not_allowed-2.d
>   create mode 100644 test/unittest/actions/return/err.not_allowed-2.r
>   create mode 100644 test/unittest/actions/return/err.not_allowed-3.d
>   create mode 100644 test/unittest/actions/return/err.not_allowed-3.r
>
> diff --git a/libdtrace/dt_prov_fbt.c b/libdtrace/dt_prov_fbt.c
> index 50fa0d9d..b98d8d87 100644
> --- a/libdtrace/dt_prov_fbt.c
> +++ b/libdtrace/dt_prov_fbt.c
> @@ -591,6 +591,139 @@ static void kprobe_detach(dtrace_hdl_t *dtp, const dt_probe_t *prp)
>   		free(tpn);
>   }
>   
> +/*
> + * raafbt only:
> + *
> + * Accept all clauses, except those that use the return() action in a function
> + * that does not allow error rejection.
> + */
> +#define FUNCS_ALLOW_RETURN	"/sys/kernel/debug/error_injection/list"
> +
> +typedef struct allowed_fn {
> +	const char	*mod;
> +	const char	*fun;
> +	dt_hentry_t	he;
> +} allowed_fun_t;
> +
> +static uint32_t
> +fun_hval(const allowed_fun_t *p)
> +{
> +	return str2hval(p->fun, p->mod ? str2hval(p->mod, 0) : 0);
> +}
> +
> +static int
> +fun_cmp(const allowed_fun_t *p, const allowed_fun_t *q) {
> +	int	rc;
> +
> +	if (p->mod != NULL) {
> +		if (q->mod == NULL)
> +			return 1;
> +		else {
> +			rc = strcmp(p->mod, q->mod);
> +			if (rc != 0)
> +				return rc;
> +		}
> +	} else if (q->mod != NULL)
> +		return -1;
> +
> +	return strcmp(p->fun, q->fun);
> +}
> +
> +DEFINE_HE_STD_LINK_FUNCS(fun, allowed_fun_t, he)
> +
> +static void *
> +fun_del_entry(allowed_fun_t *head, allowed_fun_t *p)
> +{
> +	head = fun_del(head, p);
> +
> +	free((char *)p->mod);
> +	free((char *)p->fun);
> +	free(p);
> +
> +	return head;
> +}
> +
> +static dt_htab_ops_t fun_htab_ops = {
> +	.hval = (htab_hval_fn)fun_hval,
> +	.cmp = (htab_cmp_fn)fun_cmp,
> +	.add = (htab_add_fn)fun_add,
> +	.del = (htab_del_fn)fun_del_entry,
> +	.next = (htab_next_fn)fun_next
> +};
> +
> +static void reject_clause(const dt_probe_t *prp, int clsflags)
> +{
> +	dt_htab_t	*atab = prp->prov->prv_data;
> +	allowed_fun_t	tmpl;
> +
> +	/* If the clause does not have a return() action, allow it. */
> +	if (!(clsflags & DT_CLSFLAG_RETURN))
> +		return;
> +
> +	/*
> +	 * If the htab of allowed functions for return() does not exist yet,
> +	 * create it.
> +	 */
> +	if (atab == NULL) {
> +		FILE		*f;
> +		char		*buf = NULL;
> +		size_t		len = 0;
> +		allowed_fun_t	*entry;
> +
> +		atab = dt_htab_create(&fun_htab_ops);
> +		if (atab == NULL)
> +			return;
> +
> +		prp->prov->prv_data = atab;
> +
> +		f = fopen(FUNCS_ALLOW_RETURN, "r");
> +		if (f == NULL)
> +			return;
> +
> +		while (getline(&buf, &len, f) >= 0) {
> +			char	*p;
> +
> +			entry = (allowed_fun_t *)malloc(sizeof(allowed_fun_t));
> +			if (entry == NULL)
> +				break;
> +
> +			p = strchr(buf, ' ');
> +			if (p) {
> +				*p++ = '\0';
> +				if (*p == '[') {
> +					char	*q;
> +
> +					p++;
> +					q = strchr(p, ']');
> +					if (q)
> +						*q = '\0';
> +				} else
> +					p = NULL;
> +			}
> +
> +			entry->fun = strdup(buf);
> +			entry->mod = p != NULL ? strdup(p) : NULL;
> +
> +			if (dt_htab_insert(atab, entry) < 0)
> +				return;
> +		}
> +
> +		fclose(f);
> +	}
> +
> +	tmpl.mod = prp->desc->mod;
> +	tmpl.fun = prp->desc->fun;
> +	if (dt_htab_lookup(atab, &tmpl) != NULL)
> +		return;
> +
> +	tmpl.mod = NULL;
> +	if (dt_htab_lookup(atab, &tmpl) != NULL)
> +		return;
> +
> +	xyerror(D_ACT_RETURN, "return() not allowed for %s:%s:%s:%s\n",
> +		prp->desc->prv, prp->desc->mod, prp->desc->fun, prp->desc->prb);
> +}
> +
>   dt_provimpl_t	dt_fbt_fprobe = {
>   	.name		= prvname,
>   	.prog_type	= BPF_PROG_TYPE_TRACING,
> @@ -628,6 +761,7 @@ dt_provimpl_t	dt_rawfbt = {
>   	.populate	= &populate,
>   	.provide	= &provide,
>   	.load_prog	= &dt_bpf_prog_load,
> +	.reject_clause	= &reject_clause,
>   	.trampoline	= &kprobe_trampoline,
>   	.attach		= &kprobe_attach,
>   	.detach		= &kprobe_detach,
> diff --git a/test/unittest/actions/return/err.not_allowed-1.d b/test/unittest/actions/return/err.not_allowed-1.d
> new file mode 100644
> index 00000000..246a68b1
> --- /dev/null
> +++ b/test/unittest/actions/return/err.not_allowed-1.d
> @@ -0,0 +1,27 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: return() is not allowed for fbt probes
> + *
> + * SECTION: Actions and Subroutines/return()
> + */
> +
> +#pragma D option quiet
> +#pragma D option destructive
> +
> +BEGIN
> +{
> +	ok = 0;
> +	exit(0);
> +}
> +
> +fbt:btrfs:open_ctree:entry
> +/ok/
> +{
> +	return(0);
> +}
> diff --git a/test/unittest/actions/return/err.not_allowed-1.r b/test/unittest/actions/return/err.not_allowed-1.r
> new file mode 100644
> index 00000000..e3443c30
> --- /dev/null
> +++ b/test/unittest/actions/return/err.not_allowed-1.r
> @@ -0,0 +1,2 @@
> +-- @@stderr --
> +dtrace: could not enable tracing: return() not allowed for fbt:btrfs:open_ctree:entry
> diff --git a/test/unittest/actions/return/err.not_allowed-2.d b/test/unittest/actions/return/err.not_allowed-2.d
> new file mode 100644
> index 00000000..e0d303c7
> --- /dev/null
> +++ b/test/unittest/actions/return/err.not_allowed-2.d
> @@ -0,0 +1,27 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: return() is only allowed for select functions
> + *
> + * SECTION: Actions and Subroutines/return()
> + */
> +
> +#pragma D option quiet
> +#pragma D option destructive
> +
> +BEGIN
> +{
> +	ok = 0;
> +	exit(0);
> +}
> +
> +rawfbt:btrfs:close_ctree:entry
> +/ok/
> +{
> +	return(0);
> +}
> diff --git a/test/unittest/actions/return/err.not_allowed-2.r b/test/unittest/actions/return/err.not_allowed-2.r
> new file mode 100644
> index 00000000..758d3477
> --- /dev/null
> +++ b/test/unittest/actions/return/err.not_allowed-2.r
> @@ -0,0 +1,2 @@
> +-- @@stderr --
> +dtrace: could not enable tracing: return() not allowed for rawfbt:btrfs:close_ctree:entry
> diff --git a/test/unittest/actions/return/err.not_allowed-3.d b/test/unittest/actions/return/err.not_allowed-3.d
> new file mode 100644
> index 00000000..770565c9
> --- /dev/null
> +++ b/test/unittest/actions/return/err.not_allowed-3.d
> @@ -0,0 +1,27 @@
> +/*
> + * Oracle Linux DTrace.
> + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
> + * Licensed under the Universal Permissive License v 1.0 as shown at
> + * http://oss.oracle.com/licenses/upl.
> + */
> +
> +/*
> + * ASSERTION: return() is only allowed for select functions
> + *
> + * SECTION: Actions and Subroutines/return()
> + */
> +
> +#pragma D option quiet
> +#pragma D option destructive
> +
> +BEGIN
> +{
> +	ok = 0;
> +	exit(0);
> +}
> +
> +rawfbt:btrfs:*_ctree:entry
> +/ok/
> +{
> +	return(0);
> +}
> diff --git a/test/unittest/actions/return/err.not_allowed-3.r b/test/unittest/actions/return/err.not_allowed-3.r
> new file mode 100644
> index 00000000..758d3477
> --- /dev/null
> +++ b/test/unittest/actions/return/err.not_allowed-3.r
> @@ -0,0 +1,2 @@
> +-- @@stderr --
> +dtrace: could not enable tracing: return() not allowed for rawfbt:btrfs:close_ctree:entry

[-- Attachment #2: 0001-test.patch --]
[-- Type: text/plain, Size: 2776 bytes --]

From a6a6ceb614fadd5c5d1116cc05fe71da2b2dbff7 Mon Sep 17 00:00:00 2001
From: Eugene Loh <eugene.loh@oracle.com>
Date: Tue, 15 Jul 2025 13:33:04 -0700
Subject: [PATCH] test

Signed-off-by: Eugene Loh <eugene.loh@oracle.com>
---
 .../actions/return/tst.destructive-getpid.r   | 12 +++++
 .../actions/return/tst.destructive-getpid.r.p | 10 ++++
 .../actions/return/tst.destructive-getpid.sh  | 48 +++++++++++++++++++
 3 files changed, 70 insertions(+)
 create mode 100644 test/unittest/actions/return/tst.destructive-getpid.r
 create mode 100755 test/unittest/actions/return/tst.destructive-getpid.r.p
 create mode 100755 test/unittest/actions/return/tst.destructive-getpid.sh

diff --git a/test/unittest/actions/return/tst.destructive-getpid.r b/test/unittest/actions/return/tst.destructive-getpid.r
new file mode 100644
index 00000000..b6bdf211
--- /dev/null
+++ b/test/unittest/actions/return/tst.destructive-getpid.r
@@ -0,0 +1,12 @@
+pid is mypid
+mypid
+22222
+mypid
+mypid
+55555
+mypid
+mypid
+mypid
+mypid
+mypid
+
diff --git a/test/unittest/actions/return/tst.destructive-getpid.r.p b/test/unittest/actions/return/tst.destructive-getpid.r.p
new file mode 100755
index 00000000..d6593c46
--- /dev/null
+++ b/test/unittest/actions/return/tst.destructive-getpid.r.p
@@ -0,0 +1,10 @@
+#!/usr/bin/gawk -f
+
+BEGIN { mypid = -1 }
+
+/^pid is [1-9][0-9]*$/ { mypid = $3; }
+
+{
+        if ( $NF == mypid ) $NF = "mypid";
+        print;
+}
diff --git a/test/unittest/actions/return/tst.destructive-getpid.sh b/test/unittest/actions/return/tst.destructive-getpid.sh
new file mode 100755
index 00000000..7c44dde9
--- /dev/null
+++ b/test/unittest/actions/return/tst.destructive-getpid.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+#
+
+dtrace=$1
+
+# Set up test directory.
+
+DIRNAME=$tmpdir/destructive-getpid.$$.$RANDOM
+mkdir -p $DIRNAME
+cd $DIRNAME
+
+# Make the trigger.  It reports the pid 10 times.
+
+cat << EOF > main.c
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int c, char **v) {
+	int i;
+
+	for (i = 0; i < 10; i++)
+		printf("%d\n", getpid());
+
+	return 0;
+}
+EOF
+
+$CC main.c
+if [ $? -ne 0 ]; then
+	echo ERROR: compile
+	exit 1
+fi
+
+# Trace the trigger.  On the 2nd and 5th getpid() calls, modify the result.
+
+$dtrace -c ./a.out -w -q -n '
+BEGIN { printf("pid is %d\n", $target); n = 0; }
+rawfbt:vmlinux:__*_sys_getpid:entry /pid == $target/ { n++ }
+rawfbt:vmlinux:__*_sys_getpid:entry /pid == $target && n == 2/ { return(22222); }
+rawfbt:vmlinux:__*_sys_getpid:entry /pid == $target && n == 5/ { return(55555); }
+'
+
+exit $?
-- 
2.18.4


  parent reply	other threads:[~2025-07-15 21:22 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-15  5:48 [PATCH 4/4] rawfbt: selectively allow return() in clauses Kris Van Hees
2025-07-15 10:50 ` [DTrace-devel] " Nick Alcock
2025-07-15 16:06   ` Kris Van Hees
2025-07-16 11:08     ` Nick Alcock
2025-07-15 21:22 ` Eugene Loh [this message]
2025-07-15 21:39   ` Kris Van Hees

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=97ca9d19-12b9-a99e-4710-414d6dadbcbe@oracle.com \
    --to=eugene.loh@oracle.com \
    --cc=dtrace-devel@oss.oracle.com \
    --cc=dtrace@lists.linux.dev \
    --cc=kris.van.hees@oracle.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.