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

     1  // +build linux
     2  
     3  // Package specconv implements conversion of specifications to libcontainer
     4  // configurations
     5  package specconv
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"syscall"
    13  	"time"
    14  
    15  	"github.com/opencontainers/runc/libcontainer/configs"
    16  	"github.com/opencontainers/runc/libcontainer/seccomp"
    17  	libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
    18  	"github.com/opencontainers/runtime-spec/specs-go"
    19  )
    20  
    21  const wildcard = -1
    22  
    23  var namespaceMapping = map[specs.NamespaceType]configs.NamespaceType{
    24  	specs.PIDNamespace:     configs.NEWPID,
    25  	specs.NetworkNamespace: configs.NEWNET,
    26  	specs.MountNamespace:   configs.NEWNS,
    27  	specs.UserNamespace:    configs.NEWUSER,
    28  	specs.IPCNamespace:     configs.NEWIPC,
    29  	specs.UTSNamespace:     configs.NEWUTS,
    30  }
    31  
    32  var mountPropagationMapping = map[string]int{
    33  	"rprivate": syscall.MS_PRIVATE | syscall.MS_REC,
    34  	"private":  syscall.MS_PRIVATE,
    35  	"rslave":   syscall.MS_SLAVE | syscall.MS_REC,
    36  	"slave":    syscall.MS_SLAVE,
    37  	"rshared":  syscall.MS_SHARED | syscall.MS_REC,
    38  	"shared":   syscall.MS_SHARED,
    39  	"":         syscall.MS_PRIVATE | syscall.MS_REC,
    40  }
    41  
    42  var allowedDevices = []*configs.Device{
    43  	// allow mknod for any device
    44  	{
    45  		Type:        'c',
    46  		Major:       wildcard,
    47  		Minor:       wildcard,
    48  		Permissions: "m",
    49  		Allow:       true,
    50  	},
    51  	{
    52  		Type:        'b',
    53  		Major:       wildcard,
    54  		Minor:       wildcard,
    55  		Permissions: "m",
    56  		Allow:       true,
    57  	},
    58  	{
    59  		Type:        'c',
    60  		Path:        "/dev/null",
    61  		Major:       1,
    62  		Minor:       3,
    63  		Permissions: "rwm",
    64  		Allow:       true,
    65  	},
    66  	{
    67  		Type:        'c',
    68  		Path:        "/dev/random",
    69  		Major:       1,
    70  		Minor:       8,
    71  		Permissions: "rwm",
    72  		Allow:       true,
    73  	},
    74  	{
    75  		Type:        'c',
    76  		Path:        "/dev/full",
    77  		Major:       1,
    78  		Minor:       7,
    79  		Permissions: "rwm",
    80  		Allow:       true,
    81  	},
    82  	{
    83  		Type:        'c',
    84  		Path:        "/dev/tty",
    85  		Major:       5,
    86  		Minor:       0,
    87  		Permissions: "rwm",
    88  		Allow:       true,
    89  	},
    90  	{
    91  		Type:        'c',
    92  		Path:        "/dev/zero",
    93  		Major:       1,
    94  		Minor:       5,
    95  		Permissions: "rwm",
    96  		Allow:       true,
    97  	},
    98  	{
    99  		Type:        'c',
   100  		Path:        "/dev/urandom",
   101  		Major:       1,
   102  		Minor:       9,
   103  		Permissions: "rwm",
   104  		Allow:       true,
   105  	},
   106  	{
   107  		Path:        "/dev/console",
   108  		Type:        'c',
   109  		Major:       5,
   110  		Minor:       1,
   111  		Permissions: "rwm",
   112  		Allow:       true,
   113  	},
   114  	// /dev/pts/ - pts namespaces are "coming soon"
   115  	{
   116  		Path:        "",
   117  		Type:        'c',
   118  		Major:       136,
   119  		Minor:       wildcard,
   120  		Permissions: "rwm",
   121  		Allow:       true,
   122  	},
   123  	{
   124  		Path:        "",
   125  		Type:        'c',
   126  		Major:       5,
   127  		Minor:       2,
   128  		Permissions: "rwm",
   129  		Allow:       true,
   130  	},
   131  	// tuntap
   132  	{
   133  		Path:        "",
   134  		Type:        'c',
   135  		Major:       10,
   136  		Minor:       200,
   137  		Permissions: "rwm",
   138  		Allow:       true,
   139  	},
   140  }
   141  
   142  type CreateOpts struct {
   143  	CgroupName       string
   144  	UseSystemdCgroup bool
   145  	NoPivotRoot      bool
   146  	NoNewKeyring     bool
   147  	Spec             *specs.Spec
   148  }
   149  
   150  // CreateLibcontainerConfig creates a new libcontainer configuration from a
   151  // given specification and a cgroup name
   152  func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
   153  	// runc's cwd will always be the bundle path
   154  	rcwd, err := os.Getwd()
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  	cwd, err := filepath.Abs(rcwd)
   159  	if err != nil {
   160  		return nil, err
   161  	}
   162  	spec := opts.Spec
   163  	rootfsPath := spec.Root.Path
   164  	if !filepath.IsAbs(rootfsPath) {
   165  		rootfsPath = filepath.Join(cwd, rootfsPath)
   166  	}
   167  	labels := []string{}
   168  	for k, v := range spec.Annotations {
   169  		labels = append(labels, fmt.Sprintf("%s=%s", k, v))
   170  	}
   171  	config := &configs.Config{
   172  		Rootfs:       rootfsPath,
   173  		NoPivotRoot:  opts.NoPivotRoot,
   174  		Readonlyfs:   spec.Root.Readonly,
   175  		Hostname:     spec.Hostname,
   176  		Labels:       append(labels, fmt.Sprintf("bundle=%s", cwd)),
   177  		NoNewKeyring: opts.NoNewKeyring,
   178  	}
   179  
   180  	exists := false
   181  	if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists {
   182  		return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation)
   183  	}
   184  
   185  	for _, ns := range spec.Linux.Namespaces {
   186  		t, exists := namespaceMapping[ns.Type]
   187  		if !exists {
   188  			return nil, fmt.Errorf("namespace %q does not exist", ns)
   189  		}
   190  		if config.Namespaces.Contains(t) {
   191  			return nil, fmt.Errorf("malformed spec file: duplicated ns %q", ns)
   192  		}
   193  		config.Namespaces.Add(t, ns.Path)
   194  	}
   195  	if config.Namespaces.Contains(configs.NEWNET) {
   196  		config.Networks = []*configs.Network{
   197  			{
   198  				Type: "loopback",
   199  			},
   200  		}
   201  	}
   202  	for _, m := range spec.Mounts {
   203  		config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m))
   204  	}
   205  	if err := createDevices(spec, config); err != nil {
   206  		return nil, err
   207  	}
   208  	if err := setupUserNamespace(spec, config); err != nil {
   209  		return nil, err
   210  	}
   211  	c, err := createCgroupConfig(opts.CgroupName, opts.UseSystemdCgroup, spec)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  	config.Cgroups = c
   216  	// set extra path masking for libcontainer for the various unsafe places in proc
   217  	config.MaskPaths = spec.Linux.MaskedPaths
   218  	config.ReadonlyPaths = spec.Linux.ReadonlyPaths
   219  	if spec.Linux.Seccomp != nil {
   220  		seccomp, err := setupSeccomp(spec.Linux.Seccomp)
   221  		if err != nil {
   222  			return nil, err
   223  		}
   224  		config.Seccomp = seccomp
   225  	}
   226  	if spec.Process.SelinuxLabel != "" {
   227  		config.ProcessLabel = spec.Process.SelinuxLabel
   228  	}
   229  	config.Sysctl = spec.Linux.Sysctl
   230  	if spec.Linux.Resources != nil && spec.Linux.Resources.OOMScoreAdj != nil {
   231  		config.OomScoreAdj = *spec.Linux.Resources.OOMScoreAdj
   232  	}
   233  	createHooks(spec, config)
   234  	config.MountLabel = spec.Linux.MountLabel
   235  	config.Version = specs.Version
   236  	return config, nil
   237  }
   238  
   239  func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount {
   240  	flags, pgflags, data, ext := parseMountOptions(m.Options)
   241  	source := m.Source
   242  	if m.Type == "bind" {
   243  		if !filepath.IsAbs(source) {
   244  			source = filepath.Join(cwd, m.Source)
   245  		}
   246  	}
   247  	return &configs.Mount{
   248  		Device:           m.Type,
   249  		Source:           source,
   250  		Destination:      m.Destination,
   251  		Data:             data,
   252  		Flags:            flags,
   253  		PropagationFlags: pgflags,
   254  		Extensions:       ext,
   255  	}
   256  }
   257  
   258  func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*configs.Cgroup, error) {
   259  	var myCgroupPath string
   260  
   261  	c := &configs.Cgroup{
   262  		Resources: &configs.Resources{},
   263  	}
   264  
   265  	if spec.Linux != nil && spec.Linux.CgroupsPath != nil {
   266  		myCgroupPath = libcontainerUtils.CleanPath(*spec.Linux.CgroupsPath)
   267  		if useSystemdCgroup {
   268  			myCgroupPath = *spec.Linux.CgroupsPath
   269  		}
   270  	}
   271  
   272  	if useSystemdCgroup {
   273  		if myCgroupPath == "" {
   274  			c.Parent = "system.slice"
   275  			c.ScopePrefix = "runc"
   276  			c.Name = name
   277  		} else {
   278  			// Parse the path from expected "slice:prefix:name"
   279  			// for e.g. "system.slice:docker:1234"
   280  			parts := strings.Split(myCgroupPath, ":")
   281  			if len(parts) != 3 {
   282  				return nil, fmt.Errorf("expected cgroupsPath to be of format \"slice:prefix:name\" for systemd cgroups")
   283  			}
   284  			c.Parent = parts[0]
   285  			c.ScopePrefix = parts[1]
   286  			c.Name = parts[2]
   287  		}
   288  	} else {
   289  		if myCgroupPath == "" {
   290  			c.Name = name
   291  		}
   292  		c.Path = myCgroupPath
   293  	}
   294  
   295  	c.Resources.AllowedDevices = allowedDevices
   296  	if spec.Linux == nil {
   297  		return c, nil
   298  	}
   299  	r := spec.Linux.Resources
   300  	if r == nil {
   301  		return c, nil
   302  	}
   303  	for i, d := range spec.Linux.Resources.Devices {
   304  		var (
   305  			t     = "a"
   306  			major = int64(-1)
   307  			minor = int64(-1)
   308  		)
   309  		if d.Type != nil {
   310  			t = *d.Type
   311  		}
   312  		if d.Major != nil {
   313  			major = *d.Major
   314  		}
   315  		if d.Minor != nil {
   316  			minor = *d.Minor
   317  		}
   318  		if d.Access == nil || *d.Access == "" {
   319  			return nil, fmt.Errorf("device access at %d field cannot be empty", i)
   320  		}
   321  		dt, err := stringToDeviceRune(t)
   322  		if err != nil {
   323  			return nil, err
   324  		}
   325  		dd := &configs.Device{
   326  			Type:        dt,
   327  			Major:       major,
   328  			Minor:       minor,
   329  			Permissions: *d.Access,
   330  			Allow:       d.Allow,
   331  		}
   332  		c.Resources.Devices = append(c.Resources.Devices, dd)
   333  	}
   334  	// append the default allowed devices to the end of the list
   335  	c.Resources.Devices = append(c.Resources.Devices, allowedDevices...)
   336  	if r.Memory != nil {
   337  		if r.Memory.Limit != nil {
   338  			c.Resources.Memory = int64(*r.Memory.Limit)
   339  		}
   340  		if r.Memory.Reservation != nil {
   341  			c.Resources.MemoryReservation = int64(*r.Memory.Reservation)
   342  		}
   343  		if r.Memory.Swap != nil {
   344  			c.Resources.MemorySwap = int64(*r.Memory.Swap)
   345  		}
   346  		if r.Memory.Kernel != nil {
   347  			c.Resources.KernelMemory = int64(*r.Memory.Kernel)
   348  		}
   349  		if r.Memory.KernelTCP != nil {
   350  			c.Resources.KernelMemoryTCP = int64(*r.Memory.KernelTCP)
   351  		}
   352  		if r.Memory.Swappiness != nil {
   353  			swappiness := int64(*r.Memory.Swappiness)
   354  			c.Resources.MemorySwappiness = &swappiness
   355  		}
   356  	}
   357  	if r.CPU != nil {
   358  		if r.CPU.Shares != nil {
   359  			c.Resources.CpuShares = int64(*r.CPU.Shares)
   360  		}
   361  		if r.CPU.Quota != nil {
   362  			c.Resources.CpuQuota = int64(*r.CPU.Quota)
   363  		}
   364  		if r.CPU.Period != nil {
   365  			c.Resources.CpuPeriod = int64(*r.CPU.Period)
   366  		}
   367  		if r.CPU.RealtimeRuntime != nil {
   368  			c.Resources.CpuRtRuntime = int64(*r.CPU.RealtimeRuntime)
   369  		}
   370  		if r.CPU.RealtimePeriod != nil {
   371  			c.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod)
   372  		}
   373  		if r.CPU.Cpus != nil {
   374  			c.Resources.CpusetCpus = *r.CPU.Cpus
   375  		}
   376  		if r.CPU.Mems != nil {
   377  			c.Resources.CpusetMems = *r.CPU.Mems
   378  		}
   379  	}
   380  	if r.Pids != nil && r.Pids.Limit != nil {
   381  		c.Resources.PidsLimit = *r.Pids.Limit
   382  	}
   383  	if r.BlockIO != nil {
   384  		if r.BlockIO.Weight != nil {
   385  			c.Resources.BlkioWeight = *r.BlockIO.Weight
   386  		}
   387  		if r.BlockIO.LeafWeight != nil {
   388  			c.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight
   389  		}
   390  		if r.BlockIO.WeightDevice != nil {
   391  			for _, wd := range r.BlockIO.WeightDevice {
   392  				var weight, leafWeight uint16
   393  				if wd.Weight != nil {
   394  					weight = *wd.Weight
   395  				}
   396  				if wd.LeafWeight != nil {
   397  					leafWeight = *wd.LeafWeight
   398  				}
   399  				weightDevice := configs.NewWeightDevice(wd.Major, wd.Minor, weight, leafWeight)
   400  				c.Resources.BlkioWeightDevice = append(c.Resources.BlkioWeightDevice, weightDevice)
   401  			}
   402  		}
   403  		if r.BlockIO.ThrottleReadBpsDevice != nil {
   404  			for _, td := range r.BlockIO.ThrottleReadBpsDevice {
   405  				var rate uint64
   406  				if td.Rate != nil {
   407  					rate = *td.Rate
   408  				}
   409  				throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
   410  				c.Resources.BlkioThrottleReadBpsDevice = append(c.Resources.BlkioThrottleReadBpsDevice, throttleDevice)
   411  			}
   412  		}
   413  		if r.BlockIO.ThrottleWriteBpsDevice != nil {
   414  			for _, td := range r.BlockIO.ThrottleWriteBpsDevice {
   415  				var rate uint64
   416  				if td.Rate != nil {
   417  					rate = *td.Rate
   418  				}
   419  				throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
   420  				c.Resources.BlkioThrottleWriteBpsDevice = append(c.Resources.BlkioThrottleWriteBpsDevice, throttleDevice)
   421  			}
   422  		}
   423  		if r.BlockIO.ThrottleReadIOPSDevice != nil {
   424  			for _, td := range r.BlockIO.ThrottleReadIOPSDevice {
   425  				var rate uint64
   426  				if td.Rate != nil {
   427  					rate = *td.Rate
   428  				}
   429  				throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
   430  				c.Resources.BlkioThrottleReadIOPSDevice = append(c.Resources.BlkioThrottleReadIOPSDevice, throttleDevice)
   431  			}
   432  		}
   433  		if r.BlockIO.ThrottleWriteIOPSDevice != nil {
   434  			for _, td := range r.BlockIO.ThrottleWriteIOPSDevice {
   435  				var rate uint64
   436  				if td.Rate != nil {
   437  					rate = *td.Rate
   438  				}
   439  				throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate)
   440  				c.Resources.BlkioThrottleWriteIOPSDevice = append(c.Resources.BlkioThrottleWriteIOPSDevice, throttleDevice)
   441  			}
   442  		}
   443  	}
   444  	for _, l := range r.HugepageLimits {
   445  		if l.Pagesize == nil || l.Limit == nil {
   446  			return nil, fmt.Errorf("pagesize and limit can not be empty")
   447  		}
   448  		c.Resources.HugetlbLimit = append(c.Resources.HugetlbLimit, &configs.HugepageLimit{
   449  			Pagesize: *l.Pagesize,
   450  			Limit:    *l.Limit,
   451  		})
   452  	}
   453  	if r.DisableOOMKiller != nil {
   454  		c.Resources.OomKillDisable = *r.DisableOOMKiller
   455  	}
   456  	if r.Network != nil {
   457  		if r.Network.ClassID != nil {
   458  			c.Resources.NetClsClassid = *r.Network.ClassID
   459  		}
   460  		for _, m := range r.Network.Priorities {
   461  			c.Resources.NetPrioIfpriomap = append(c.Resources.NetPrioIfpriomap, &configs.IfPrioMap{
   462  				Interface: m.Name,
   463  				Priority:  int64(m.Priority),
   464  			})
   465  		}
   466  	}
   467  	return c, nil
   468  }
   469  
   470  func stringToDeviceRune(s string) (rune, error) {
   471  	switch s {
   472  	case "a":
   473  		return 'a', nil
   474  	case "b":
   475  		return 'b', nil
   476  	case "c":
   477  		return 'c', nil
   478  	default:
   479  		return 0, fmt.Errorf("invalid device type %q", s)
   480  	}
   481  }
   482  
   483  func createDevices(spec *specs.Spec, config *configs.Config) error {
   484  	// add whitelisted devices
   485  	config.Devices = []*configs.Device{
   486  		{
   487  			Type:     'c',
   488  			Path:     "/dev/null",
   489  			Major:    1,
   490  			Minor:    3,
   491  			FileMode: 0666,
   492  			Uid:      0,
   493  			Gid:      0,
   494  		},
   495  		{
   496  			Type:     'c',
   497  			Path:     "/dev/random",
   498  			Major:    1,
   499  			Minor:    8,
   500  			FileMode: 0666,
   501  			Uid:      0,
   502  			Gid:      0,
   503  		},
   504  		{
   505  			Type:     'c',
   506  			Path:     "/dev/full",
   507  			Major:    1,
   508  			Minor:    7,
   509  			FileMode: 0666,
   510  			Uid:      0,
   511  			Gid:      0,
   512  		},
   513  		{
   514  			Type:     'c',
   515  			Path:     "/dev/tty",
   516  			Major:    5,
   517  			Minor:    0,
   518  			FileMode: 0666,
   519  			Uid:      0,
   520  			Gid:      0,
   521  		},
   522  		{
   523  			Type:     'c',
   524  			Path:     "/dev/zero",
   525  			Major:    1,
   526  			Minor:    5,
   527  			FileMode: 0666,
   528  			Uid:      0,
   529  			Gid:      0,
   530  		},
   531  		{
   532  			Type:     'c',
   533  			Path:     "/dev/urandom",
   534  			Major:    1,
   535  			Minor:    9,
   536  			FileMode: 0666,
   537  			Uid:      0,
   538  			Gid:      0,
   539  		},
   540  	}
   541  	// merge in additional devices from the spec
   542  	for _, d := range spec.Linux.Devices {
   543  		var uid, gid uint32
   544  		var filemode os.FileMode = 0666
   545  
   546  		if d.UID != nil {
   547  			uid = *d.UID
   548  		}
   549  		if d.GID != nil {
   550  			gid = *d.GID
   551  		}
   552  		dt, err := stringToDeviceRune(d.Type)
   553  		if err != nil {
   554  			return err
   555  		}
   556  		if d.FileMode != nil {
   557  			filemode = *d.FileMode
   558  		}
   559  		device := &configs.Device{
   560  			Type:     dt,
   561  			Path:     d.Path,
   562  			Major:    d.Major,
   563  			Minor:    d.Minor,
   564  			FileMode: filemode,
   565  			Uid:      uid,
   566  			Gid:      gid,
   567  		}
   568  		config.Devices = append(config.Devices, device)
   569  	}
   570  	return nil
   571  }
   572  
   573  func setupUserNamespace(spec *specs.Spec, config *configs.Config) error {
   574  	if len(spec.Linux.UIDMappings) == 0 {
   575  		return nil
   576  	}
   577  	create := func(m specs.IDMapping) configs.IDMap {
   578  		return configs.IDMap{
   579  			HostID:      int(m.HostID),
   580  			ContainerID: int(m.ContainerID),
   581  			Size:        int(m.Size),
   582  		}
   583  	}
   584  	for _, m := range spec.Linux.UIDMappings {
   585  		config.UidMappings = append(config.UidMappings, create(m))
   586  	}
   587  	for _, m := range spec.Linux.GIDMappings {
   588  		config.GidMappings = append(config.GidMappings, create(m))
   589  	}
   590  	rootUID, err := config.HostUID()
   591  	if err != nil {
   592  		return err
   593  	}
   594  	rootGID, err := config.HostGID()
   595  	if err != nil {
   596  		return err
   597  	}
   598  	for _, node := range config.Devices {
   599  		node.Uid = uint32(rootUID)
   600  		node.Gid = uint32(rootGID)
   601  	}
   602  	return nil
   603  }
   604  
   605  // parseMountOptions parses the string and returns the flags, propagation
   606  // flags and any mount data that it contains.
   607  func parseMountOptions(options []string) (int, []int, string, int) {
   608  	var (
   609  		flag     int
   610  		pgflag   []int
   611  		data     []string
   612  		extFlags int
   613  	)
   614  	flags := map[string]struct {
   615  		clear bool
   616  		flag  int
   617  	}{
   618  		"async":         {true, syscall.MS_SYNCHRONOUS},
   619  		"atime":         {true, syscall.MS_NOATIME},
   620  		"bind":          {false, syscall.MS_BIND},
   621  		"defaults":      {false, 0},
   622  		"dev":           {true, syscall.MS_NODEV},
   623  		"diratime":      {true, syscall.MS_NODIRATIME},
   624  		"dirsync":       {false, syscall.MS_DIRSYNC},
   625  		"exec":          {true, syscall.MS_NOEXEC},
   626  		"mand":          {false, syscall.MS_MANDLOCK},
   627  		"noatime":       {false, syscall.MS_NOATIME},
   628  		"nodev":         {false, syscall.MS_NODEV},
   629  		"nodiratime":    {false, syscall.MS_NODIRATIME},
   630  		"noexec":        {false, syscall.MS_NOEXEC},
   631  		"nomand":        {true, syscall.MS_MANDLOCK},
   632  		"norelatime":    {true, syscall.MS_RELATIME},
   633  		"nostrictatime": {true, syscall.MS_STRICTATIME},
   634  		"nosuid":        {false, syscall.MS_NOSUID},
   635  		"rbind":         {false, syscall.MS_BIND | syscall.MS_REC},
   636  		"relatime":      {false, syscall.MS_RELATIME},
   637  		"remount":       {false, syscall.MS_REMOUNT},
   638  		"ro":            {false, syscall.MS_RDONLY},
   639  		"rw":            {true, syscall.MS_RDONLY},
   640  		"strictatime":   {false, syscall.MS_STRICTATIME},
   641  		"suid":          {true, syscall.MS_NOSUID},
   642  		"sync":          {false, syscall.MS_SYNCHRONOUS},
   643  	}
   644  	propagationFlags := map[string]int{
   645  		"private":     syscall.MS_PRIVATE,
   646  		"shared":      syscall.MS_SHARED,
   647  		"slave":       syscall.MS_SLAVE,
   648  		"unbindable":  syscall.MS_UNBINDABLE,
   649  		"rprivate":    syscall.MS_PRIVATE | syscall.MS_REC,
   650  		"rshared":     syscall.MS_SHARED | syscall.MS_REC,
   651  		"rslave":      syscall.MS_SLAVE | syscall.MS_REC,
   652  		"runbindable": syscall.MS_UNBINDABLE | syscall.MS_REC,
   653  	}
   654  	extensionFlags := map[string]struct {
   655  		clear bool
   656  		flag  int
   657  	}{
   658  		"tmpcopyup": {false, configs.EXT_COPYUP},
   659  	}
   660  	for _, o := range options {
   661  		// If the option does not exist in the flags table or the flag
   662  		// is not supported on the platform,
   663  		// then it is a data value for a specific fs type
   664  		if f, exists := flags[o]; exists && f.flag != 0 {
   665  			if f.clear {
   666  				flag &= ^f.flag
   667  			} else {
   668  				flag |= f.flag
   669  			}
   670  		} else if f, exists := propagationFlags[o]; exists && f != 0 {
   671  			pgflag = append(pgflag, f)
   672  		} else if f, exists := extensionFlags[o]; exists && f.flag != 0 {
   673  			if f.clear {
   674  				extFlags &= ^f.flag
   675  			} else {
   676  				extFlags |= f.flag
   677  			}
   678  		} else {
   679  			data = append(data, o)
   680  		}
   681  	}
   682  	return flag, pgflag, strings.Join(data, ","), extFlags
   683  }
   684  
   685  func setupSeccomp(config *specs.Seccomp) (*configs.Seccomp, error) {
   686  	if config == nil {
   687  		return nil, nil
   688  	}
   689  
   690  	// No default action specified, no syscalls listed, assume seccomp disabled
   691  	if config.DefaultAction == "" && len(config.Syscalls) == 0 {
   692  		return nil, nil
   693  	}
   694  
   695  	newConfig := new(configs.Seccomp)
   696  	newConfig.Syscalls = []*configs.Syscall{}
   697  
   698  	if len(config.Architectures) > 0 {
   699  		newConfig.Architectures = []string{}
   700  		for _, arch := range config.Architectures {
   701  			newArch, err := seccomp.ConvertStringToArch(string(arch))
   702  			if err != nil {
   703  				return nil, err
   704  			}
   705  			newConfig.Architectures = append(newConfig.Architectures, newArch)
   706  		}
   707  	}
   708  
   709  	// Convert default action from string representation
   710  	newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction))
   711  	if err != nil {
   712  		return nil, err
   713  	}
   714  	newConfig.DefaultAction = newDefaultAction
   715  
   716  	// Loop through all syscall blocks and convert them to libcontainer format
   717  	for _, call := range config.Syscalls {
   718  		newAction, err := seccomp.ConvertStringToAction(string(call.Action))
   719  		if err != nil {
   720  			return nil, err
   721  		}
   722  
   723  		newCall := configs.Syscall{
   724  			Name:   call.Name,
   725  			Action: newAction,
   726  			Args:   []*configs.Arg{},
   727  		}
   728  
   729  		// Loop through all the arguments of the syscall and convert them
   730  		for _, arg := range call.Args {
   731  			newOp, err := seccomp.ConvertStringToOperator(string(arg.Op))
   732  			if err != nil {
   733  				return nil, err
   734  			}
   735  
   736  			newArg := configs.Arg{
   737  				Index:    arg.Index,
   738  				Value:    arg.Value,
   739  				ValueTwo: arg.ValueTwo,
   740  				Op:       newOp,
   741  			}
   742  
   743  			newCall.Args = append(newCall.Args, &newArg)
   744  		}
   745  
   746  		newConfig.Syscalls = append(newConfig.Syscalls, &newCall)
   747  	}
   748  
   749  	return newConfig, nil
   750  }
   751  
   752  func createHooks(rspec *specs.Spec, config *configs.Config) {
   753  	config.Hooks = &configs.Hooks{}
   754  	for _, h := range rspec.Hooks.Prestart {
   755  		cmd := createCommandHook(h)
   756  		config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd))
   757  	}
   758  	for _, h := range rspec.Hooks.Poststart {
   759  		cmd := createCommandHook(h)
   760  		config.Hooks.Poststart = append(config.Hooks.Poststart, configs.NewCommandHook(cmd))
   761  	}
   762  	for _, h := range rspec.Hooks.Poststop {
   763  		cmd := createCommandHook(h)
   764  		config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd))
   765  	}
   766  }
   767  
   768  func createCommandHook(h specs.Hook) configs.Command {
   769  	cmd := configs.Command{
   770  		Path: h.Path,
   771  		Args: h.Args,
   772  		Env:  h.Env,
   773  	}
   774  	if h.Timeout != nil {
   775  		d := time.Duration(*h.Timeout) * time.Second
   776  		cmd.Timeout = &d
   777  	}
   778  	return cmd
   779  }