Commit 29edd8b0 authored by Jiri Olsa's avatar Jiri Olsa Committed by Masami Hiramatsu (Google)

selftests/x86: Add return uprobe shadow stack test

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

Link: https://lore.kernel.org/all/20240611112158.40795-5-jolsa@kernel.org/Acked-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
parent ff474a78
......@@ -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
......@@ -734,6 +735,144 @@ 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) {
if (type == -ENOENT)
printf("[SKIP]\tUretprobe test, uprobes are not available\n");
return 0;
}
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. */
......@@ -926,6 +1065,12 @@ int main(int argc, char *argv[])
goto out;
}
if (test_uretprobe()) {
ret = 1;
printf("[FAIL]\turetprobe test\n");
goto out;
}
return ret;
out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment