Detecting seccomp features at runtime

Features

The possible features in a given kernel for seccomp are: 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.

No seccomp

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");

Seccomp filtering

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;
}

End notes

Thanks for reading! --Kees Cook, Dec 2013.
For reference, this is all under a BSD license.