diff mbox series

[PATCHv5,bpf-next,7/8] selftests/x86: Add return uprobe shadow stack test

Message ID 20240507105321.71524-8-jolsa@kernel.org (mailing list archive)
State Handled Elsewhere
Delegated to: BPF
Headers show
Series uprobe: uretprobe speed up | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18

Commit Message

Jiri Olsa May 7, 2024, 10:53 a.m. UTC
Adding return uprobe test for shadow stack and making sure it's
working properly. Borrowed some of the code from bpf selftests.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 .../testing/selftests/x86/test_shadow_stack.c | 142 ++++++++++++++++++
 1 file changed, 142 insertions(+)

Comments

Masami Hiramatsu (Google) May 13, 2024, 9:45 a.m. UTC | #1
On Tue,  7 May 2024 12:53:20 +0200
Jiri Olsa <jolsa@kernel.org> wrote:

> Adding return uprobe test for shadow stack and making sure it's
> working properly. Borrowed some of the code from bpf selftests.

Hi Jiri,

I can not find "SKIP" result in this change. If CONFIG_UPROBES=n,
this should skip uprobe test.

Thank you,

> 
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  .../testing/selftests/x86/test_shadow_stack.c | 142 ++++++++++++++++++
>  1 file changed, 142 insertions(+)
> 
> diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c
> index 757e6527f67e..1b919baa999b 100644
> --- a/tools/testing/selftests/x86/test_shadow_stack.c
> +++ b/tools/testing/selftests/x86/test_shadow_stack.c
> @@ -34,6 +34,7 @@
>  #include <sys/ptrace.h>
>  #include <sys/signal.h>
>  #include <linux/elf.h>
> +#include <linux/perf_event.h>
>  
>  /*
>   * Define the ABI defines if needed, so people can run the tests
> @@ -681,6 +682,141 @@ int test_32bit(void)
>  	return !segv_triggered;
>  }
>  
> +static int parse_uint_from_file(const char *file, const char *fmt)
> +{
> +	int err, ret;
> +	FILE *f;
> +
> +	f = fopen(file, "re");
> +	if (!f) {
> +		err = -errno;
> +		printf("failed to open '%s': %d\n", file, err);
> +		return err;
> +	}
> +	err = fscanf(f, fmt, &ret);
> +	if (err != 1) {
> +		err = err == EOF ? -EIO : -errno;
> +		printf("failed to parse '%s': %d\n", file, err);
> +		fclose(f);
> +		return err;
> +	}
> +	fclose(f);
> +	return ret;
> +}
> +
> +static int determine_uprobe_perf_type(void)
> +{
> +	const char *file = "/sys/bus/event_source/devices/uprobe/type";
> +
> +	return parse_uint_from_file(file, "%d\n");
> +}
> +
> +static int determine_uprobe_retprobe_bit(void)
> +{
> +	const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe";
> +
> +	return parse_uint_from_file(file, "config:%d\n");
> +}
> +
> +static ssize_t get_uprobe_offset(const void *addr)
> +{
> +	size_t start, end, base;
> +	char buf[256];
> +	bool found = false;
> +	FILE *f;
> +
> +	f = fopen("/proc/self/maps", "r");
> +	if (!f)
> +		return -errno;
> +
> +	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
> +		if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
> +			found = true;
> +			break;
> +		}
> +	}
> +
> +	fclose(f);
> +
> +	if (!found)
> +		return -ESRCH;
> +
> +	return (uintptr_t)addr - start + base;
> +}
> +
> +static __attribute__((noinline)) void uretprobe_trigger(void)
> +{
> +	asm volatile ("");
> +}
> +
> +/*
> + * This test setups return uprobe, which is sensitive to shadow stack
> + * (crashes without extra fix). After executing the uretprobe we fail
> + * the test if we receive SIGSEGV, no crash means we're good.
> + *
> + * Helper functions above borrowed from bpf selftests.
> + */
> +static int test_uretprobe(void)
> +{
> +	const size_t attr_sz = sizeof(struct perf_event_attr);
> +	const char *file = "/proc/self/exe";
> +	int bit, fd = 0, type, err = 1;
> +	struct perf_event_attr attr;
> +	struct sigaction sa = {};
> +	ssize_t offset;
> +
> +	type = determine_uprobe_perf_type();
> +	if (type < 0)
> +		return 1;
> +
> +	offset = get_uprobe_offset(uretprobe_trigger);
> +	if (offset < 0)
> +		return 1;
> +
> +	bit = determine_uprobe_retprobe_bit();
> +	if (bit < 0)
> +		return 1;
> +
> +	sa.sa_sigaction = segv_gp_handler;
> +	sa.sa_flags = SA_SIGINFO;
> +	if (sigaction(SIGSEGV, &sa, NULL))
> +		return 1;
> +
> +	/* Setup return uprobe through perf event interface. */
> +	memset(&attr, 0, attr_sz);
> +	attr.size = attr_sz;
> +	attr.type = type;
> +	attr.config = 1 << bit;
> +	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;
> +
> +	ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK);
> +
> +	/*
> +	 * This either segfaults and goes through sigsetjmp above
> +	 * or succeeds and we're good.
> +	 */
> +	uretprobe_trigger();
> +
> +	printf("[OK]\tUretprobe test\n");
> +	err = 0;
> +
> +out:
> +	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
> +	signal(SIGSEGV, SIG_DFL);
> +	if (fd)
> +		close(fd);
> +	return err;
> +}
> +
>  void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)
>  {
>  	/* The SSP adjustment caused a segfault. */
> @@ -867,6 +1003,12 @@ int main(int argc, char *argv[])
>  		goto out;
>  	}
>  
> +	if (test_uretprobe()) {
> +		ret = 1;
> +		printf("[FAIL]\turetprobe test\n");
> +		goto out;
> +	}
> +
>  	return ret;
>  
>  out:
> -- 
> 2.44.0
>
Jiri Olsa May 13, 2024, 9:28 p.m. UTC | #2
On Mon, May 13, 2024 at 06:45:07PM +0900, Masami Hiramatsu wrote:
> On Tue,  7 May 2024 12:53:20 +0200
> Jiri Olsa <jolsa@kernel.org> wrote:
> 
> > Adding return uprobe test for shadow stack and making sure it's
> > working properly. Borrowed some of the code from bpf selftests.
> 
> Hi Jiri,
> 
> I can not find "SKIP" result in this change. If CONFIG_UPROBES=n,
> this should skip uprobe test.

ah it should be detected by parse_uint_from_file returning ENOENT
or something like that.. will add that

thanks,
jirka

> 
> Thank you,
> 
> > 
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > ---
> >  .../testing/selftests/x86/test_shadow_stack.c | 142 ++++++++++++++++++
> >  1 file changed, 142 insertions(+)
> > 
> > diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c
> > index 757e6527f67e..1b919baa999b 100644
> > --- a/tools/testing/selftests/x86/test_shadow_stack.c
> > +++ b/tools/testing/selftests/x86/test_shadow_stack.c
> > @@ -34,6 +34,7 @@
> >  #include <sys/ptrace.h>
> >  #include <sys/signal.h>
> >  #include <linux/elf.h>
> > +#include <linux/perf_event.h>
> >  
> >  /*
> >   * Define the ABI defines if needed, so people can run the tests
> > @@ -681,6 +682,141 @@ int test_32bit(void)
> >  	return !segv_triggered;
> >  }
> >  
> > +static int parse_uint_from_file(const char *file, const char *fmt)
> > +{
> > +	int err, ret;
> > +	FILE *f;
> > +
> > +	f = fopen(file, "re");
> > +	if (!f) {
> > +		err = -errno;
> > +		printf("failed to open '%s': %d\n", file, err);
> > +		return err;
> > +	}
> > +	err = fscanf(f, fmt, &ret);
> > +	if (err != 1) {
> > +		err = err == EOF ? -EIO : -errno;
> > +		printf("failed to parse '%s': %d\n", file, err);
> > +		fclose(f);
> > +		return err;
> > +	}
> > +	fclose(f);
> > +	return ret;
> > +}
> > +
> > +static int determine_uprobe_perf_type(void)
> > +{
> > +	const char *file = "/sys/bus/event_source/devices/uprobe/type";
> > +
> > +	return parse_uint_from_file(file, "%d\n");
> > +}
> > +
> > +static int determine_uprobe_retprobe_bit(void)
> > +{
> > +	const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe";
> > +
> > +	return parse_uint_from_file(file, "config:%d\n");
> > +}
> > +
> > +static ssize_t get_uprobe_offset(const void *addr)
> > +{
> > +	size_t start, end, base;
> > +	char buf[256];
> > +	bool found = false;
> > +	FILE *f;
> > +
> > +	f = fopen("/proc/self/maps", "r");
> > +	if (!f)
> > +		return -errno;
> > +
> > +	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
> > +		if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
> > +			found = true;
> > +			break;
> > +		}
> > +	}
> > +
> > +	fclose(f);
> > +
> > +	if (!found)
> > +		return -ESRCH;
> > +
> > +	return (uintptr_t)addr - start + base;
> > +}
> > +
> > +static __attribute__((noinline)) void uretprobe_trigger(void)
> > +{
> > +	asm volatile ("");
> > +}
> > +
> > +/*
> > + * This test setups return uprobe, which is sensitive to shadow stack
> > + * (crashes without extra fix). After executing the uretprobe we fail
> > + * the test if we receive SIGSEGV, no crash means we're good.
> > + *
> > + * Helper functions above borrowed from bpf selftests.
> > + */
> > +static int test_uretprobe(void)
> > +{
> > +	const size_t attr_sz = sizeof(struct perf_event_attr);
> > +	const char *file = "/proc/self/exe";
> > +	int bit, fd = 0, type, err = 1;
> > +	struct perf_event_attr attr;
> > +	struct sigaction sa = {};
> > +	ssize_t offset;
> > +
> > +	type = determine_uprobe_perf_type();
> > +	if (type < 0)
> > +		return 1;
> > +
> > +	offset = get_uprobe_offset(uretprobe_trigger);
> > +	if (offset < 0)
> > +		return 1;
> > +
> > +	bit = determine_uprobe_retprobe_bit();
> > +	if (bit < 0)
> > +		return 1;
> > +
> > +	sa.sa_sigaction = segv_gp_handler;
> > +	sa.sa_flags = SA_SIGINFO;
> > +	if (sigaction(SIGSEGV, &sa, NULL))
> > +		return 1;
> > +
> > +	/* Setup return uprobe through perf event interface. */
> > +	memset(&attr, 0, attr_sz);
> > +	attr.size = attr_sz;
> > +	attr.type = type;
> > +	attr.config = 1 << bit;
> > +	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;
> > +
> > +	ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK);
> > +
> > +	/*
> > +	 * This either segfaults and goes through sigsetjmp above
> > +	 * or succeeds and we're good.
> > +	 */
> > +	uretprobe_trigger();
> > +
> > +	printf("[OK]\tUretprobe test\n");
> > +	err = 0;
> > +
> > +out:
> > +	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
> > +	signal(SIGSEGV, SIG_DFL);
> > +	if (fd)
> > +		close(fd);
> > +	return err;
> > +}
> > +
> >  void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)
> >  {
> >  	/* The SSP adjustment caused a segfault. */
> > @@ -867,6 +1003,12 @@ int main(int argc, char *argv[])
> >  		goto out;
> >  	}
> >  
> > +	if (test_uretprobe()) {
> > +		ret = 1;
> > +		printf("[FAIL]\turetprobe test\n");
> > +		goto out;
> > +	}
> > +
> >  	return ret;
> >  
> >  out:
> > -- 
> > 2.44.0
> > 
> 
> 
> -- 
> Masami Hiramatsu (Google) <mhiramat@kernel.org>
diff mbox series

Patch

diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c
index 757e6527f67e..1b919baa999b 100644
--- a/tools/testing/selftests/x86/test_shadow_stack.c
+++ b/tools/testing/selftests/x86/test_shadow_stack.c
@@ -34,6 +34,7 @@ 
 #include <sys/ptrace.h>
 #include <sys/signal.h>
 #include <linux/elf.h>
+#include <linux/perf_event.h>
 
 /*
  * Define the ABI defines if needed, so people can run the tests
@@ -681,6 +682,141 @@  int test_32bit(void)
 	return !segv_triggered;
 }
 
+static int parse_uint_from_file(const char *file, const char *fmt)
+{
+	int err, ret;
+	FILE *f;
+
+	f = fopen(file, "re");
+	if (!f) {
+		err = -errno;
+		printf("failed to open '%s': %d\n", file, err);
+		return err;
+	}
+	err = fscanf(f, fmt, &ret);
+	if (err != 1) {
+		err = err == EOF ? -EIO : -errno;
+		printf("failed to parse '%s': %d\n", file, err);
+		fclose(f);
+		return err;
+	}
+	fclose(f);
+	return ret;
+}
+
+static int determine_uprobe_perf_type(void)
+{
+	const char *file = "/sys/bus/event_source/devices/uprobe/type";
+
+	return parse_uint_from_file(file, "%d\n");
+}
+
+static int determine_uprobe_retprobe_bit(void)
+{
+	const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe";
+
+	return parse_uint_from_file(file, "config:%d\n");
+}
+
+static ssize_t get_uprobe_offset(const void *addr)
+{
+	size_t start, end, base;
+	char buf[256];
+	bool found = false;
+	FILE *f;
+
+	f = fopen("/proc/self/maps", "r");
+	if (!f)
+		return -errno;
+
+	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
+		if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
+			found = true;
+			break;
+		}
+	}
+
+	fclose(f);
+
+	if (!found)
+		return -ESRCH;
+
+	return (uintptr_t)addr - start + base;
+}
+
+static __attribute__((noinline)) void uretprobe_trigger(void)
+{
+	asm volatile ("");
+}
+
+/*
+ * This test setups return uprobe, which is sensitive to shadow stack
+ * (crashes without extra fix). After executing the uretprobe we fail
+ * the test if we receive SIGSEGV, no crash means we're good.
+ *
+ * Helper functions above borrowed from bpf selftests.
+ */
+static int test_uretprobe(void)
+{
+	const size_t attr_sz = sizeof(struct perf_event_attr);
+	const char *file = "/proc/self/exe";
+	int bit, fd = 0, type, err = 1;
+	struct perf_event_attr attr;
+	struct sigaction sa = {};
+	ssize_t offset;
+
+	type = determine_uprobe_perf_type();
+	if (type < 0)
+		return 1;
+
+	offset = get_uprobe_offset(uretprobe_trigger);
+	if (offset < 0)
+		return 1;
+
+	bit = determine_uprobe_retprobe_bit();
+	if (bit < 0)
+		return 1;
+
+	sa.sa_sigaction = segv_gp_handler;
+	sa.sa_flags = SA_SIGINFO;
+	if (sigaction(SIGSEGV, &sa, NULL))
+		return 1;
+
+	/* Setup return uprobe through perf event interface. */
+	memset(&attr, 0, attr_sz);
+	attr.size = attr_sz;
+	attr.type = type;
+	attr.config = 1 << bit;
+	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;
+
+	ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK);
+
+	/*
+	 * This either segfaults and goes through sigsetjmp above
+	 * or succeeds and we're good.
+	 */
+	uretprobe_trigger();
+
+	printf("[OK]\tUretprobe test\n");
+	err = 0;
+
+out:
+	ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);
+	signal(SIGSEGV, SIG_DFL);
+	if (fd)
+		close(fd);
+	return err;
+}
+
 void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)
 {
 	/* The SSP adjustment caused a segfault. */
@@ -867,6 +1003,12 @@  int main(int argc, char *argv[])
 		goto out;
 	}
 
+	if (test_uretprobe()) {
+		ret = 1;
+		printf("[FAIL]\turetprobe test\n");
+		goto out;
+	}
+
 	return ret;
 
 out: