github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/profiles/seccomp/seccomp.go (about)

     1  package seccomp // import "github.com/docker/docker/profiles/seccomp"
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/opencontainers/runtime-spec/specs-go"
    10  )
    11  
    12  // Seccomp represents the config for a seccomp profile for syscall restriction.
    13  // It is used to marshal/unmarshal the JSON profiles as accepted by docker, and
    14  // extends the runtime-spec's specs.LinuxSeccomp, overriding some fields to
    15  // provide the ability to define conditional rules based on the host's kernel
    16  // version, architecture, and the container's capabilities.
    17  type Seccomp struct {
    18  	specs.LinuxSeccomp
    19  
    20  	// ArchMap contains a list of Architectures and Sub-architectures for the
    21  	// profile. When generating the profile, this list is expanded to a
    22  	// []specs.Arch, to propagate the Architectures field of the profile.
    23  	ArchMap []Architecture `json:"archMap,omitempty"`
    24  
    25  	// Syscalls contains lists of syscall rules. Rules can define conditions
    26  	// for them to be included or excluded in the resulting profile (based on
    27  	// on kernel version, architecture, capabilities, etc.). These lists are
    28  	// expanded to an specs.Syscall  When generating the profile, these lists
    29  	// are expanded to a []specs.LinuxSyscall.
    30  	Syscalls []*Syscall `json:"syscalls"`
    31  }
    32  
    33  // Architecture is used to represent a specific architecture
    34  // and its sub-architectures
    35  type Architecture struct {
    36  	Arch      specs.Arch   `json:"architecture"`
    37  	SubArches []specs.Arch `json:"subArchitectures"`
    38  }
    39  
    40  // Filter is used to conditionally apply Seccomp rules
    41  type Filter struct {
    42  	Caps   []string `json:"caps,omitempty"`
    43  	Arches []string `json:"arches,omitempty"`
    44  
    45  	// MinKernel describes the minimum kernel version the rule must be applied
    46  	// on, in the format "<kernel version>.<major revision>" (e.g. "3.12").
    47  	//
    48  	// When matching the kernel version of the host, minor revisions, and distro-
    49  	// specific suffixes are ignored, which means that "3.12.25-gentoo", "3.12-1-amd64",
    50  	// "3.12", and "3.12-rc5" are considered equal (kernel 3, major revision 12).
    51  	MinKernel *KernelVersion `json:"minKernel,omitempty"`
    52  }
    53  
    54  // Syscall is used to match a group of syscalls in Seccomp. It extends the
    55  // runtime-spec Syscall type, adding a "Name" field for backward compatibility
    56  // with older JSON representations, additional "Comment" metadata, and conditional
    57  // rules ("Includes", "Excludes") used to generate a runtime-spec Seccomp profile
    58  // based on the container (capabilities) and host's (arch, kernel) configuration.
    59  type Syscall struct {
    60  	specs.LinuxSyscall
    61  	// Deprecated: kept for backward compatibility with old JSON profiles, use Names instead
    62  	Name     string  `json:"name,omitempty"`
    63  	Comment  string  `json:"comment,omitempty"`
    64  	Includes *Filter `json:"includes,omitempty"`
    65  	Excludes *Filter `json:"excludes,omitempty"`
    66  }
    67  
    68  // KernelVersion holds information about the kernel.
    69  type KernelVersion struct {
    70  	Kernel uint64 // Version of the Kernel (i.e., the "4" in "4.1.2-generic")
    71  	Major  uint64 // Major revision of the Kernel (i.e., the "1" in "4.1.2-generic")
    72  }
    73  
    74  // String implements fmt.Stringer for KernelVersion
    75  func (k *KernelVersion) String() string {
    76  	if k.Kernel > 0 || k.Major > 0 {
    77  		return fmt.Sprintf("%d.%d", k.Kernel, k.Major)
    78  	}
    79  	return ""
    80  }
    81  
    82  // MarshalJSON implements json.Unmarshaler for KernelVersion
    83  func (k *KernelVersion) MarshalJSON() ([]byte, error) {
    84  	return json.Marshal(k.String())
    85  }
    86  
    87  // UnmarshalJSON implements json.Marshaler for KernelVersion
    88  func (k *KernelVersion) UnmarshalJSON(version []byte) error {
    89  	var (
    90  		ver string
    91  		err error
    92  	)
    93  
    94  	// make sure we have a string
    95  	if err = json.Unmarshal(version, &ver); err != nil {
    96  		return fmt.Errorf(`invalid kernel version: %s, expected "<kernel>.<major>": %v`, string(version), err)
    97  	}
    98  	if ver == "" {
    99  		return nil
   100  	}
   101  	parts := strings.SplitN(ver, ".", 3)
   102  	if len(parts) != 2 {
   103  		return fmt.Errorf(`invalid kernel version: %s, expected "<kernel>.<major>"`, string(version))
   104  	}
   105  	if k.Kernel, err = strconv.ParseUint(parts[0], 10, 8); err != nil {
   106  		return fmt.Errorf(`invalid kernel version: %s, expected "<kernel>.<major>": %v`, string(version), err)
   107  	}
   108  	if k.Major, err = strconv.ParseUint(parts[1], 10, 8); err != nil {
   109  		return fmt.Errorf(`invalid kernel version: %s, expected "<kernel>.<major>": %v`, string(version), err)
   110  	}
   111  	if k.Kernel == 0 && k.Major == 0 {
   112  		return fmt.Errorf(`invalid kernel version: %s, expected "<kernel>.<major>": version cannot be 0.0`, string(version))
   113  	}
   114  	return nil
   115  }