diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go index 042ba1a2e..14a096038 100644 --- a/libcontainer/configs/config.go +++ b/libcontainer/configs/config.go @@ -31,9 +31,10 @@ type IDMap struct { // for syscalls. Additional architectures can be added by specifying them in // Architectures. type Seccomp struct { - DefaultAction Action `json:"default_action"` - Architectures []string `json:"architectures"` - Syscalls []*Syscall `json:"syscalls"` + DefaultAction Action `json:"default_action"` + Architectures []string `json:"architectures"` + Syscalls []*Syscall `json:"syscalls"` + DefaultErrnoRet *uint `json:"default_errno_ret"` } // Action is taken upon rule match in Seccomp diff --git a/libcontainer/seccomp/patchbpf/enosys_linux.go b/libcontainer/seccomp/patchbpf/enosys_linux.go index f074ad4d8..a8432bfd4 100644 --- a/libcontainer/seccomp/patchbpf/enosys_linux.go +++ b/libcontainer/seccomp/patchbpf/enosys_linux.go @@ -523,6 +523,11 @@ func assemble(program []bpf.Instruction) ([]unix.SockFilter, error) { } func generatePatch(config *configs.Seccomp) ([]bpf.Instruction, error) { + // Patch the generated cBPF only when there is not a defaultErrnoRet set + // and it is different from ENOSYS + if config.DefaultErrnoRet != nil && *config.DefaultErrnoRet == uint(retErrnoEnosys) { + return nil, nil + } // We only add the stub if the default action is not permissive. if isAllowAction(config.DefaultAction) { logrus.Debugf("seccomp: skipping -ENOSYS stub filter generation") diff --git a/libcontainer/seccomp/seccomp_linux.go b/libcontainer/seccomp/seccomp_linux.go index b6d197845..b14d0ede3 100644 --- a/libcontainer/seccomp/seccomp_linux.go +++ b/libcontainer/seccomp/seccomp_linux.go @@ -36,7 +36,7 @@ func InitSeccomp(config *configs.Seccomp) error { return errors.New("cannot initialize Seccomp - nil config passed") } - defaultAction, err := getAction(config.DefaultAction, nil) + defaultAction, err := getAction(config.DefaultAction, config.DefaultErrnoRet) if err != nil { return errors.New("error initializing seccomp - invalid default action") } diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go index 8626be80e..0c99a67ac 100644 --- a/libcontainer/specconv/spec_linux.go +++ b/libcontainer/specconv/spec_linux.go @@ -878,6 +878,7 @@ func SetupSeccomp(config *specs.LinuxSeccomp) (*configs.Seccomp, error) { return nil, err } newConfig.DefaultAction = newDefaultAction + newConfig.DefaultErrnoRet = config.DefaultErrnoRet // Loop through all syscall blocks and convert them to libcontainer format for _, call := range config.Syscalls { diff --git a/tests/integration/seccomp.bats b/tests/integration/seccomp.bats index 937f961a2..e2d529465 100644 --- a/tests/integration/seccomp.bats +++ b/tests/integration/seccomp.bats @@ -21,3 +21,15 @@ function teardown() { runc run test_busybox [ "$status" -eq 0 ] } + +@test "runc run [seccomp defaultErrnoRet=ENXIO]" { + TEST_NAME="seccomp_syscall_test2" + + # Compile the test binary and update the config to run it. + gcc -static -o rootfs/seccomp_test2 "${TESTDATA}/${TEST_NAME}.c" + update_config ".linux.seccomp = $(<"${TESTDATA}/${TEST_NAME}.json")" + update_config '.process.args = ["/seccomp_test2"]' + + runc run test_busybox + [ "$status" -eq 0 ] +} diff --git a/tests/integration/testdata/seccomp_syscall_test2.c b/tests/integration/testdata/seccomp_syscall_test2.c new file mode 100644 index 000000000..71d4a1cd4 --- /dev/null +++ b/tests/integration/testdata/seccomp_syscall_test2.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +int main() +{ + if (chdir("/") < 0 && errno == ENXIO) + exit(EXIT_SUCCESS); + fprintf(stderr, "got errno=%m\n"); + exit(EXIT_FAILURE); +} diff --git a/tests/integration/testdata/seccomp_syscall_test2.json b/tests/integration/testdata/seccomp_syscall_test2.json new file mode 100644 index 000000000..f9fb11a43 --- /dev/null +++ b/tests/integration/testdata/seccomp_syscall_test2.json @@ -0,0 +1,356 @@ +{ + "defaultAction": "SCMP_ACT_ERRNO", + "defaultErrnoRet": 6, + "architectures": [ + "SCMP_ARCH_X86", + "SCMP_ARCH_X32", + "SCMP_ARCH_X86_64", + "SCMP_ARCH_AARCH64", + "SCMP_ARCH_ARM" + ], + "syscalls": [ + { + "action": "SCMP_ACT_ALLOW", + "names": [ + "accept", + "accept4", + "access", + "adjtimex", + "alarm", + "arch_prctl", + "bind", + "brk", + "capget", + "capset", + "chmod", + "chown", + "chown32", + "clock_adjtime", + "clock_adjtime64", + "clock_getres", + "clock_getres_time64", + "clock_gettime", + "clock_gettime64", + "clock_nanosleep", + "clock_nanosleep_time64", + "close", + "connect", + "copy_file_range", + "creat", + "dup", + "dup2", + "epoll_create", + "epoll_create1", + "epoll_ctl", + "epoll_ctl_old", + "epoll_pwait", + "epoll_wait", + "epoll_wait_old", + "eventfd", + "eventfd2", + "execve", + "execveat", + "exit", + "exit_group", + "faccessat", + "faccessat2", + "fadvise64", + "fadvise64_64", + "fallocate", + "fanotify_mark", + "fchdir", + "fchmod", + "fchmodat", + "fchown", + "fchown32", + "fchownat", + "fcntl", + "fcntl64", + "fdatasync", + "fgetxattr", + "flistxattr", + "flock", + "fork", + "fremovexattr", + "fsetxattr", + "fstat", + "fstat64", + "fstatat64", + "fstatfs", + "fstatfs64", + "fsync", + "ftruncate", + "ftruncate64", + "futex", + "futex_time64", + "futimesat", + "getcpu", + "getcwd", + "getdents", + "getdents64", + "getegid", + "getegid32", + "geteuid", + "geteuid32", + "getgid", + "getgid32", + "getgroups", + "getgroups32", + "getitimer", + "getpeername", + "getpgid", + "getpgrp", + "getpid", + "getppid", + "getpriority", + "getrandom", + "getresgid", + "getresgid32", + "getresuid", + "getresuid32", + "getrlimit", + "get_robust_list", + "getrusage", + "getsid", + "getsockname", + "getsockopt", + "get_thread_area", + "gettid", + "gettimeofday", + "getuid", + "getuid32", + "getxattr", + "inotify_add_watch", + "inotify_init", + "inotify_init1", + "inotify_rm_watch", + "io_cancel", + "ioctl", + "io_destroy", + "io_getevents", + "io_pgetevents", + "io_pgetevents_time64", + "ioprio_get", + "ioprio_set", + "io_setup", + "io_submit", + "io_uring_enter", + "io_uring_register", + "io_uring_setup", + "ipc", + "kill", + "lchown", + "lchown32", + "lgetxattr", + "link", + "linkat", + "listen", + "listxattr", + "llistxattr", + "_llseek", + "lremovexattr", + "lseek", + "lsetxattr", + "lstat", + "lstat64", + "madvise", + "membarrier", + "memfd_create", + "mincore", + "mkdir", + "mkdirat", + "mknod", + "mknodat", + "mlock", + "mlock2", + "mlockall", + "mmap", + "mmap2", + "modify_ldt", + "mprotect", + "mq_getsetattr", + "mq_notify", + "mq_open", + "mq_timedreceive", + "mq_timedreceive_time64", + "mq_timedsend", + "mq_timedsend_time64", + "mq_unlink", + "mremap", + "msgctl", + "msgget", + "msgrcv", + "msgsnd", + "msync", + "munlock", + "munlockall", + "munmap", + "nanosleep", + "newfstatat", + "_newselect", + "open", + "openat", + "openat2", + "pause", + "pidfd_open", + "pidfd_send_signal", + "pipe", + "pipe2", + "poll", + "ppoll", + "ppoll_time64", + "prctl", + "pread64", + "preadv", + "preadv2", + "prlimit64", + "pselect6", + "pselect6_time64", + "pwrite64", + "pwritev", + "pwritev2", + "read", + "readahead", + "readlink", + "readlinkat", + "readv", + "recv", + "recvfrom", + "recvmmsg", + "recvmmsg_time64", + "recvmsg", + "remap_file_pages", + "removexattr", + "rename", + "renameat", + "renameat2", + "restart_syscall", + "rmdir", + "rseq", + "rt_sigaction", + "rt_sigpending", + "rt_sigprocmask", + "rt_sigqueueinfo", + "rt_sigreturn", + "rt_sigsuspend", + "rt_sigtimedwait", + "rt_sigtimedwait_time64", + "rt_tgsigqueueinfo", + "sched_getaffinity", + "sched_getattr", + "sched_getparam", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_getscheduler", + "sched_rr_get_interval", + "sched_rr_get_interval_time64", + "sched_setaffinity", + "sched_setattr", + "sched_setparam", + "sched_setscheduler", + "sched_yield", + "seccomp", + "select", + "semctl", + "semget", + "semop", + "semtimedop", + "semtimedop_time64", + "send", + "sendfile", + "sendfile64", + "sendmmsg", + "sendmsg", + "sendto", + "setfsgid", + "setfsgid32", + "setfsuid", + "setfsuid32", + "setgid", + "setgid32", + "setgroups", + "setgroups32", + "setitimer", + "setpgid", + "setpriority", + "setregid", + "setregid32", + "setresgid", + "setresgid32", + "setresuid", + "setresuid32", + "setreuid", + "setreuid32", + "setrlimit", + "set_robust_list", + "setsid", + "setsockopt", + "set_thread_area", + "set_tid_address", + "setuid", + "setuid32", + "setxattr", + "shmat", + "shmctl", + "shmdt", + "shmget", + "shutdown", + "sigaltstack", + "signalfd", + "signalfd4", + "sigprocmask", + "sigreturn", + "socketcall", + "socketpair", + "splice", + "stat", + "stat64", + "statfs", + "statfs64", + "statx", + "symlink", + "symlinkat", + "sync", + "sync_file_range", + "syncfs", + "sysinfo", + "tee", + "tgkill", + "time", + "timer_create", + "timer_delete", + "timer_getoverrun", + "timer_gettime", + "timer_gettime64", + "timer_settime", + "timer_settime64", + "timerfd_create", + "timerfd_gettime", + "timerfd_gettime64", + "timerfd_settime", + "timerfd_settime64", + "times", + "tkill", + "truncate", + "truncate64", + "ugetrlimit", + "umask", + "uname", + "unlink", + "unlinkat", + "utime", + "utimensat", + "utimensat_time64", + "utimes", + "vfork", + "vmsplice", + "wait4", + "waitid", + "waitpid", + "write", + "writev" + ] + } + ] +} +