github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/configs/config.go (about)

     1  package configs
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"os/exec"
     8  	"time"
     9  
    10  	"github.com/Sirupsen/logrus"
    11  )
    12  
    13  type Rlimit struct {
    14  	Type int    `json:"type"`
    15  	Hard uint64 `json:"hard"`
    16  	Soft uint64 `json:"soft"`
    17  }
    18  
    19  // IDMap represents UID/GID Mappings for User Namespaces.
    20  type IDMap struct {
    21  	ContainerID int `json:"container_id"`
    22  	HostID      int `json:"host_id"`
    23  	Size        int `json:"size"`
    24  }
    25  
    26  // Seccomp represents syscall restrictions
    27  // By default, only the native architecture of the kernel is allowed to be used
    28  // for syscalls. Additional architectures can be added by specifying them in
    29  // Architectures.
    30  type Seccomp struct {
    31  	DefaultAction Action     `json:"default_action"`
    32  	Architectures []string   `json:"architectures"`
    33  	Syscalls      []*Syscall `json:"syscalls"`
    34  }
    35  
    36  // Action is taken upon rule match in Seccomp
    37  type Action int
    38  
    39  const (
    40  	Kill Action = iota + 1
    41  	Errno
    42  	Trap
    43  	Allow
    44  	Trace
    45  )
    46  
    47  // Operator is a comparison operator to be used when matching syscall arguments in Seccomp
    48  type Operator int
    49  
    50  const (
    51  	EqualTo Operator = iota + 1
    52  	NotEqualTo
    53  	GreaterThan
    54  	GreaterThanOrEqualTo
    55  	LessThan
    56  	LessThanOrEqualTo
    57  	MaskEqualTo
    58  )
    59  
    60  // Arg is a rule to match a specific syscall argument in Seccomp
    61  type Arg struct {
    62  	Index    uint     `json:"index"`
    63  	Value    uint64   `json:"value"`
    64  	ValueTwo uint64   `json:"value_two"`
    65  	Op       Operator `json:"op"`
    66  }
    67  
    68  // Syscall is a rule to match a syscall in Seccomp
    69  type Syscall struct {
    70  	Name   string `json:"name"`
    71  	Action Action `json:"action"`
    72  	Args   []*Arg `json:"args"`
    73  }
    74  
    75  // TODO Windows. Many of these fields should be factored out into those parts
    76  // which are common across platforms, and those which are platform specific.
    77  
    78  // Config defines configuration options for executing a process inside a contained environment.
    79  type Config struct {
    80  	// NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs
    81  	// This is a common option when the container is running in ramdisk
    82  	NoPivotRoot bool `json:"no_pivot_root"`
    83  
    84  	// ParentDeathSignal specifies the signal that is sent to the container's process in the case
    85  	// that the parent process dies.
    86  	ParentDeathSignal int `json:"parent_death_signal"`
    87  
    88  	// Path to a directory containing the container's root filesystem.
    89  	Rootfs string `json:"rootfs"`
    90  
    91  	// Readonlyfs will remount the container's rootfs as readonly where only externally mounted
    92  	// bind mounts are writtable.
    93  	Readonlyfs bool `json:"readonlyfs"`
    94  
    95  	// Specifies the mount propagation flags to be applied to /.
    96  	RootPropagation int `json:"rootPropagation"`
    97  
    98  	// Mounts specify additional source and destination paths that will be mounted inside the container's
    99  	// rootfs and mount namespace if specified
   100  	Mounts []*Mount `json:"mounts"`
   101  
   102  	// The device nodes that should be automatically created within the container upon container start.  Note, make sure that the node is marked as allowed in the cgroup as well!
   103  	Devices []*Device `json:"devices"`
   104  
   105  	MountLabel string `json:"mount_label"`
   106  
   107  	// Hostname optionally sets the container's hostname if provided
   108  	Hostname string `json:"hostname"`
   109  
   110  	// Namespaces specifies the container's namespaces that it should setup when cloning the init process
   111  	// If a namespace is not provided that namespace is shared from the container's parent process
   112  	Namespaces Namespaces `json:"namespaces"`
   113  
   114  	// Capabilities specify the capabilities to keep when executing the process inside the container
   115  	// All capbilities not specified will be dropped from the processes capability mask
   116  	Capabilities []string `json:"capabilities"`
   117  
   118  	// Networks specifies the container's network setup to be created
   119  	Networks []*Network `json:"networks"`
   120  
   121  	// Routes can be specified to create entries in the route table as the container is started
   122  	Routes []*Route `json:"routes"`
   123  
   124  	// Cgroups specifies specific cgroup settings for the various subsystems that the container is
   125  	// placed into to limit the resources the container has available
   126  	Cgroups *Cgroup `json:"cgroups"`
   127  
   128  	// AppArmorProfile specifies the profile to apply to the process running in the container and is
   129  	// change at the time the process is execed
   130  	AppArmorProfile string `json:"apparmor_profile,omitempty"`
   131  
   132  	// ProcessLabel specifies the label to apply to the process running in the container.  It is
   133  	// commonly used by selinux
   134  	ProcessLabel string `json:"process_label,omitempty"`
   135  
   136  	// Rlimits specifies the resource limits, such as max open files, to set in the container
   137  	// If Rlimits are not set, the container will inherit rlimits from the parent process
   138  	Rlimits []Rlimit `json:"rlimits,omitempty"`
   139  
   140  	// OomScoreAdj specifies the adjustment to be made by the kernel when calculating oom scores
   141  	// for a process. Valid values are between the range [-1000, '1000'], where processes with
   142  	// higher scores are preferred for being killed.
   143  	// More information about kernel oom score calculation here: https://lwn.net/Articles/317814/
   144  	OomScoreAdj int `json:"oom_score_adj"`
   145  
   146  	// UidMappings is an array of User ID mappings for User Namespaces
   147  	UidMappings []IDMap `json:"uid_mappings"`
   148  
   149  	// GidMappings is an array of Group ID mappings for User Namespaces
   150  	GidMappings []IDMap `json:"gid_mappings"`
   151  
   152  	// MaskPaths specifies paths within the container's rootfs to mask over with a bind
   153  	// mount pointing to /dev/null as to prevent reads of the file.
   154  	MaskPaths []string `json:"mask_paths"`
   155  
   156  	// ReadonlyPaths specifies paths within the container's rootfs to remount as read-only
   157  	// so that these files prevent any writes.
   158  	ReadonlyPaths []string `json:"readonly_paths"`
   159  
   160  	// Sysctl is a map of properties and their values. It is the equivalent of using
   161  	// sysctl -w my.property.name value in Linux.
   162  	Sysctl map[string]string `json:"sysctl"`
   163  
   164  	// Seccomp allows actions to be taken whenever a syscall is made within the container.
   165  	// A number of rules are given, each having an action to be taken if a syscall matches it.
   166  	// A default action to be taken if no rules match is also given.
   167  	Seccomp *Seccomp `json:"seccomp"`
   168  
   169  	// NoNewPrivileges controls whether processes in the container can gain additional privileges.
   170  	NoNewPrivileges bool `json:"no_new_privileges,omitempty"`
   171  
   172  	// Hooks are a collection of actions to perform at various container lifecycle events.
   173  	// CommandHooks are serialized to JSON, but other hooks are not.
   174  	Hooks *Hooks
   175  
   176  	// Version is the version of opencontainer specification that is supported.
   177  	Version string `json:"version"`
   178  
   179  	// Labels are user defined metadata that is stored in the config and populated on the state
   180  	Labels []string `json:"labels"`
   181  
   182  	// NoNewKeyring will not allocated a new session keyring for the container.  It will use the
   183  	// callers keyring in this case.
   184  	NoNewKeyring bool `json:"no_new_keyring"`
   185  }
   186  
   187  type Hooks struct {
   188  	// Prestart commands are executed after the container namespaces are created,
   189  	// but before the user supplied command is executed from init.
   190  	Prestart []Hook
   191  
   192  	// Poststart commands are executed after the container init process starts.
   193  	Poststart []Hook
   194  
   195  	// Poststop commands are executed after the container init process exits.
   196  	Poststop []Hook
   197  }
   198  
   199  func (hooks *Hooks) UnmarshalJSON(b []byte) error {
   200  	var state struct {
   201  		Prestart  []CommandHook
   202  		Poststart []CommandHook
   203  		Poststop  []CommandHook
   204  	}
   205  
   206  	if err := json.Unmarshal(b, &state); err != nil {
   207  		return err
   208  	}
   209  
   210  	deserialize := func(shooks []CommandHook) (hooks []Hook) {
   211  		for _, shook := range shooks {
   212  			hooks = append(hooks, shook)
   213  		}
   214  
   215  		return hooks
   216  	}
   217  
   218  	hooks.Prestart = deserialize(state.Prestart)
   219  	hooks.Poststart = deserialize(state.Poststart)
   220  	hooks.Poststop = deserialize(state.Poststop)
   221  	return nil
   222  }
   223  
   224  func (hooks Hooks) MarshalJSON() ([]byte, error) {
   225  	serialize := func(hooks []Hook) (serializableHooks []CommandHook) {
   226  		for _, hook := range hooks {
   227  			switch chook := hook.(type) {
   228  			case CommandHook:
   229  				serializableHooks = append(serializableHooks, chook)
   230  			default:
   231  				logrus.Warnf("cannot serialize hook of type %T, skipping", hook)
   232  			}
   233  		}
   234  
   235  		return serializableHooks
   236  	}
   237  
   238  	return json.Marshal(map[string]interface{}{
   239  		"prestart":  serialize(hooks.Prestart),
   240  		"poststart": serialize(hooks.Poststart),
   241  		"poststop":  serialize(hooks.Poststop),
   242  	})
   243  }
   244  
   245  // HookState is the payload provided to a hook on execution.
   246  type HookState struct {
   247  	Version    string `json:"ociVersion"`
   248  	ID         string `json:"id"`
   249  	Pid        int    `json:"pid"`
   250  	Root       string `json:"root"`
   251  	BundlePath string `json:"bundlePath"`
   252  }
   253  
   254  type Hook interface {
   255  	// Run executes the hook with the provided state.
   256  	Run(HookState) error
   257  }
   258  
   259  // NewFunctionHook will call the provided function when the hook is run.
   260  func NewFunctionHook(f func(HookState) error) FuncHook {
   261  	return FuncHook{
   262  		run: f,
   263  	}
   264  }
   265  
   266  type FuncHook struct {
   267  	run func(HookState) error
   268  }
   269  
   270  func (f FuncHook) Run(s HookState) error {
   271  	return f.run(s)
   272  }
   273  
   274  type Command struct {
   275  	Path    string         `json:"path"`
   276  	Args    []string       `json:"args"`
   277  	Env     []string       `json:"env"`
   278  	Dir     string         `json:"dir"`
   279  	Timeout *time.Duration `json:"timeout"`
   280  }
   281  
   282  // NewCommandHook will execute the provided command when the hook is run.
   283  func NewCommandHook(cmd Command) CommandHook {
   284  	return CommandHook{
   285  		Command: cmd,
   286  	}
   287  }
   288  
   289  type CommandHook struct {
   290  	Command
   291  }
   292  
   293  func (c Command) Run(s HookState) error {
   294  	b, err := json.Marshal(s)
   295  	if err != nil {
   296  		return err
   297  	}
   298  	var stdout, stderr bytes.Buffer
   299  	cmd := exec.Cmd{
   300  		Path:   c.Path,
   301  		Args:   c.Args,
   302  		Env:    c.Env,
   303  		Stdin:  bytes.NewReader(b),
   304  		Stdout: &stdout,
   305  		Stderr: &stderr,
   306  	}
   307  	if err := cmd.Start(); err != nil {
   308  		return err
   309  	}
   310  	errC := make(chan error, 1)
   311  	go func() {
   312  		err := cmd.Wait()
   313  		if err != nil {
   314  			err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
   315  		}
   316  		errC <- err
   317  	}()
   318  	var timerCh <-chan time.Time
   319  	if c.Timeout != nil {
   320  		timer := time.NewTimer(*c.Timeout)
   321  		defer timer.Stop()
   322  		timerCh = timer.C
   323  	}
   324  	select {
   325  	case err := <-errC:
   326  		return err
   327  	case <-timerCh:
   328  		cmd.Process.Kill()
   329  		cmd.Wait()
   330  		return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
   331  	}
   332  }