Skip to content

Commit ad56821

Browse files
Christian Braunerkees
authored andcommitted
selftests/seccomp: Check for EPOLLHUP for user_notif
This verifies we're correctly notified when a seccomp filter becomes unused when a notifier is in use. Signed-off-by: Christian Brauner <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent 99cdb8b commit ad56821

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed

tools/testing/selftests/seccomp/seccomp_bpf.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <poll.h>
5252

5353
#include "../kselftest_harness.h"
54+
#include "../clone3/clone3_selftests.h"
5455

5556
/* Attempt to de-conflict with the selftests tree. */
5657
#ifndef SKIP
@@ -3702,6 +3703,141 @@ TEST(user_notification_continue)
37023703
}
37033704
}
37043705

3706+
TEST(user_notification_filter_empty)
3707+
{
3708+
pid_t pid;
3709+
long ret;
3710+
int status;
3711+
struct pollfd pollfd;
3712+
struct clone_args args = {
3713+
.flags = CLONE_FILES,
3714+
.exit_signal = SIGCHLD,
3715+
};
3716+
3717+
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3718+
ASSERT_EQ(0, ret) {
3719+
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3720+
}
3721+
3722+
pid = sys_clone3(&args, sizeof(args));
3723+
ASSERT_GE(pid, 0);
3724+
3725+
if (pid == 0) {
3726+
int listener;
3727+
3728+
listener = user_trap_syscall(__NR_mknod, SECCOMP_FILTER_FLAG_NEW_LISTENER);
3729+
if (listener < 0)
3730+
_exit(EXIT_FAILURE);
3731+
3732+
if (dup2(listener, 200) != 200)
3733+
_exit(EXIT_FAILURE);
3734+
3735+
close(listener);
3736+
3737+
_exit(EXIT_SUCCESS);
3738+
}
3739+
3740+
EXPECT_EQ(waitpid(pid, &status, 0), pid);
3741+
EXPECT_EQ(true, WIFEXITED(status));
3742+
EXPECT_EQ(0, WEXITSTATUS(status));
3743+
3744+
/*
3745+
* The seccomp filter has become unused so we should be notified once
3746+
* the kernel gets around to cleaning up task struct.
3747+
*/
3748+
pollfd.fd = 200;
3749+
pollfd.events = POLLHUP;
3750+
3751+
EXPECT_GT(poll(&pollfd, 1, 2000), 0);
3752+
EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
3753+
}
3754+
3755+
static void *do_thread(void *data)
3756+
{
3757+
return NULL;
3758+
}
3759+
3760+
TEST(user_notification_filter_empty_threaded)
3761+
{
3762+
pid_t pid;
3763+
long ret;
3764+
int status;
3765+
struct pollfd pollfd;
3766+
struct clone_args args = {
3767+
.flags = CLONE_FILES,
3768+
.exit_signal = SIGCHLD,
3769+
};
3770+
3771+
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
3772+
ASSERT_EQ(0, ret) {
3773+
TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
3774+
}
3775+
3776+
pid = sys_clone3(&args, sizeof(args));
3777+
ASSERT_GE(pid, 0);
3778+
3779+
if (pid == 0) {
3780+
pid_t pid1, pid2;
3781+
int listener, status;
3782+
pthread_t thread;
3783+
3784+
listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
3785+
if (listener < 0)
3786+
_exit(EXIT_FAILURE);
3787+
3788+
if (dup2(listener, 200) != 200)
3789+
_exit(EXIT_FAILURE);
3790+
3791+
close(listener);
3792+
3793+
pid1 = fork();
3794+
if (pid1 < 0)
3795+
_exit(EXIT_FAILURE);
3796+
3797+
if (pid1 == 0)
3798+
_exit(EXIT_SUCCESS);
3799+
3800+
pid2 = fork();
3801+
if (pid2 < 0)
3802+
_exit(EXIT_FAILURE);
3803+
3804+
if (pid2 == 0)
3805+
_exit(EXIT_SUCCESS);
3806+
3807+
if (pthread_create(&thread, NULL, do_thread, NULL) ||
3808+
pthread_join(thread, NULL))
3809+
_exit(EXIT_FAILURE);
3810+
3811+
if (pthread_create(&thread, NULL, do_thread, NULL) ||
3812+
pthread_join(thread, NULL))
3813+
_exit(EXIT_FAILURE);
3814+
3815+
if (waitpid(pid1, &status, 0) != pid1 || !WIFEXITED(status) ||
3816+
WEXITSTATUS(status))
3817+
_exit(EXIT_FAILURE);
3818+
3819+
if (waitpid(pid2, &status, 0) != pid2 || !WIFEXITED(status) ||
3820+
WEXITSTATUS(status))
3821+
_exit(EXIT_FAILURE);
3822+
3823+
exit(EXIT_SUCCESS);
3824+
}
3825+
3826+
EXPECT_EQ(waitpid(pid, &status, 0), pid);
3827+
EXPECT_EQ(true, WIFEXITED(status));
3828+
EXPECT_EQ(0, WEXITSTATUS(status));
3829+
3830+
/*
3831+
* The seccomp filter has become unused so we should be notified once
3832+
* the kernel gets around to cleaning up task struct.
3833+
*/
3834+
pollfd.fd = 200;
3835+
pollfd.events = POLLHUP;
3836+
3837+
EXPECT_GT(poll(&pollfd, 1, 2000), 0);
3838+
EXPECT_GT((pollfd.revents & POLLHUP) ?: 0, 0);
3839+
}
3840+
37053841
/*
37063842
* TODO:
37073843
* - add microbenchmarks

0 commit comments

Comments
 (0)