Ubuntu 22.04.4 LTS, 5.15.0-105-generic.
I’m trying to prevent a process from making execve/execveat syscalls using seccomp-bpf. I would, however, also like to log the attempt from within the application.
Here’s a little test app:
#include <errno.h>
#include <linux/audit.h>
#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
static void bad_syscall_handler(int sig, siginfo_t *info, void *ucontext)
{
printf( "attempted prohibited syscalln" );
}
static bool install_filter( void )
{
struct sock_filter filter[] =
{
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, arch))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, AUDIT_ARCH_X86_64, 0, 4),
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, (offsetof(struct seccomp_data, nr))),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_execve, 1, 0),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_execveat, 0, 1),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRAP ),
BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog =
{
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
{
perror("prctl(NO_NEW_PRIVS)");
return false;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog))
{
perror("prctl(PR_SET_SECCOMP)");
return false;
}
return true;
}
int main()
{
system( "echo hello world" );
install_filter();
int rc;
struct sigaction action;
memset( &action, 0, sizeof( action ) );
action.sa_sigaction = bad_syscall_handler;
action.sa_flags = SA_SIGINFO;
rc = sigaction( SIGSYS, &action, NULL );
if( rc )
{
printf( "sigaction returned %dn", rc );
exit( -1 );
}
system( "echo hello world again" );
return 0;
}
However, the output is:
hello world
Bad system call
… and the process terminates immediately. ie: It looks like the SIGSYS signal is not being caught by the handler.
Did something change between kernel versions? Am I doing something wrong? Any ideas much appreciated.
Interestingly, if I put a delay loop after installing the signal, and then manually send SIGSYS to the process, the handler is correctly invoked. So (I think) the signal is being hooked correctly.
Also interestingly, on a second machine running Ubuntu 18.04 (4.15.0-213-generic), things behave as expected.