The possible features in a given kernel for seccomp are:
- No seccomp of any kind
- Only original ("mode 1") seccomp
- Seccomp ("bpf") filtering
Each of these modes can be detected at runtime, and there is not need to
write fragile kernel version/config checking code. For more details,
check the
manpage for prctl
where
PR_GET_SECCOMP
and
PR_SET_SECCOMP
are described.
If there is no seccomp at all, it can be seen as an
ENOSYS
(before 2.6.23) or
EINVAL
(not compiled in) failure from
prctl(PR_GET_SECCOMP, ...)
:
int ret;
ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
if (ret < 0) {
switch (errno) {
case ENOSYS:
printf("seccomp not available: pre-2.6.23\n");
return 0;
case EINVAL:
printf("seccomp not available: not built in\n");
return 0;
default:
fprintf(stderr, "unknown PR_GET_SECCOMP error: %s\n",
strerror(errno));
return 1;
}
}
printf("seccomp available\n");
Having seccomp with only mode 1 is possible on 2.6.23 through 3.4, on on
architectures that haven't implemented filtering yet. Filtering
can be detected by attempting to set a
SECCOMP_MODE_FILTER
from
unallocated memory (
NULL
).
EINVAL
means only mode 1,
EFAULT
means filtering is available
(and you haven't entered seccomp, so this can be done by your main thread):
int ret;
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
if (ret < 0) {
switch (errno) {
case EINVAL:
printf("seccomp filter not available\n");
return 0;
case EFAULT:
printf("seccomp filter available\n");
return 0;
default:
fprintf(stderr, "unknown PR_SET_SECCOMP error: %s\n",
strerror(errno));
return 1;
}
}
printf("PR_SET_SECCOMP unexpectedly succeeded?!\n");
Full example
Here the entire thing as a single example:
/*
* seccomp runtime detection
*
* Copyright (c) 2013 The Chromium OS Authors <chromium-os-dev@chromium.org>
* Authors:
* Kees Cook <keescook@chromium.org>
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
int main(void)
{
int ret;
ret = prctl(PR_GET_SECCOMP, 0, 0, 0, 0);
if (ret < 0) {
switch (errno) {
case ENOSYS:
printf("seccomp not available: pre-2.6.23\n");
return 0;
case EINVAL:
printf("seccomp not available: not built in\n");
return 0;
default:
fprintf(stderr, "unknown PR_GET_SECCOMP error: %s\n",
strerror(errno));
return 1;
}
}
printf("seccomp available\n");
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL, 0, 0);
if (ret < 0) {
switch (errno) {
case EINVAL:
printf("seccomp filter not available\n");
return 0;
case EFAULT:
printf("seccomp filter available\n");
return 0;
default:
fprintf(stderr, "unknown PR_SET_SECCOMP error: %s\n",
strerror(errno));
return 1;
}
}
printf("PR_SET_SECCOMP unexpectedly succeeded?!\n");
return 1;
}