I have just started learning about seccomp filters and I am using libseccomp v2.4.4. I tried to write a basic whitelisting filter that will only allow writing to the file named file1
but I am getting a "Bad system call" message in STDOUT
. Here is my code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <seccomp.h>
#include <stdlib.h>
#include <errno.h>
int main(void)
{
FILE *fil = fopen("file1", "w");
scmp_filter_ctx filter = seccomp_init(SCMP_ACT_KILL);
if (filter==NULL || NULL==fil)
goto End1;
int chk1 = seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
SCMP_A0(SCMP_CMP_EQ, fileno(fil)));
int chk2 = seccomp_load(filter);
if (chk1<0 || chk2<0)
goto End;
fprintf(stdout,"Filter did not work correctly\n");
fprintf(fil,"Filter worked correctly\n");
End:
seccomp_release(filter); //releasing filter before closing file
fclose(fil);
End1:
return 0;
}
Additionally, I see no output in file1
. I am just a beginner and unsure about a lot of things here as I have written the code from my understanding, not from some reference. What seems to be the issue?
Edit: I removed the filter completely and simply executed
int main(void)
{
FILE *fil = fopen("file1", "w");
fprintf(stdout,"Filter did not work correctly\n");
fprintf(fil,"Filter worked correctly\n");
End:
fclose(fil);
End1:
return 0;
}
Stracing this I observed that syscalls fstat
,close
as mentioned in the answer below by @pchaigno and additionally mmap
,munmap
were being called. So I must allow these syscalls for the expected behaviour.
Stracing your application will reveal the issue:
$ strace ./test
[...]
seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=12, filter=0x55ace60a6600}) = 0
fstat(1, <unfinished ...>) = ?
+++ killed by SIGSYS (core dumped) +++
Bad system call (core dumped)
You need to allow a lot more syscalls than just write(2)
for the end of your program to proceed without errors.
You'll need fstat(2)
for fprintf()
, close(2)
for fclose()
, and exit_group(2)
to end the process.
In addition, if you want your program to continue running after an unauthorized syscall, you shouldn't kill it with SCMP_ACT_KILL
. SCMP_ACT_ERRNO(EPERM)
is probably more appropriate in this context.
int main(void) {
FILE *fil = fopen("file1", "w");
scmp_filter_ctx filter = seccomp_init(SCMP_ACT_ERRNO(EPERM));
if (filter == NULL || NULL == fil)
return 1;
if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ,fileno(fil))) < 0)
goto err;
if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0) < 0)
goto err;
if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(close), 0) < 0)
goto err;
if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0) < 0)
goto err;
if (seccomp_load(filter) < 0)
goto err;
fprintf(stdout, "Filter did not work correctly\n");
fprintf(fil, "Filter worked correctly\n");
err:
seccomp_release(filter); //releasing filter before closing file
fclose(fil);
return 0;
}
gives us:
$ ./test; echo file1
Filter worked correctly