Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions spo-seccomp-mitigation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPO Seccomp Mitigation for CVE-2026-31431 (Copy Fail)

This directory provides a mitigation for CVE-2026-31431 using the Kubernetes Security Profiles Operator (SPO). It uses a custom `SeccompProfile` that copies containerd's default allowed syscalls but blocks both `AF_VSOCK` and `AF_ALG` (socket family 38).

## Instructions

**1. Install the Security Profiles Operator (SPO)**
If you do not already have SPO installed in your cluster, follow the installation instructions here:
[SPO Installation & Usage](https://github.com/kubernetes-sigs/security-profiles-operator/blob/main/installation-usage.md)

**2. Deploy the Mitigated Seccomp Profile**
Apply the `seccomp-profile.yaml` to create the profile in your namespace. This profile explicitly denies `AF_ALG` socket creation.
```bash
kubectl apply -f seccomp-profile.yaml
```

**3. Enable Binding on the Namespace**
For the binding to take effect, you must label the target namespace to permit the Security Profiles Operator to modify pods within it:
```bash
kubectl label ns my-namespace spo.x-k8s.io/enable-binding=true
```

**4. Bind the Profile to Containers**
Apply the `profile-binding.yaml` to bind the new seccomp profile to all containers in the namespace.
```bash
kubectl apply -f profile-binding.yaml
```

**5. Restart Existing Pods**
The binding is applied via a mutating webhook during pod creation. Existing pods must be restarted or recreated to pick up the new profile and be protected.
10 changes: 10 additions & 0 deletions spo-seccomp-mitigation/profile-binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
kind: ProfileBinding
metadata:
name: mitigate-copyfail-binding
namespace: my-namespace
spec:
profileRef:
kind: SeccompProfile
name: containerd-default-copyfail-mitigated
image: "*" # Apply to all images in a namespace
107 changes: 107 additions & 0 deletions spo-seccomp-mitigation/seccomp-profile.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
name: containerd-default-copyfail-mitigated
namespace: my-namespace
spec:
defaultAction: SCMP_ACT_ERRNO
architectures:
- SCMP_ARCH_X86_64
- SCMP_ARCH_X86
- SCMP_ARCH_X32
- SCMP_ARCH_AARCH64
- SCMP_ARCH_ARM
syscalls:
# 1. The Mitigated Socket Rule
# Replaces containerd's standard rule to block BOTH AF_VSOCK (40) and AF_ALG (38)
- names:
- socket
action: SCMP_ACT_ALLOW
args:
- index: 0
value: 40 # Containerd default: block AF_VSOCK
op: SCMP_CMP_NEQ
- index: 0
value: 38 # Mitigation: block AF_ALG
op: SCMP_CMP_NEQ

# 2. Containerd's conditional allowed personality domains
- names: ["personality"]
action: SCMP_ACT_ALLOW
args: [{ index: 0, value: 0, op: SCMP_CMP_EQ }]
- names: ["personality"]
action: SCMP_ACT_ALLOW
args: [{ index: 0, value: 8, op: SCMP_CMP_EQ }]
- names: ["personality"]
action: SCMP_ACT_ALLOW
args: [{ index: 0, value: 131072, op: SCMP_CMP_EQ }] # 0x20000
- names: ["personality"]
action: SCMP_ACT_ALLOW
args: [{ index: 0, value: 131080, op: SCMP_CMP_EQ }] # 0x20008
- names: ["personality"]
action: SCMP_ACT_ALLOW
args: [{ index: 0, value: 4294967295, op: SCMP_CMP_EQ }] # 0xffffffff

# 3. Containerd's unconditionally allowed baseline syscalls
- action: SCMP_ACT_ALLOW
names: [
"accept", "accept4", "access", "adjtimex", "alarm", "bind", "brk", "cachestat",
"capget", "capset", "chdir", "chmod", "chown", "chown32", "clock_adjtime",
"clock_adjtime64", "clock_getres", "clock_getres_time64", "clock_gettime",
"clock_gettime64", "clock_nanosleep", "clock_nanosleep_time64", "close",
"close_range", "connect", "copy_file_range", "creat", "dup", "dup2", "dup3",
"epoll_create", "epoll_create1", "epoll_ctl", "epoll_ctl_old", "epoll_pwait",
"epoll_pwait2", "epoll_wait", "epoll_wait_old", "eventfd", "eventfd2", "execve",
"execveat", "exit", "exit_group", "faccessat", "faccessat2", "fadvise64",
"fadvise64_64", "fallocate", "fanotify_mark", "fchdir", "fchmod", "fchmodat",
"fchmodat2", "fchown", "fchown32", "fchownat", "fcntl", "fcntl64", "fdatasync",
"fgetxattr", "flistxattr", "flock", "fork", "fremovexattr", "fsetxattr", "fstat",
"fstat64", "fstatat64", "fstatfs", "fstatfs64", "fsync", "ftruncate", "ftruncate64",
"futex", "futex_requeue", "futex_time64", "futex_wait", "futex_waitv", "futex_wake",
"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", "getxattrat", "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", "ipc", "kill", "landlock_add_rule", "landlock_create_ruleset",
"landlock_restrict_self", "lchown", "lchown32", "lgetxattr", "link", "linkat", "listen",
"listmount", "listxattr", "listxattrat", "llistxattr", "_llseek", "lremovexattr", "lseek",
"lsetxattr", "lsm_get_self_attr", "lsm_list_modules", "lsm_set_self_attr", "lstat",
"lstat64", "madvise", "membarrier", "memfd_create", "memfd_secret", "mincore", "mkdir",
"mkdirat", "mknod", "mknodat", "mlock", "mlock2", "mlockall", "map_shadow_stack", "mmap",
"mmap2", "mprotect", "mq_getsetattr", "mq_notify", "mq_open", "mq_timedreceive",
"mq_timedreceive_time64", "mq_timedsend", "mq_timedsend_time64", "mq_unlink", "mremap",
"mseal", "msgctl", "msgget", "msgrcv", "msgsnd", "msync", "munlock", "munlockall",
"munmap", "name_to_handle_at", "nanosleep", "newfstatat", "_newselect", "open", "openat",
"openat2", "pause", "pidfd_open", "pidfd_send_signal", "pipe", "pipe2", "pkey_alloc",
"pkey_free", "pkey_mprotect", "poll", "ppoll", "ppoll_time64", "prctl", "pread64",
"preadv", "preadv2", "prlimit64", "process_mrelease", "process_vm_readv", "process_vm_writev",
"ptrace", "pselect6", "pselect6_time64", "pwrite64", "pwritev", "pwritev2", "read",
"readahead", "readlink", "readlinkat", "readv", "recv", "recvfrom", "recvmmsg",
"recvmmsg_time64", "recvmsg", "remap_file_pages", "removexattr", "removexattrat",
"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", "setxattrat", "shmat", "shmctl", "shmdt", "shmget", "shutdown", "sigaltstack",
"signalfd", "signalfd4", "sigprocmask", "sigreturn", "socketcall", "socketpair", "splice",
"stat", "stat64", "statfs", "statfs64", "statmount", "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", "uretprobe", "utime", "utimensat", "utimensat_time64",
"utimes", "vfork", "vmsplice", "wait4", "waitid", "waitpid", "write", "writev"
]