in-toto / witness

Witness is a pluggable framework for software supply chain risk management. It automates, normalizes, and verifies software artifact provenance.
https://witness.dev
Apache License 2.0
416 stars 60 forks source link

Better sandboxing #241

Open colek42 opened 1 year ago

colek42 commented 1 year ago

Currently, our sandboxing is weak and does not meet the requirements for SLSA level 3/4 attestations. To improve our security posture, we should implement SEComp for sandboxing on Linux.

SEComp provides an additional layer of protection by allowing us to restrict a process's access to system resources based on its label. This ensures that the build process cannot tamper with the build observer.

We need to research and implement SEComp rules to restrict the build runner's access to only necessary system resources. This will prevent any unauthorized access or modification of the system and ensure that our build process is secure.

Once we have implemented SEComp for Linux, we can investigate similar options for Windows.

colek42 commented 1 year ago

I think the best way forward is going to be to use user namespaces and SEComp

colek42 commented 1 year ago
package main

// #include <stdlib.h>
// #include <seccomp.h>
import "C"

import (
    "fmt"
    "os/exec"
    "unsafe"
)

func main() {
    // Define the policy rules
    rules := []string{
        "open",
        "close",
        "read",
        "write",
        "exit",
    }

    // Create a new SEComp filter
    filter, err := C.seccomp_init(C.SCMP_ACT_ALLOW)
    if err != nil {
        fmt.Println("Error initializing seccomp:", err)
        return
    }

    // Add rules to the filter
    for _, rule := range rules {
        syscallNr := C.int(C.__NR_##rule)
        if _, err := C.seccomp_rule_add(filter, C.SCMP_ACT_ALLOW, syscallNr, 0); err != nil {
            fmt.Println("Error adding seccomp rule:", err)
            return
        }
    }

    // Load the filter into the kernel
    if _, err := C.seccomp_load(filter); err != nil {
        fmt.Println("Error loading seccomp filter:", err)
        return
    }

    // Execute the command with the SEComp filter applied
    cmd := exec.Command("/bin/bash", "-c", "echo 'Hello, world!'")
    cmd.SysProcAttr = &syscall.SysProcAttr{
        Seccomp: &syscall.SockFilter{
            Len:    uint16(filter.len),
            Filter: (*syscall.SockFilterElem)(unsafe.Pointer(filter.filter)),
        },
    }
    if err := cmd.Run(); err != nil {
        fmt.Println("Error running command:", err)
        return
    }
}
colek42 commented 1 year ago

Possible filters.

Restrict access to network resources Restrict access to system files and directories Prevent process from creating or modifying files outside of a specific directory Prevent process from executing other processes Limit the amount of CPU and memory resources that the process can use Limit the use of system calls to a whitelist of allowed calls Restrict access to kernel modules Restrict access to specific system devices Restrict access to inter-process communication mechanisms (e.g. sockets, pipes, signals) Prevent process from changing its UID or GID Restrict access to shared memory regions Restrict access to system configuration files (e.g. /etc/passwd, /etc/shadow) Restrict access to sensitive environment variables (e.g. PATH, LD_LIBRARY_PATH) Restrict access to system logs Restrict access to the proc file system Restrict access to system calls related to time manipulation (e.g. gettimeofday, settimeofday) Restrict access to system calls related to process control (e.g. fork, clone, exec) Prevent process from binding to privileged ports (i.e. ports below 1024) Restrict access to system calls related to signal handling (e.g. sigaction, sigprocmask) Restrict access to system calls related to file system manipulation (e.g. mount, umount)

colek42 commented 1 year ago

https://github.com/containers/common/tree/main/pkg/seccomp seems to provide a pure go implementation

mikhailswift commented 1 year ago

I'm a bit confused -- is this issue referring to our builds or builds that Witness observes? If the latter I'm not sure if we will have all the info necessary to create seccomp rules for any arbitrary command.

colek42 commented 1 year ago

The ones that witness observes. Most of the items in the list above could be done. We will have to have some config flags to set though.

colek42 commented 1 year ago

https://github.com/testifysec/witness/issues/259