Skip to content

Instantly share code, notes, and snippets.

@alexlarsson
Last active May 30, 2017 14:02
Show Gist options
  • Save alexlarsson/021c4134954ad58dd6ff3a1a0f7bfc3c to your computer and use it in GitHub Desktop.
Save alexlarsson/021c4134954ad58dd6ff3a1a0f7bfc3c to your computer and use it in GitHub Desktop.
seccomp test
/* Build with:
gcc -o test_seccomp `pkg-config --cflags --libs glib-2.0 libseccomp` test_seccomp.c
*/
#define _GNU_SOURCE
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/personality.h>
#include <grp.h>
#include <unistd.h>
#include <glib.h>
#include <errno.h>
#include <seccomp.h>
static const uint32_t seccomp_x86_64_extra_arches[] = { SCMP_ARCH_X86, 0, };
static inline void
cleanup_seccomp (void *p)
{
scmp_filter_ctx *pp = (scmp_filter_ctx *) p;
if (*pp)
seccomp_release (*pp);
}
int
main(int argc,
char *argv[])
{
__attribute__((cleanup (cleanup_seccomp))) scmp_filter_ctx seccomp = NULL;
/**** BEGIN NOTE ON CODE SHARING
*
* There are today a number of different Linux container
* implementations. That will likely continue for long into the
* future. But we can still try to share code, and it's important
* to do so because it affects what library and application writers
* can do, and we should support code portability between different
* container tools.
*
* This syscall blacklist is copied from linux-user-chroot, which was in turn
* clearly influenced by the Sandstorm.io blacklist.
*
* If you make any changes here, I suggest sending the changes along
* to other sandbox maintainers. Using the libseccomp list is also
* an appropriate venue:
* https://groups.google.com/forum/#!topic/libseccomp
*
* A non-exhaustive list of links to container tooling that might
* want to share this blacklist:
*
* https://github.com/sandstorm-io/sandstorm
* in src/sandstorm/supervisor.c++
* http://cgit.freedesktop.org/xdg-app/xdg-app/
* in common/flatpak-run.c
* https://git.gnome.org/browse/linux-user-chroot
* in src/setup-seccomp.c
*
**** END NOTE ON CODE SHARING
*/
struct
{
int scall;
struct scmp_arg_cmp *arg;
} syscall_blacklist[] = {
/* Block dmesg */
{SCMP_SYS (syslog)},
/* Useless old syscall */
{SCMP_SYS (uselib)},
/* Don't allow you to switch to bsd emulation or whatnot */
{SCMP_SYS (personality)},
/* Don't allow disabling accounting */
{SCMP_SYS (acct)},
/* 16-bit code is unnecessary in the sandbox, and modify_ldt is a
historic source of interesting information leaks. */
{SCMP_SYS (modify_ldt)},
/* Don't allow reading current quota use */
{SCMP_SYS (quotactl)},
/* Don't allow access to the kernel keyring */
{SCMP_SYS (add_key)},
{SCMP_SYS (keyctl)},
{SCMP_SYS (request_key)},
/* Scary VM/NUMA ops */
{SCMP_SYS (move_pages)},
{SCMP_SYS (mbind)},
{SCMP_SYS (get_mempolicy)},
{SCMP_SYS (set_mempolicy)},
{SCMP_SYS (migrate_pages)},
/* Don't allow subnamespace setups: */
{SCMP_SYS (unshare)},
{SCMP_SYS (mount)},
{SCMP_SYS (pivot_root)},
{SCMP_SYS (clone), &SCMP_A0 (SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)},
/* Don't allow faking input to the controlling tty (CVE-2017-5226) */
{SCMP_SYS (ioctl), &SCMP_A1(SCMP_CMP_EQ, (int)TIOCSTI)},
};
struct
{
int scall;
struct scmp_arg_cmp *arg;
} syscall_nondevel_blacklist[] = {
/* Profiling operations; we expect these to be done by tools from outside
* the sandbox. In particular perf has been the source of many CVEs.
*/
{SCMP_SYS (perf_event_open)},
{SCMP_SYS (ptrace)}
};
/* Blacklist all but unix, inet, inet6 and netlink */
int socket_family_blacklist[] = {
AF_AX25,
AF_IPX,
AF_APPLETALK,
AF_NETROM,
AF_BRIDGE,
AF_ATMPVC,
AF_X25,
AF_ROSE,
AF_DECnet,
AF_NETBEUI,
AF_SECURITY,
AF_KEY,
AF_NETLINK + 1, /* Last gets CMP_GE, so order is important */
};
int i, r;
int fd = -1;
char *fd_str = NULL;
char *path = NULL;
char *arch;
char *args[] = {"/bin/sh", NULL };
seccomp = seccomp_init (SCMP_ACT_ALLOW);
if (!seccomp)
{
g_print ("Initialize seccomp failed");
return 1;
}
arch = "x86_64";
if (arch != NULL)
{
uint32_t arch_id = 0;
const uint32_t *extra_arches = NULL;
if (strcmp (arch, "i386") == 0)
{
arch_id = SCMP_ARCH_X86;
}
else if (strcmp (arch, "x86_64") == 0)
{
arch_id = SCMP_ARCH_X86_64;
extra_arches = seccomp_x86_64_extra_arches;
}
/* We only really need to handle arches on multiarch systems.
* If only one arch is supported the default is fine */
if (arch_id != 0)
{
/* This *adds* the target arch, instead of replacing the
native one. This is not ideal, because we'd like to only
allow the target arch, but we can't really disallow the
native arch at this point, because then bubblewrap
couldn't continue running. */
r = seccomp_arch_add (seccomp, arch_id);
if (r < 0 && r != -EEXIST)
{
g_print ("Failed to add architecture to seccomp filter");
}
}
}
for (i = 0; i < G_N_ELEMENTS (syscall_blacklist); i++)
{
int scall = syscall_blacklist[i].scall;
if (syscall_blacklist[i].arg)
r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 1, *syscall_blacklist[i].arg);
else
r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 0);
if (r < 0 && r == -EFAULT /* unknown syscall */)
{
g_print ("Failed to block syscall %d", scall);
return 1;
}
}
for (i = 0; i < G_N_ELEMENTS (syscall_nondevel_blacklist); i++)
{
int scall = syscall_nondevel_blacklist[i].scall;
if (syscall_nondevel_blacklist[i].arg)
r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 1, *syscall_nondevel_blacklist[i].arg);
else
r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 0);
if (r < 0 && r == -EFAULT /* unknown syscall */)
{
g_print ("Failed to block syscall %d", scall);
return 1;
}
}
/* Socket filtering doesn't work on e.g. i386, so ignore failures here
* However, we need to user seccomp_rule_add_exact to avoid libseccomp doing
* something else: https://github.com/seccomp/libseccomp/issues/8 */
for (i = 0; i < G_N_ELEMENTS (socket_family_blacklist); i++)
{
int family = socket_family_blacklist[i];
if (i == G_N_ELEMENTS (socket_family_blacklist) - 1)
seccomp_rule_add_exact (seccomp, SCMP_ACT_ERRNO (EAFNOSUPPORT), SCMP_SYS (socket), 1, SCMP_A0 (SCMP_CMP_GE, family));
else
seccomp_rule_add_exact (seccomp, SCMP_ACT_ERRNO (EAFNOSUPPORT), SCMP_SYS (socket), 1, SCMP_A0 (SCMP_CMP_EQ, family));
}
if (seccomp_load (seccomp) != 0)
g_print("Failed to load seccomp");
if (execvpe (args[0], args, NULL) == -1)
g_print("Failed to execve");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment