Skip to content

Commit

Permalink
seccomp: add syscall emulation for safe syscalls, like mknod of /dev/…
Browse files Browse the repository at this point in the history
…null devices.
  • Loading branch information
Snaipe committed May 18, 2022
1 parent c561df7 commit 157dddc
Show file tree
Hide file tree
Showing 12 changed files with 531 additions and 0 deletions.
21 changes: 21 additions & 0 deletions arch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/* Copyright © 2022 Arista Networks, Inc. All rights reserved.
*
* Use of this source code is governed by the MIT license that can be found
* in the LICENSE file.
*/

#ifndef ARCH_H_
# define ARCH_H_

# include "config.h"

# define ARCH_STR_(x) #x
# define ARCH_STR(x) ARCH_STR_(x)

/* *INDENT-OFF* - formatters try to add spaces here */
# define ARCH_HEADER_BASE arch/ARCH
/* *INDENT-ON* */

# include ARCH_STR(ARCH_HEADER_BASE/syscall.h)

#endif /* !ARCH_H_ */
26 changes: 26 additions & 0 deletions arch/x86/syscall.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright © 2022 Arista Networks, Inc. All rights reserved.
*
* Use of this source code is governed by the MIT license that can be found
* in the LICENSE file.
*/

#include <stddef.h>
#include <linux/audit.h>

/* The following is the x86-64-specific BPF boilerplate code for checking
that the BPF program is running on the right architecture + ABI. At
completion of these instructions, the accumulator contains the system
call number. */

/* For the x32 ABI, all system call numbers have bit 30 set */

#define X32_SYSCALL_BIT 0x40000000

#define CHECK_ARCH_AND_LOAD_SYSCALL_NR \
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \
(offsetof(struct seccomp_data, arch))), \
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 0, 2), \
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, \
(offsetof(struct seccomp_data, nr))), \
BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, X32_SYSCALL_BIT, 0, 1), \
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS)
1 change: 1 addition & 0 deletions arch/x86_64
1 change: 1 addition & 0 deletions capable.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# define BST_CAP_SETUID ((uint64_t) 1 << CAP_SETUID)
# define BST_CAP_SETGID ((uint64_t) 1 << CAP_SETGID)
# define BST_CAP_SYS_CHROOT ((uint64_t) 1 << CAP_SYS_CHROOT)
# define BST_CAP_MKNOD ((uint64_t) 1 << CAP_MKNOD)

extern int deny_new_capabilities;

Expand Down
6 changes: 6 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@
# define LIBEXECDIR "@libexecdir@"
# define VERSION "@version@"

#mesondefine ARCH
#mesondefine ARCH_X86
#mesondefine ARCH_X86_64

#mesondefine HAVE_SECCOMP_UNOTIFY

#endif /* !CONFIG_H_ */
15 changes: 15 additions & 0 deletions enter.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@

#include "bst_limits.h"
#include "capable.h"
#include "config.h"
#include "enter.h"
#include "errutil.h"
#include "fd.h"
#include "mount.h"
#include "net.h"
#include "ns.h"
Expand All @@ -38,6 +40,10 @@
#include "sig.h"
#include "util.h"

#ifdef HAVE_SECCOMP_UNOTIFY
# include "sec.h"
#endif

static inline size_t append_argv(char **argv, size_t argc, char *arg)
{
if (argc >= ARG_MAX) {
Expand Down Expand Up @@ -411,6 +417,15 @@ int enter(struct entry_settings *opts)
}

outer_helper_sync(&outer_helper);

#ifdef HAVE_SECCOMP_UNOTIFY
int seccomp_fd = sec_seccomp_install_filter();
if (seccomp_fd != -1) {
send_fd(outer_helper.fd, seccomp_fd);
close(seccomp_fd);
}
#endif

outer_helper_close(&outer_helper);

int rtnl = init_rtnetlink_socket();
Expand Down
16 changes: 16 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ add_project_arguments(
'-D_GNU_SOURCE',
language: ['c'])

arch = host_machine.cpu_family()

config = configuration_data()
config.set('package', meson.project_name())
config.set('bindir', bindir)
config.set('libexecdir', libexecdir)
config.set('version', version)

config.set('ARCH', arch)
config.set('ARCH_@0@'.format(arch.to_upper()), 1)

has_seccomp_unotify = cc.has_header_symbol('linux/seccomp.h', 'SECCOMP_FILTER_FLAG_NEW_LISTENER')
config.set('HAVE_SECCOMP_UNOTIFY', has_seccomp_unotify)

configure_file(input: 'config.h.in', output: 'config.h', configuration: config)

bst_init_sources = [
Expand Down Expand Up @@ -94,6 +102,13 @@ bst_sources = [
'userns.c',
]

if has_seccomp_unotify
bst_sources += [
'proc.c',
'sec.c',
]
endif

executable('bst', bst_sources, install: true)

if not get_option('no-setcap-or-suid')
Expand All @@ -106,6 +121,7 @@ if not get_option('no-setcap-or-suid')
'cap_sys_admin',
'cap_sys_chroot',
'cap_sys_ptrace',
'cap_mknod',
],
'bst-unpersist': [
'cap_sys_admin',
Expand Down
12 changes: 12 additions & 0 deletions outer.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,18 @@
#include <unistd.h>

#include "capable.h"
#include "config.h"
#include "enter.h"
#include "fd.h"
#include "outer.h"
#include "path.h"
#include "userns.h"
#include "util.h"

#ifdef HAVE_SECCOMP_UNOTIFY
# include "sec.h"
#endif

enum {
/* This should be enough for defining our mappings. If we assign
340 mappings, and since each line would contain at most
Expand Down Expand Up @@ -270,7 +276,13 @@ void outer_helper_spawn(struct outer_helper *helper)
ssize_t count = write(fd, &ok, sizeof (ok));
assert((ssize_t)(sizeof (ok)) == count);

#ifdef HAVE_SECCOMP_UNOTIFY
int seccomp_fd = recv_fd(fd);
sec_seccomp_supervisor(seccomp_fd);
__builtin_unreachable();
#else
_exit(0);
#endif
}

void outer_helper_sendpid(const struct outer_helper *helper, pid_t pid)
Expand Down
31 changes: 31 additions & 0 deletions proc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Copyright © 2022 Arista Networks, Inc. All rights reserved.
*
* Use of this source code is governed by the MIT license that can be found
* in the LICENSE file.
*/

#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#include "proc.h"

int proc_read_status(int procfd, struct proc_status *out)
{
memset(out, 0, sizeof (*out));

int statusfd = openat(procfd, "status", O_RDONLY | O_CLOEXEC);
if (statusfd == -1) {
return -1;
}

FILE *f = fdopen(statusfd, "r");

char line[4096];
while (fgets(line, sizeof (line) - 1, f)) {
sscanf(line, "Umask:\t%o\n", &out->umask);
}

fclose(f);
return 0;
}
16 changes: 16 additions & 0 deletions proc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* Copyright © 2022 Arista Networks, Inc. All rights reserved.
*
* Use of this source code is governed by the MIT license that can be found
* in the LICENSE file.
*/

#ifndef PROC_H_
# define PROC_H_

struct proc_status {
mode_t umask;
};

int proc_read_status(int procfd, struct proc_status *out);

#endif /* !PROC_H_ */
Loading

0 comments on commit 157dddc

Please sign in to comment.