Skip to content

Commit

Permalink
basic seccmp filter
Browse files Browse the repository at this point in the history
  • Loading branch information
leifj committed Sep 4, 2012
1 parent 7050b8f commit 3312d89
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 1 deletion.
7 changes: 6 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ endif(COMMAND cmake_policy)
project (pkcs11 C)

set(PKCS11_PROXY_SRCS gck-rpc-module.c gck-rpc-message.c gck-rpc-util.c egg-buffer.c)
set(PKCS11_DAEMON_SRCS egg-buffer.c gck-rpc-daemon-standalone.c gck-rpc-dispatch.c gck-rpc-message.c gck-rpc-util.c)
set(PKCS11_DAEMON_SRCS egg-buffer.c gck-rpc-daemon-standalone.c gck-rpc-dispatch.c gck-rpc-message.c gck-rpc-util.c syscall-reporter.c syscall-names.h)

add_definitions(-Wall)
add_library(pkcs11-proxy SHARED ${PKCS11_PROXY_SRCS})
Expand Down Expand Up @@ -38,3 +38,8 @@ target_link_libraries (pkcs11-daemon dl pthread)

install_targets (/lib pkcs11-proxy)
install_targets (/bin pkcs11-daemon)

add_custom_command(
OUTPUT syscall-names.h
COMMAND ${CMAKE_SOURCE_DIR}/mksyscalls.sh
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
63 changes: 63 additions & 0 deletions gck-rpc-daemon-standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,63 @@

#define SOCKET_PATH "tcp://127.0.0.1"

#include "seccomp-bpf.h"
#include "syscall-reporter.h"

static int install_syscall_filter(void)
{
struct sock_filter filter[] = {
/* Validate architecture. */
VALIDATE_ARCHITECTURE,
/* Grab the system call number. */
EXAMINE_SYSCALL,
/* List allowed syscalls. */
ALLOW_SYSCALL(rt_sigreturn),
#ifdef __NR_sigreturn
ALLOW_SYSCALL(sigreturn),
#endif
ALLOW_SYSCALL(exit_group),
ALLOW_SYSCALL(exit),
ALLOW_SYSCALL(read),
ALLOW_SYSCALL(write),
ALLOW_SYSCALL(futex),
ALLOW_SYSCALL(brk),
ALLOW_SYSCALL(open),
ALLOW_SYSCALL(fstat64),
ALLOW_SYSCALL(mmap2),
ALLOW_SYSCALL(mprotect),
ALLOW_SYSCALL(close),
ALLOW_SYSCALL(access),
ALLOW_SYSCALL(munmap),
ALLOW_SYSCALL(time),
ALLOW_SYSCALL(_llseek),
ALLOW_SYSCALL(stat64),
ALLOW_SYSCALL(fcntl64),
ALLOW_SYSCALL(mlock),
ALLOW_SYSCALL(munlock),
KILL_PROCESS,
};
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)");
goto failed;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
perror("prctl(SECCOMP)");
goto failed;
}
return 0;

failed:
if (errno == EINVAL)
fprintf(stderr, "SECCOMP_FILTER is not available. :(\n");
return 1;
}

#if 0
/* Sample configuration for loading NSS remotely */
static CK_C_INITIALIZE_ARGS p11_init_args = {
Expand Down Expand Up @@ -72,6 +129,12 @@ int main(int argc, char *argv[])
int sock, ret;
CK_RV rv;


if (install_syscall_reporter())
return 1;
if (install_syscall_filter())
return 1;

/* The module to load is the argument */
if (argc != 2 && argc != 3)
usage();
Expand Down
4 changes: 4 additions & 0 deletions mksyscalls.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash
(echo "static const char *syscall_names[] = {"
echo "#include <sys/syscall.h>" | cpp -dM | grep '^#define __NR_' | LC_ALL=C sed -r -n -e 's/^\#define[ \t]+__NR_([a-z0-9_]+)[ \t]+([0-9]+)(.*)/ [\2] = "\1",/p'
echo "};")> syscall-names.h
81 changes: 81 additions & 0 deletions seccomp-bpf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* seccomp example for x86 (32-bit and 64-bit) with BPF macros
*
* Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
* Authors:
* Will Drewry <wad@chromium.org>
* Kees Cook <keescook@chromium.org>
*
* The code may be used by anyone for any purpose, and can serve as a
* starting point for developing applications using mode 2 seccomp.
*/
#ifndef _SECCOMP_BPF_H_
#define _SECCOMP_BPF_H_

#define _GNU_SOURCE 1
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

#include <sys/prctl.h>
#ifndef PR_SET_NO_NEW_PRIVS
# define PR_SET_NO_NEW_PRIVS 38
#endif

#include <linux/unistd.h>
#include <linux/audit.h>
#include <linux/filter.h>
#ifdef HAVE_LINUX_SECCOMP_H
# include <linux/seccomp.h>
#endif
#ifndef SECCOMP_MODE_FILTER
# define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
# define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */
# define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */
# define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
struct seccomp_data {
int nr;
__u32 arch;
__u64 instruction_pointer;
__u64 args[6];
};
#endif
#ifndef SYS_SECCOMP
# define SYS_SECCOMP 1
#endif

#define syscall_nr (offsetof(struct seccomp_data, nr))
#define arch_nr (offsetof(struct seccomp_data, arch))

#if defined(__i386__)
# define REG_SYSCALL REG_EAX
# define ARCH_NR AUDIT_ARCH_I386
#elif defined(__x86_64__)
# define REG_SYSCALL REG_RAX
# define ARCH_NR AUDIT_ARCH_X86_64
#else
# warning "Platform does not support seccomp filter yet"
# define REG_SYSCALL 0
# define ARCH_NR 0
#endif

#define VALIDATE_ARCHITECTURE \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)

#define EXAMINE_SYSCALL \
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr)

#define ALLOW_SYSCALL(name) \
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)

#define KILL_PROCESS \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL)

#endif /* _SECCOMP_BPF_H_ */
76 changes: 76 additions & 0 deletions syscall-reporter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* syscall reporting example for seccomp
*
* Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
* Authors:
* Will Drewry <wad@chromium.org>
* Kees Cook <keescook@chromium.org>
*
* The code may be used by anyone for any purpose, and can serve as a
* starting point for developing applications using mode 2 seccomp.
*/
#include "syscall-reporter.h"
#include "syscall-names.h"

const char * const msg_needed = "Looks like you also need syscall: ";

/* Since "sprintf" is technically not signal-safe, reimplement %d here. */
static void write_uint(char *buf, unsigned int val)
{
int width = 0;
unsigned int tens;

if (val == 0) {
strcpy(buf, "0");
return;
}
for (tens = val; tens; tens /= 10)
++ width;
buf[width] = '\0';
for (tens = val; tens; tens /= 10)
buf[--width] = '0' + (tens % 10);
}

static void reporter(int nr, siginfo_t *info, void *void_context)
{
char buf[128];
ucontext_t *ctx = (ucontext_t *)(void_context);
unsigned int syscall;
if (info->si_code != SYS_SECCOMP)
return;
if (!ctx)
return;
syscall = ctx->uc_mcontext.gregs[REG_SYSCALL];
strcpy(buf, msg_needed);
if (syscall < sizeof(syscall_names)) {
strcat(buf, syscall_names[syscall]);
strcat(buf, "(");
}
write_uint(buf + strlen(buf), syscall);
if (syscall < sizeof(syscall_names))
strcat(buf, ")");
strcat(buf, "\n");
write(STDERR_FILENO, buf, strlen(buf));
_exit(1);
}

int install_syscall_reporter(void)
{
struct sigaction act;
sigset_t mask;
memset(&act, 0, sizeof(act));
sigemptyset(&mask);
sigaddset(&mask, SIGSYS);

act.sa_sigaction = &reporter;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGSYS, &act, NULL) < 0) {
perror("sigaction");
return -1;
}
if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
perror("sigprocmask");
return -1;
}
return 0;
}
28 changes: 28 additions & 0 deletions syscall-reporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* syscall reporting example for seccomp
*
* Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
* Authors:
* Kees Cook <keescook@chromium.org>
* Will Drewry <wad@chromium.org>
*
* The code may be used by anyone for any purpose, and can serve as a
* starting point for developing applications using mode 2 seccomp.
*/
#ifndef _BPF_REPORTER_H_
#define _BPF_REPORTER_H_

#include "seccomp-bpf.h"

/* Since this redfines "KILL_PROCESS" into a TRAP for the reporter hook,
* we want to make sure it stands out in the build as it should not be
* used in the final program.
*/
#warning "You've included the syscall reporter. Do not use in production!"
#undef KILL_PROCESS
#define KILL_PROCESS \
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRAP)

extern int install_syscall_reporter(void);

#endif

0 comments on commit 3312d89

Please sign in to comment.