Skip to content

Commit da2d0e6

Browse files
committed
selftests/seccomp: validate uprobe syscall passes through seccomp
Adding uprobe checks into the current uretprobe tests. All the related tests are now executed with attached uprobe or uretprobe or without any probe. Renaming the test fixture to uprobe, because it seems better. Cc: Kees Cook <[email protected]> Cc: Eyal Birger <[email protected]> Reviewed-by: Kees Cook <[email protected]> Signed-off-by: Jiri Olsa <[email protected]>
1 parent d2cc0c7 commit da2d0e6

File tree

1 file changed

+86
-21
lines changed

1 file changed

+86
-21
lines changed

tools/testing/selftests/seccomp/seccomp_bpf.c

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@
7373
#define noinline __attribute__((noinline))
7474
#endif
7575

76+
#ifndef __nocf_check
77+
#define __nocf_check __attribute__((nocf_check))
78+
#endif
79+
80+
#ifndef __naked
81+
#define __naked __attribute__((__naked__))
82+
#endif
83+
7684
#ifndef PR_SET_NO_NEW_PRIVS
7785
#define PR_SET_NO_NEW_PRIVS 38
7886
#define PR_GET_NO_NEW_PRIVS 39
@@ -4896,7 +4904,36 @@ TEST(tsync_vs_dead_thread_leader)
48964904
EXPECT_EQ(0, status);
48974905
}
48984906

4899-
noinline int probed(void)
4907+
#ifdef __x86_64__
4908+
4909+
/*
4910+
* We need naked probed_uprobe function. Using __nocf_check
4911+
* check to skip possible endbr64 instruction and ignoring
4912+
* -Wattributes, otherwise the compilation might fail.
4913+
*/
4914+
#pragma GCC diagnostic push
4915+
#pragma GCC diagnostic ignored "-Wattributes"
4916+
4917+
__naked __nocf_check noinline int probed_uprobe(void)
4918+
{
4919+
/*
4920+
* Optimized uprobe is possible only on top of nop5 instruction.
4921+
*/
4922+
asm volatile (" \n"
4923+
".byte 0x0f, 0x1f, 0x44, 0x00, 0x00 \n"
4924+
"ret \n"
4925+
);
4926+
}
4927+
#pragma GCC diagnostic pop
4928+
4929+
#else
4930+
noinline int probed_uprobe(void)
4931+
{
4932+
return 1;
4933+
}
4934+
#endif
4935+
4936+
noinline int probed_uretprobe(void)
49004937
{
49014938
return 1;
49024939
}
@@ -4949,35 +4986,46 @@ static ssize_t get_uprobe_offset(const void *addr)
49494986
return found ? (uintptr_t)addr - start + base : -1;
49504987
}
49514988

4952-
FIXTURE(URETPROBE) {
4989+
FIXTURE(UPROBE) {
49534990
int fd;
49544991
};
49554992

4956-
FIXTURE_VARIANT(URETPROBE) {
4993+
FIXTURE_VARIANT(UPROBE) {
49574994
/*
4958-
* All of the URETPROBE behaviors can be tested with either
4959-
* uretprobe attached or not
4995+
* All of the U(RET)PROBE behaviors can be tested with either
4996+
* u(ret)probe attached or not
49604997
*/
49614998
bool attach;
4999+
/*
5000+
* Test both uprobe and uretprobe.
5001+
*/
5002+
bool uretprobe;
49625003
};
49635004

4964-
FIXTURE_VARIANT_ADD(URETPROBE, attached) {
5005+
FIXTURE_VARIANT_ADD(UPROBE, not_attached) {
5006+
.attach = false,
5007+
.uretprobe = false,
5008+
};
5009+
5010+
FIXTURE_VARIANT_ADD(UPROBE, uprobe_attached) {
49655011
.attach = true,
5012+
.uretprobe = false,
49665013
};
49675014

4968-
FIXTURE_VARIANT_ADD(URETPROBE, not_attached) {
4969-
.attach = false,
5015+
FIXTURE_VARIANT_ADD(UPROBE, uretprobe_attached) {
5016+
.attach = true,
5017+
.uretprobe = true,
49705018
};
49715019

4972-
FIXTURE_SETUP(URETPROBE)
5020+
FIXTURE_SETUP(UPROBE)
49735021
{
49745022
const size_t attr_sz = sizeof(struct perf_event_attr);
49755023
struct perf_event_attr attr;
49765024
ssize_t offset;
49775025
int type, bit;
49785026

4979-
#ifndef __NR_uretprobe
4980-
SKIP(return, "__NR_uretprobe syscall not defined");
5027+
#if !defined(__NR_uprobe) || !defined(__NR_uretprobe)
5028+
SKIP(return, "__NR_uprobe ot __NR_uretprobe syscalls not defined");
49815029
#endif
49825030

49835031
if (!variant->attach)
@@ -4987,12 +5035,17 @@ FIXTURE_SETUP(URETPROBE)
49875035

49885036
type = determine_uprobe_perf_type();
49895037
ASSERT_GE(type, 0);
4990-
bit = determine_uprobe_retprobe_bit();
4991-
ASSERT_GE(bit, 0);
4992-
offset = get_uprobe_offset(probed);
5038+
5039+
if (variant->uretprobe) {
5040+
bit = determine_uprobe_retprobe_bit();
5041+
ASSERT_GE(bit, 0);
5042+
}
5043+
5044+
offset = get_uprobe_offset(variant->uretprobe ? probed_uretprobe : probed_uprobe);
49935045
ASSERT_GE(offset, 0);
49945046

4995-
attr.config |= 1 << bit;
5047+
if (variant->uretprobe)
5048+
attr.config |= 1 << bit;
49965049
attr.size = attr_sz;
49975050
attr.type = type;
49985051
attr.config1 = ptr_to_u64("/proc/self/exe");
@@ -5003,7 +5056,7 @@ FIXTURE_SETUP(URETPROBE)
50035056
PERF_FLAG_FD_CLOEXEC);
50045057
}
50055058

5006-
FIXTURE_TEARDOWN(URETPROBE)
5059+
FIXTURE_TEARDOWN(UPROBE)
50075060
{
50085061
/* we could call close(self->fd), but we'd need extra filter for
50095062
* that and since we are calling _exit right away..
@@ -5017,11 +5070,17 @@ static int run_probed_with_filter(struct sock_fprog *prog)
50175070
return -1;
50185071
}
50195072

5020-
probed();
5073+
/*
5074+
* Uprobe is optimized after first hit, so let's hit twice.
5075+
*/
5076+
probed_uprobe();
5077+
probed_uprobe();
5078+
5079+
probed_uretprobe();
50215080
return 0;
50225081
}
50235082

5024-
TEST_F(URETPROBE, uretprobe_default_allow)
5083+
TEST_F(UPROBE, uprobe_default_allow)
50255084
{
50265085
struct sock_filter filter[] = {
50275086
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
@@ -5034,7 +5093,7 @@ TEST_F(URETPROBE, uretprobe_default_allow)
50345093
ASSERT_EQ(0, run_probed_with_filter(&prog));
50355094
}
50365095

5037-
TEST_F(URETPROBE, uretprobe_default_block)
5096+
TEST_F(UPROBE, uprobe_default_block)
50385097
{
50395098
struct sock_filter filter[] = {
50405099
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
@@ -5051,11 +5110,14 @@ TEST_F(URETPROBE, uretprobe_default_block)
50515110
ASSERT_EQ(0, run_probed_with_filter(&prog));
50525111
}
50535112

5054-
TEST_F(URETPROBE, uretprobe_block_uretprobe_syscall)
5113+
TEST_F(UPROBE, uprobe_block_syscall)
50555114
{
50565115
struct sock_filter filter[] = {
50575116
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
50585117
offsetof(struct seccomp_data, nr)),
5118+
#ifdef __NR_uprobe
5119+
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uprobe, 1, 2),
5120+
#endif
50595121
#ifdef __NR_uretprobe
50605122
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uretprobe, 0, 1),
50615123
#endif
@@ -5070,11 +5132,14 @@ TEST_F(URETPROBE, uretprobe_block_uretprobe_syscall)
50705132
ASSERT_EQ(0, run_probed_with_filter(&prog));
50715133
}
50725134

5073-
TEST_F(URETPROBE, uretprobe_default_block_with_uretprobe_syscall)
5135+
TEST_F(UPROBE, uprobe_default_block_with_syscall)
50745136
{
50755137
struct sock_filter filter[] = {
50765138
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
50775139
offsetof(struct seccomp_data, nr)),
5140+
#ifdef __NR_uprobe
5141+
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uprobe, 3, 0),
5142+
#endif
50785143
#ifdef __NR_uretprobe
50795144
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_uretprobe, 2, 0),
50805145
#endif

0 commit comments

Comments
 (0)