Using st_dev is not sufficient to uniquely identify a mount: You can mount the same device twice, but those are still separate trees, and e.g. by mounting something else inside one of them, they may differ. Using statx(), we can get a mount ID that uniquely identifies a mount. If that is available, add it to the lo_inode key. Most of this patch is taken from Miklos's mail here: https://marc.info/?l=fuse-devel&m=160062521827983 (virtiofsd-use-mount-id.patch attachment) Suggested-by: Miklos Szeredi <mszeredi@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <20201102161859.156603-5-mreitz@redhat.com> Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
177 lines
4.2 KiB
C
177 lines
4.2 KiB
C
/*
|
|
* Seccomp sandboxing for virtiofsd
|
|
*
|
|
* Copyright (C) 2019 Red Hat, Inc.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "passthrough_seccomp.h"
|
|
#include "fuse_i.h"
|
|
#include "fuse_log.h"
|
|
#include <errno.h>
|
|
#include <glib.h>
|
|
#include <seccomp.h>
|
|
#include <stdlib.h>
|
|
|
|
/* Bodge for libseccomp 2.4.2 which broke ppoll */
|
|
#if !defined(__SNR_ppoll) && defined(__SNR_brk)
|
|
#ifdef __NR_ppoll
|
|
#define __SNR_ppoll __NR_ppoll
|
|
#else
|
|
#define __SNR_ppoll __PNR_ppoll
|
|
#endif
|
|
#endif
|
|
|
|
static const int syscall_whitelist[] = {
|
|
/* TODO ireg sem*() syscalls */
|
|
SCMP_SYS(brk),
|
|
SCMP_SYS(capget), /* For CAP_FSETID */
|
|
SCMP_SYS(capset),
|
|
SCMP_SYS(clock_gettime),
|
|
SCMP_SYS(clone),
|
|
#ifdef __NR_clone3
|
|
SCMP_SYS(clone3),
|
|
#endif
|
|
SCMP_SYS(close),
|
|
SCMP_SYS(copy_file_range),
|
|
SCMP_SYS(dup),
|
|
SCMP_SYS(eventfd2),
|
|
SCMP_SYS(exit),
|
|
SCMP_SYS(exit_group),
|
|
SCMP_SYS(fallocate),
|
|
SCMP_SYS(fchdir),
|
|
SCMP_SYS(fchmod),
|
|
SCMP_SYS(fchmodat),
|
|
SCMP_SYS(fchownat),
|
|
SCMP_SYS(fcntl),
|
|
SCMP_SYS(fdatasync),
|
|
SCMP_SYS(fgetxattr),
|
|
SCMP_SYS(flistxattr),
|
|
SCMP_SYS(flock),
|
|
SCMP_SYS(fremovexattr),
|
|
SCMP_SYS(fsetxattr),
|
|
SCMP_SYS(fstat),
|
|
SCMP_SYS(fstatfs),
|
|
SCMP_SYS(fsync),
|
|
SCMP_SYS(ftruncate),
|
|
SCMP_SYS(futex),
|
|
SCMP_SYS(getdents),
|
|
SCMP_SYS(getdents64),
|
|
SCMP_SYS(getegid),
|
|
SCMP_SYS(geteuid),
|
|
SCMP_SYS(getpid),
|
|
SCMP_SYS(gettid),
|
|
SCMP_SYS(gettimeofday),
|
|
SCMP_SYS(getxattr),
|
|
SCMP_SYS(linkat),
|
|
SCMP_SYS(listxattr),
|
|
SCMP_SYS(lseek),
|
|
SCMP_SYS(madvise),
|
|
SCMP_SYS(mkdirat),
|
|
SCMP_SYS(mknodat),
|
|
SCMP_SYS(mmap),
|
|
SCMP_SYS(mprotect),
|
|
SCMP_SYS(mremap),
|
|
SCMP_SYS(munmap),
|
|
SCMP_SYS(newfstatat),
|
|
SCMP_SYS(statx),
|
|
SCMP_SYS(open),
|
|
SCMP_SYS(openat),
|
|
SCMP_SYS(ppoll),
|
|
SCMP_SYS(prctl), /* TODO restrict to just PR_SET_NAME? */
|
|
SCMP_SYS(preadv),
|
|
SCMP_SYS(pread64),
|
|
SCMP_SYS(pwritev),
|
|
SCMP_SYS(pwrite64),
|
|
SCMP_SYS(read),
|
|
SCMP_SYS(readlinkat),
|
|
SCMP_SYS(recvmsg),
|
|
SCMP_SYS(renameat),
|
|
SCMP_SYS(renameat2),
|
|
SCMP_SYS(removexattr),
|
|
SCMP_SYS(rt_sigaction),
|
|
SCMP_SYS(rt_sigprocmask),
|
|
SCMP_SYS(rt_sigreturn),
|
|
SCMP_SYS(sched_getattr),
|
|
SCMP_SYS(sched_setattr),
|
|
SCMP_SYS(sendmsg),
|
|
SCMP_SYS(setresgid),
|
|
SCMP_SYS(setresuid),
|
|
#ifdef __NR_setresgid32
|
|
SCMP_SYS(setresgid32),
|
|
#endif
|
|
#ifdef __NR_setresuid32
|
|
SCMP_SYS(setresuid32),
|
|
#endif
|
|
SCMP_SYS(set_robust_list),
|
|
SCMP_SYS(setxattr),
|
|
SCMP_SYS(symlinkat),
|
|
SCMP_SYS(time), /* Rarely needed, except on static builds */
|
|
SCMP_SYS(tgkill),
|
|
SCMP_SYS(unlinkat),
|
|
SCMP_SYS(unshare),
|
|
SCMP_SYS(utimensat),
|
|
SCMP_SYS(write),
|
|
SCMP_SYS(writev),
|
|
};
|
|
|
|
/* Syscalls used when --syslog is enabled */
|
|
static const int syscall_whitelist_syslog[] = {
|
|
SCMP_SYS(send),
|
|
SCMP_SYS(sendto),
|
|
};
|
|
|
|
static void add_whitelist(scmp_filter_ctx ctx, const int syscalls[], size_t len)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (seccomp_rule_add(ctx, SCMP_ACT_ALLOW, syscalls[i], 0) != 0) {
|
|
fuse_log(FUSE_LOG_ERR, "seccomp_rule_add syscall %d failed\n",
|
|
syscalls[i]);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void setup_seccomp(bool enable_syslog)
|
|
{
|
|
scmp_filter_ctx ctx;
|
|
|
|
#ifdef SCMP_ACT_KILL_PROCESS
|
|
ctx = seccomp_init(SCMP_ACT_KILL_PROCESS);
|
|
/* Handle a newer libseccomp but an older kernel */
|
|
if (!ctx && errno == EOPNOTSUPP) {
|
|
ctx = seccomp_init(SCMP_ACT_TRAP);
|
|
}
|
|
#else
|
|
ctx = seccomp_init(SCMP_ACT_TRAP);
|
|
#endif
|
|
if (!ctx) {
|
|
fuse_log(FUSE_LOG_ERR, "seccomp_init() failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
add_whitelist(ctx, syscall_whitelist, G_N_ELEMENTS(syscall_whitelist));
|
|
if (enable_syslog) {
|
|
add_whitelist(ctx, syscall_whitelist_syslog,
|
|
G_N_ELEMENTS(syscall_whitelist_syslog));
|
|
}
|
|
|
|
/* libvhost-user calls this for post-copy migration, we don't need it */
|
|
if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOSYS),
|
|
SCMP_SYS(userfaultfd), 0) != 0) {
|
|
fuse_log(FUSE_LOG_ERR, "seccomp_rule_add userfaultfd failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (seccomp_load(ctx) < 0) {
|
|
fuse_log(FUSE_LOG_ERR, "seccomp_load() failed\n");
|
|
exit(1);
|
|
}
|
|
|
|
seccomp_release(ctx);
|
|
}
|