spec_linux.go 19 KB

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