summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-06 23:34:15 +0100
committerMark Brown <broonie@kernel.org>2026-07-06 23:34:15 +0100
commitbf2cecaae4fb165639deaed6983124d0602264f3 (patch)
treedb05a6a3ef710d2b8806d71bfd303fc4bab3f30b /tools
parentf29a8bf6fde130313ec77c89d7612100ff5bafb2 (diff)
parentd37664f99ef94f7a7bbca4b5ddcb7ab5c801f2e1 (diff)
regulator: qcom_usb_vbus: add pm4125 VBUS regulator support
Rakesh Kota <rakesh.kota@oss.qualcomm.com> says: Add support for PM4125 USB VBUS regulator. Unlike PM8150B which uses a current-limit selector, PM4125 uses a 2-bit VBOOST voltage selector supporting 4.25 V, 4.5 V, 4.75 V and 5.0 V output. Link: https://patch.msgid.link/20260706-add_pm4125-vbus-reg-v3-0-999d78a87b81@oss.qualcomm.com
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/cxl/test/mem.c1
-rw-r--r--tools/testing/selftests/bpf/prog_tests/sockmap_strp.c31
-rw-r--r--tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c34
-rw-r--r--tools/testing/selftests/bpf/progs/sockmap_parse_prog.c22
-rw-r--r--tools/testing/selftests/bpf/progs/test_sockmap_strp.c7
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_unpriv.c19
-rwxr-xr-xtools/testing/selftests/drivers/net/hw/tso.py16
-rw-r--r--tools/testing/selftests/filesystems/.gitignore1
-rw-r--r--tools/testing/selftests/filesystems/Makefile4
-rw-r--r--tools/testing/selftests/filesystems/idmapped_tmpfile.c168
-rw-r--r--tools/testing/selftests/net/lib/py/utils.py4
-rw-r--r--tools/testing/selftests/vfio/Makefile2
-rw-r--r--tools/testing/selftests/vfio/lib/libvfio.mk2
-rw-r--r--tools/testing/selftests/x86/test_shadow_stack.c86
14 files changed, 360 insertions, 37 deletions
diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c
index a1d170f88fee..a7da279aa3ef 100644
--- a/tools/testing/cxl/test/mem.c
+++ b/tools/testing/cxl/test/mem.c
@@ -2,7 +2,6 @@
// Copyright(c) 2021 Intel Corporation. All rights reserved.
#include <linux/platform_device.h>
-#include <linux/mod_devicetable.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c b/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c
index 621b3b71888e..1d7231728eaf 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c
@@ -431,6 +431,35 @@ out:
test_sockmap_strp__destroy(strp);
}
+static void test_sockmap_strp_parser_reject(void)
+{
+ struct test_sockmap_strp *strp = NULL;
+ int parser_mod, parser_ro, link;
+ int err, map;
+
+ strp = test_sockmap_strp__open_and_load();
+ if (!ASSERT_OK_PTR(strp, "test_sockmap_strp__open_and_load"))
+ return;
+
+ map = bpf_map__fd(strp->maps.sock_map);
+ parser_mod = bpf_program__fd(strp->progs.prog_skb_parser_resize);
+ parser_ro = bpf_program__fd(strp->progs.prog_skb_parser);
+
+ err = bpf_prog_attach(parser_mod, map, BPF_SK_SKB_STREAM_PARSER, 0);
+ ASSERT_ERR(err, "bpf_prog_attach parser_mod");
+
+ link = bpf_link_create(parser_ro, map, BPF_SK_SKB_STREAM_PARSER, NULL);
+ if (!ASSERT_GE(link, 0, "bpf_link_create parser_ro"))
+ goto out;
+
+ err = bpf_link_update(link, parser_mod, NULL);
+ ASSERT_ERR(err, "bpf_link_update parser_mod");
+out:
+ if (link >= 0)
+ close(link);
+ test_sockmap_strp__destroy(strp);
+}
+
void test_sockmap_strp(void)
{
if (test__start_subtest("sockmap strp tcp pass"))
@@ -451,4 +480,6 @@ void test_sockmap_strp(void)
test_sockmap_strp_multiple_pkt(AF_INET, SOCK_STREAM);
if (test__start_subtest("sockmap strp tcp dispatch"))
test_sockmap_strp_dispatch_pkt(AF_INET, SOCK_STREAM);
+ if (test__start_subtest("sockmap strp parser reject pkt mod"))
+ test_sockmap_strp_parser_reject();
}
diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
index 7247a20c0a3b..024ef2aae200 100644
--- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c
@@ -13,12 +13,20 @@ struct node_acquire {
struct bpf_refcount refcount;
};
+struct node_refcounted {
+ long key;
+ struct bpf_list_node list;
+ struct bpf_refcount refcount;
+};
+
extern void bpf_rcu_read_lock(void) __ksym;
extern void bpf_rcu_read_unlock(void) __ksym;
#define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8)))
private(A) struct bpf_spin_lock glock;
private(A) struct bpf_rb_root groot __contains(node_acquire, node);
+private(B) struct bpf_spin_lock lock;
+private(B) struct bpf_list_head head __contains(node_refcounted, list);
static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b)
{
@@ -93,6 +101,32 @@ long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx)
return 0;
}
+SEC("?tc")
+__failure __msg("dereference of modified ptr_ ptr R1")
+long refcount_acquire_list_node_offset(void *ctx)
+{
+ struct node_refcounted *node, *base, *ref;
+ struct bpf_list_node *list_node;
+
+ node = bpf_obj_new(typeof(*node));
+ if (!node)
+ return 1;
+
+ bpf_spin_lock(&lock);
+ bpf_list_push_front(&head, &node->list);
+ list_node = bpf_list_pop_front(&head);
+ bpf_spin_unlock(&lock);
+ if (!list_node)
+ return 2;
+
+ base = container_of(list_node, struct node_refcounted, list);
+ ref = bpf_refcount_acquire(list_node);
+ if (ref)
+ bpf_obj_drop(ref);
+ bpf_obj_drop(base);
+ return 0;
+}
+
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
__failure __msg("function calls are not allowed while holding a lock")
int BPF_PROG(rbtree_fail_sleepable_lock_across_rcu,
diff --git a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c
index c9abfe3a11af..56e9aebf05f2 100644
--- a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c
+++ b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c
@@ -5,28 +5,6 @@
SEC("sk_skb1")
int bpf_prog1(struct __sk_buff *skb)
{
- void *data_end = (void *)(long) skb->data_end;
- void *data = (void *)(long) skb->data;
- __u8 *d = data;
- int err;
-
- if (data + 10 > data_end) {
- err = bpf_skb_pull_data(skb, 10);
- if (err)
- return SK_DROP;
-
- data_end = (void *)(long)skb->data_end;
- data = (void *)(long)skb->data;
- if (data + 10 > data_end)
- return SK_DROP;
- }
-
- /* This write/read is a bit pointless but tests the verifier and
- * strparser handler for read/write pkt data and access into sk
- * fields.
- */
- d = data;
- d[7] = 1;
return skb->len;
}
diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_strp.c b/tools/testing/selftests/bpf/progs/test_sockmap_strp.c
index dde3d5bec515..fe88fa6d40bc 100644
--- a/tools/testing/selftests/bpf/progs/test_sockmap_strp.c
+++ b/tools/testing/selftests/bpf/progs/test_sockmap_strp.c
@@ -50,4 +50,11 @@ int prog_skb_parser_partial(struct __sk_buff *skb)
return 10;
}
+SEC("sk_skb/stream_parser")
+int prog_skb_parser_resize(struct __sk_buff *skb)
+{
+ bpf_skb_change_tail(skb, skb->len, 0);
+ return skb->len;
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
index 49f7bd05edad..42de5cff7e52 100644
--- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
+++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
@@ -6,6 +6,8 @@
#include "../../../include/linux/filter.h"
#include "bpf_misc.h"
+extern const int bpf_prog_active __ksym;
+
#define BPF_SK_LOOKUP(func) \
/* struct bpf_sock_tuple tuple = {} */ \
"r2 = 0;" \
@@ -78,6 +80,23 @@ __naked void dummy_prog_loop1_socket(void)
}
SEC("socket")
+__description("unpriv: pseudo btf id log masks address")
+__success_unpriv
+__msg_unpriv("0: (18) r1 = 0x0")
+__not_msg_unpriv("0: (18) r1 = 0x{{[1-9a-f][0-9a-f]*}}")
+__retval_unpriv(0)
+__log_level(2)
+__naked void pseudo_btf_id_log_masks_address(void)
+{
+ asm volatile ("r1 = %[bpf_prog_active] ll;"
+ "r0 = 0;"
+ "exit;"
+ :
+ : __imm_addr(bpf_prog_active)
+ : __clobber_all);
+}
+
+SEC("socket")
__description("unpriv: return pointer")
__success __failure_unpriv __msg_unpriv("R0 leaks addr")
__retval(POINTER_VALUE)
diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py
index 1b789fea8929..802bb4868046 100755
--- a/tools/testing/selftests/drivers/net/hw/tso.py
+++ b/tools/testing/selftests/drivers/net/hw/tso.py
@@ -187,28 +187,24 @@ def query_nic_features(cfg) -> None:
cfg.wanted_features.add(f["name"])
cfg.hw_features = set()
- hw_all_features_cmd = ""
for f in features["hw"]["bits"]["bit"]:
if f.get("value", False):
- feature = f["name"]
- cfg.hw_features.add(feature)
- hw_all_features_cmd += f" {feature} on"
- try:
- ethtool(f"-K {cfg.ifname} {hw_all_features_cmd}")
- except Exception as e:
- ksft_pr(f"WARNING: failure enabling all hw features: {e}")
- ksft_pr("partial gso feature detection may be impacted")
+ cfg.hw_features.add(f["name"])
# Check which features are supported via GSO partial
cfg.partial_features = set()
if 'tx-gso-partial' in cfg.hw_features:
+ seg_features = {f for f in cfg.hw_features if "segmentation" in f}
+ ethtool(f"-K {cfg.ifname} " +
+ " ".join(f"{f} on" for f in seg_features))
+
ethtool(f"-K {cfg.ifname} tx-gso-partial off")
no_partial = set()
features = cfg.ethnl.features_get({"header": {"dev-index": cfg.ifindex}})
for f in features["active"]["bits"]["bit"]:
no_partial.add(f["name"])
- cfg.partial_features = cfg.hw_features - no_partial
+ cfg.partial_features = seg_features - no_partial
ethtool(f"-K {cfg.ifname} tx-gso-partial on")
restore_wanted_features(cfg)
diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore
index 64ac0dfa46b7..a78f894157de 100644
--- a/tools/testing/selftests/filesystems/.gitignore
+++ b/tools/testing/selftests/filesystems/.gitignore
@@ -5,3 +5,4 @@ fclog
file_stressor
anon_inode_test
kernfs_test
+idmapped_tmpfile
diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile
index 85427d7f19b9..a7ec2ba2dd83 100644
--- a/tools/testing/selftests/filesystems/Makefile
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -2,6 +2,10 @@
CFLAGS += $(KHDR_INCLUDES)
TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test fclog
+TEST_GEN_PROGS += idmapped_tmpfile
TEST_GEN_PROGS_EXTENDED := dnotify_test
include ../lib.mk
+
+$(OUTPUT)/idmapped_tmpfile: LDLIBS += -lcap
+$(OUTPUT)/idmapped_tmpfile: utils.c
diff --git a/tools/testing/selftests/filesystems/idmapped_tmpfile.c b/tools/testing/selftests/filesystems/idmapped_tmpfile.c
new file mode 100644
index 000000000000..bc411ab8281e
--- /dev/null
+++ b/tools/testing/selftests/filesystems/idmapped_tmpfile.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/fsuid.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#include <linux/mount.h>
+#include <linux/types.h>
+
+#include "kselftest_harness.h"
+#include "wrappers.h"
+#include "utils.h"
+
+/*
+ * The test mount maps caller-visible ids [0, MAP_RANGE) onto the on-disk range
+ * [MAP_HOST, MAP_HOST + MAP_RANGE). An id outside [0, MAP_RANGE) therefore has
+ * no mapping in the mount and is not representable in the filesystem.
+ */
+#define MAP_HOST 10000
+#define MAP_RANGE 10000
+#define UNMAPPED 50000
+
+#ifndef MOUNT_ATTR_IDMAP
+#define MOUNT_ATTR_IDMAP 0x00100000
+#endif
+
+#ifndef __NR_mount_setattr
+#define __NR_mount_setattr 442
+#endif
+
+static inline int sys_mount_setattr(int dfd, const char *path,
+ unsigned int flags,
+ struct mount_attr *attr, size_t size)
+{
+ return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
+}
+
+/*
+ * Clone @path into a detached mount idmapped so that caller-visible ids
+ * [0, MAP_RANGE) map onto the on-disk ids [MAP_HOST, MAP_HOST + MAP_RANGE).
+ * Returns the mount fd, or -1 if idmapped mounts are not available.
+ */
+static int idmapped_clone(const char *path)
+{
+ struct mount_attr attr = {
+ .attr_set = MOUNT_ATTR_IDMAP,
+ };
+ int fd_tree, userns_fd, ret;
+
+ fd_tree = sys_open_tree(AT_FDCWD, path,
+ OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
+ if (fd_tree < 0)
+ return -1;
+
+ userns_fd = get_userns_fd(MAP_HOST, 0, MAP_RANGE);
+ if (userns_fd < 0) {
+ close(fd_tree);
+ return -1;
+ }
+
+ attr.userns_fd = userns_fd;
+ ret = sys_mount_setattr(fd_tree, "", AT_EMPTY_PATH, &attr, sizeof(attr));
+ close(userns_fd);
+ if (ret) {
+ close(fd_tree);
+ return -1;
+ }
+
+ return fd_tree;
+}
+
+FIXTURE(idmapped_tmpfile) {
+ char dir[64]; /* non-idmapped path to the layer directory */
+};
+
+FIXTURE_SETUP(idmapped_tmpfile)
+{
+ /* Private mount namespace so test mounts need no cleanup. */
+ ASSERT_EQ(unshare(CLONE_NEWNS), 0);
+ ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);
+ ASSERT_EQ(sys_mount("tmpfs", "/tmp", "tmpfs", 0, NULL), 0);
+
+ snprintf(self->dir, sizeof(self->dir), "/tmp/d");
+ ASSERT_EQ(mkdir(self->dir, 0777), 0);
+ /* World-writable so an unmapped caller still passes permission(). */
+ ASSERT_EQ(chmod(self->dir, 0777), 0);
+}
+
+FIXTURE_TEARDOWN(idmapped_tmpfile)
+{
+}
+
+/*
+ * A caller whose fsuid/fsgid have no mapping in the idmapped mount must not be
+ * able to create an O_TMPFILE. Without the check in vfs_tmpfile() the inode
+ * would be created owned by (uid_t)-1 and could then be linked into the
+ * namespace.
+ */
+TEST_F(idmapped_tmpfile, unmapped_caller_is_refused)
+{
+ int mfd, fd;
+
+ mfd = idmapped_clone(self->dir);
+ if (mfd < 0)
+ SKIP(return, "idmapped mounts not supported");
+
+ /* Become a caller outside the mount's [0, MAP_RANGE) range. */
+ setfsgid(UNMAPPED);
+ setfsuid(UNMAPPED);
+ ASSERT_EQ(setfsuid(-1), UNMAPPED);
+
+ fd = openat(mfd, ".", O_TMPFILE | O_WRONLY, 0644);
+ ASSERT_LT(fd, 0);
+ EXPECT_EQ(errno, EOVERFLOW);
+ if (fd >= 0)
+ close(fd);
+
+ EXPECT_EQ(close(mfd), 0);
+}
+
+/*
+ * A mapped caller can create an O_TMPFILE and link it into the namespace; the
+ * ownership round-trips through the mount idmap. This is what makes refusing
+ * the unmapped case above necessary in the first place.
+ */
+TEST_F(idmapped_tmpfile, mapped_caller_creates_and_links)
+{
+ char path[PATH_MAX];
+ struct stat st;
+ int mfd, fd;
+
+ mfd = idmapped_clone(self->dir);
+ if (mfd < 0)
+ SKIP(return, "idmapped mounts not supported");
+
+ /* Caller is uid/gid 0, which maps to MAP_HOST through the mount. */
+ fd = openat(mfd, ".", O_TMPFILE | O_RDWR, 0600);
+ ASSERT_GE(fd, 0);
+
+ ASSERT_EQ(fstat(fd, &st), 0);
+ EXPECT_EQ(st.st_uid, 0);
+ EXPECT_EQ(st.st_gid, 0);
+
+ /* The tmpfile is linkable: splice it into the directory. */
+ ASSERT_EQ(linkat(fd, "", mfd, "linked", AT_EMPTY_PATH), 0);
+ EXPECT_EQ(close(fd), 0);
+
+ ASSERT_EQ(fstatat(mfd, "linked", &st, 0), 0);
+ EXPECT_EQ(st.st_uid, 0);
+ EXPECT_EQ(st.st_gid, 0);
+
+ /* On the underlying, non-idmapped tmpfs it is stored as MAP_HOST. */
+ snprintf(path, sizeof(path), "%s/linked", self->dir);
+ ASSERT_EQ(stat(path, &st), 0);
+ EXPECT_EQ(st.st_uid, MAP_HOST);
+ EXPECT_EQ(st.st_gid, MAP_HOST);
+
+ EXPECT_EQ(close(mfd), 0);
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index 87eae79d01c1..184bb04343f6 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -44,7 +44,7 @@ class cmd:
Use bkg() instead to run a command in the background.
"""
def __init__(self, comm, shell=None, fail=True, expect_fail=False, ns=None,
- background=False, host=None, timeout=5, ksft_ready=None,
+ background=False, host=None, timeout=20, ksft_ready=None,
ksft_wait=None):
if ns:
if hasattr(ns, 'user_ns_path'):
@@ -113,7 +113,7 @@ class cmd:
return stdout, stderr
- def process(self, terminate=True, fail=None, expect_fail=False, timeout=5):
+ def process(self, terminate=True, fail=None, expect_fail=False, timeout=20):
if fail is None:
fail = not terminate
diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index e6e8cb52ab03..2c32c48db509 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -29,8 +29,6 @@ CFLAGS += $(EXTRA_CFLAGS)
LDFLAGS += -pthread
-LDLIBS += -luuid
-
$(TEST_GEN_PROGS): $(OUTPUT)/%: $(OUTPUT)/%.o $(LIBVFIO_O)
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@
diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk
index 2b8d73b7d329..67942b085068 100644
--- a/tools/testing/selftests/vfio/lib/libvfio.mk
+++ b/tools/testing/selftests/vfio/lib/libvfio.mk
@@ -26,6 +26,8 @@ $(LIBVFIO_O_DIRS):
CFLAGS += -I$(LIBVFIO_SRCDIR)/include
+LDLIBS += -luuid
+
$(LIBVFIO_O): $(LIBVFIO_OUTPUT)/%.o : $(LIBVFIO_SRCDIR)/%.c | $(LIBVFIO_O_DIRS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c
index 21af54d5f4ea..3d6ca33edba4 100644
--- a/tools/testing/selftests/x86/test_shadow_stack.c
+++ b/tools/testing/selftests/x86/test_shadow_stack.c
@@ -873,6 +873,86 @@ out:
return err;
}
+/* Keep the CALL first so the function address is exactly the probed CALL. */
+extern void uprobe_call_trigger(void);
+asm (".pushsection .text\n"
+ ".global uprobe_call_target\n"
+ ".type uprobe_call_target, @function\n"
+ "uprobe_call_target:\n"
+ " ret\n"
+ ".size uprobe_call_target, .-uprobe_call_target\n"
+
+ ".global uprobe_call_trigger\n"
+ ".type uprobe_call_trigger, @function\n"
+ "uprobe_call_trigger:\n"
+ " call uprobe_call_target\n"
+ " ret\n"
+ ".size uprobe_call_trigger, .-uprobe_call_trigger\n"
+ ".popsection\n"
+);
+
+/* If CALL emulation misses the shadow stack update, this exits via SIGSEGV. */
+static int test_uprobe_call(void)
+{
+ const size_t attr_sz = sizeof(struct perf_event_attr);
+ const char *file = "/proc/self/exe";
+ int fd = -1, type, err = 1;
+ struct perf_event_attr attr;
+ struct sigaction sa = {};
+ ssize_t offset;
+
+ type = determine_uprobe_perf_type();
+ if (type < 0) {
+ if (type == -ENOENT)
+ printf("[SKIP]\tUprobe on CALL test, uprobes are not available\n");
+ return 0;
+ }
+
+ offset = get_uprobe_offset(uprobe_call_trigger);
+ if (offset < 0)
+ return 1;
+
+ sa.sa_sigaction = segv_gp_handler;
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGSEGV, &sa, NULL))
+ return 1;
+
+ /* Setup entry uprobe through perf event interface. */
+ memset(&attr, 0, attr_sz);
+ attr.size = attr_sz;
+ attr.type = type;
+ attr.config = 0;
+ attr.config1 = (__u64)(unsigned long)file;
+ attr.config2 = offset;
+
+ fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */,
+ -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
+ if (fd < 0)
+ goto out;
+
+ if (sigsetjmp(jmp_buffer, 1))
+ goto out;
+
+ if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK))
+ goto out;
+
+ /*
+ * This either segfaults and goes through sigsetjmp above
+ * or succeeds and we're good.
+ */
+ uprobe_call_trigger();
+
+ printf("[OK]\tUprobe on CALL test\n");
+ err = 0;
+
+out:
+ ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
+ signal(SIGSEGV, SIG_DFL);
+ if (fd >= 0)
+ close(fd);
+ return err;
+}
+
void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)
{
/* The SSP adjustment caused a segfault. */
@@ -1071,6 +1151,12 @@ int main(int argc, char *argv[])
goto out;
}
+ if (test_uprobe_call()) {
+ ret = 1;
+ printf("[FAIL]\tuprobe on CALL test\n");
+ goto out;
+ }
+
return ret;
out: