summaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runtime-tools
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
committerMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
commita031b83a09a8628435317a03f199cdc18b78262f (patch)
treebc017a96769ce6de33745b8b0b1304ccf38e9df0 /vendor/github.com/opencontainers/runtime-tools
parent2b74391cd5281f6fdf391ff8ad50fd1490f6bf89 (diff)
downloadpodman-a031b83a09a8628435317a03f199cdc18b78262f.tar.gz
podman-a031b83a09a8628435317a03f199cdc18b78262f.tar.bz2
podman-a031b83a09a8628435317a03f199cdc18b78262f.zip
Initial checkin from CRI-O repo
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'vendor/github.com/opencontainers/runtime-tools')
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/LICENSE191
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/README.md84
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/error/error.go92
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/generate.go1256
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go12
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go135
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go55
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go73
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go52
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go577
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go140
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/generate/spec.go109
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/specerror/error.go170
-rw-r--r--vendor/github.com/opencontainers/runtime-tools/validate/validate.go1050
14 files changed, 3996 insertions, 0 deletions
diff --git a/vendor/github.com/opencontainers/runtime-tools/LICENSE b/vendor/github.com/opencontainers/runtime-tools/LICENSE
new file mode 100644
index 000000000..bdc403653
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/LICENSE
@@ -0,0 +1,191 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ Copyright 2015 The Linux Foundation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/opencontainers/runtime-tools/README.md b/vendor/github.com/opencontainers/runtime-tools/README.md
new file mode 100644
index 000000000..bbcafc26e
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/README.md
@@ -0,0 +1,84 @@
+# oci-runtime-tool [![Build Status](https://travis-ci.org/opencontainers/runtime-tools.svg?branch=master)](https://travis-ci.org/opencontainers/runtime-tools) [![Go Report Card](https://goreportcard.com/badge/github.com/opencontainers/runtime-tools)](https://goreportcard.com/report/github.com/opencontainers/runtime-tools)
+
+oci-runtime-tool is a collection of tools for working with the [OCI runtime specification][runtime-spec].
+To build from source code, runtime-tools requires Go 1.7.x or above.
+
+## Generating an OCI runtime spec configuration files
+
+[`oci-runtime-tool generate`][generate.1] generates [configuration JSON][config.json] for an [OCI bundle][bundle].
+[OCI-compatible runtimes][runtime-spec] like [runC][] expect to read the configuration from `config.json`.
+
+```sh
+$ oci-runtime-tool generate --output config.json
+$ cat config.json
+{
+ "ociVersion": "0.5.0",
+ …
+}
+```
+
+## Validating an OCI bundle
+
+[`oci-runtime-tool validate`][validate.1] validates an OCI bundle.
+The error message will be printed if the OCI bundle failed the validation procedure.
+
+```sh
+$ oci-runtime-tool generate
+$ oci-runtime-tool validate
+INFO[0000] Bundle validation succeeded.
+```
+
+## Testing OCI runtimes
+
+```sh
+$ sudo make RUNTIME=runc localvalidation
+RUNTIME=runc go test -tags "" -v github.com/opencontainers/runtime-tools/validation
+=== RUN TestValidateBasic
+TAP version 13
+ok 1 - root filesystem
+ok 2 - hostname
+ok 3 - mounts
+ok 4 - capabilities
+ok 5 - default symlinks
+ok 6 - default devices
+ok 7 - linux devices
+ok 8 - linux process
+ok 9 - masked paths
+ok 10 - oom score adj
+ok 11 - read only paths
+ok 12 - rlimits
+ok 13 - sysctls
+ok 14 - uid mappings
+ok 15 - gid mappings
+1..15
+--- PASS: TestValidateBasic (0.08s)
+=== RUN TestValidateSysctls
+TAP version 13
+ok 1 - root filesystem
+ok 2 - hostname
+ok 3 - mounts
+ok 4 - capabilities
+ok 5 - default symlinks
+ok 6 - default devices
+ok 7 - linux devices
+ok 8 - linux process
+ok 9 - masked paths
+ok 10 - oom score adj
+ok 11 - read only paths
+ok 12 - rlimits
+ok 13 - sysctls
+ok 14 - uid mappings
+ok 15 - gid mappings
+1..15
+--- PASS: TestValidateSysctls (0.20s)
+PASS
+ok github.com/opencontainers/runtime-tools/validation 0.281s
+```
+
+[bundle]: https://github.com/opencontainers/runtime-spec/blob/master/bundle.md
+[config.json]: https://github.com/opencontainers/runtime-spec/blob/master/config.md
+[runC]: https://github.com/opencontainers/runc
+[runtime-spec]: https://github.com/opencontainers/runtime-spec
+
+[generate.1]: man/oci-runtime-tool-generate.1.md
+[validate.1]: man/oci-runtime-tool-validate.1.md
diff --git a/vendor/github.com/opencontainers/runtime-tools/error/error.go b/vendor/github.com/opencontainers/runtime-tools/error/error.go
new file mode 100644
index 000000000..f5a90800e
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/error/error.go
@@ -0,0 +1,92 @@
+// Package error implements generic tooling for tracking RFC 2119
+// violations and linking back to the appropriate specification section.
+package error
+
+import (
+ "fmt"
+ "strings"
+)
+
+// Level represents the RFC 2119 compliance levels
+type Level int
+
+const (
+ // MAY-level
+
+ // May represents 'MAY' in RFC 2119.
+ May Level = iota
+ // Optional represents 'OPTIONAL' in RFC 2119.
+ Optional
+
+ // SHOULD-level
+
+ // Should represents 'SHOULD' in RFC 2119.
+ Should
+ // ShouldNot represents 'SHOULD NOT' in RFC 2119.
+ ShouldNot
+ // Recommended represents 'RECOMMENDED' in RFC 2119.
+ Recommended
+ // NotRecommended represents 'NOT RECOMMENDED' in RFC 2119.
+ NotRecommended
+
+ // MUST-level
+
+ // Must represents 'MUST' in RFC 2119
+ Must
+ // MustNot represents 'MUST NOT' in RFC 2119.
+ MustNot
+ // Shall represents 'SHALL' in RFC 2119.
+ Shall
+ // ShallNot represents 'SHALL NOT' in RFC 2119.
+ ShallNot
+ // Required represents 'REQUIRED' in RFC 2119.
+ Required
+)
+
+// Error represents an error with compliance level and specification reference.
+type Error struct {
+ // Level represents the RFC 2119 compliance level.
+ Level Level
+
+ // Reference is a URL for the violated specification requirement.
+ Reference string
+
+ // Err holds additional details about the violation.
+ Err error
+}
+
+// ParseLevel takes a string level and returns the RFC 2119 compliance level constant.
+func ParseLevel(level string) (Level, error) {
+ switch strings.ToUpper(level) {
+ case "MAY":
+ fallthrough
+ case "OPTIONAL":
+ return May, nil
+ case "SHOULD":
+ fallthrough
+ case "SHOULDNOT":
+ fallthrough
+ case "RECOMMENDED":
+ fallthrough
+ case "NOTRECOMMENDED":
+ return Should, nil
+ case "MUST":
+ fallthrough
+ case "MUSTNOT":
+ fallthrough
+ case "SHALL":
+ fallthrough
+ case "SHALLNOT":
+ fallthrough
+ case "REQUIRED":
+ return Must, nil
+ }
+
+ var l Level
+ return l, fmt.Errorf("%q is not a valid compliance level", level)
+}
+
+// Error returns the error message with specification reference.
+func (err *Error) Error() string {
+ return fmt.Sprintf("%s\nRefer to: %s", err.Err.Error(), err.Reference)
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/generate.go b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go
new file mode 100644
index 000000000..fce88f5e2
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/generate.go
@@ -0,0 +1,1256 @@
+// Package generate implements functions generating container config files.
+package generate
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/opencontainers/runtime-tools/generate/seccomp"
+ "github.com/opencontainers/runtime-tools/validate"
+ "github.com/syndtr/gocapability/capability"
+)
+
+var (
+ // Namespaces include the names of supported namespaces.
+ Namespaces = []string{"network", "pid", "mount", "ipc", "uts", "user", "cgroup"}
+)
+
+// Generator represents a generator for a container spec.
+type Generator struct {
+ spec *rspec.Spec
+ HostSpecific bool
+}
+
+// ExportOptions have toggles for exporting only certain parts of the specification
+type ExportOptions struct {
+ Seccomp bool // seccomp toggles if only seccomp should be exported
+}
+
+// New creates a spec Generator with the default spec.
+func New() Generator {
+ spec := rspec.Spec{
+ Version: rspec.Version,
+ Root: &rspec.Root{
+ Path: "",
+ Readonly: false,
+ },
+ Process: &rspec.Process{
+ Terminal: false,
+ User: rspec.User{},
+ Args: []string{
+ "sh",
+ },
+ Env: []string{
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ "TERM=xterm",
+ },
+ Cwd: "/",
+ Capabilities: &rspec.LinuxCapabilities{
+ Bounding: []string{
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE",
+ },
+ Permitted: []string{
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE",
+ },
+ Inheritable: []string{
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE",
+ },
+ Effective: []string{
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE",
+ },
+ Ambient: []string{
+ "CAP_CHOWN",
+ "CAP_DAC_OVERRIDE",
+ "CAP_FSETID",
+ "CAP_FOWNER",
+ "CAP_MKNOD",
+ "CAP_NET_RAW",
+ "CAP_SETGID",
+ "CAP_SETUID",
+ "CAP_SETFCAP",
+ "CAP_SETPCAP",
+ "CAP_NET_BIND_SERVICE",
+ "CAP_SYS_CHROOT",
+ "CAP_KILL",
+ "CAP_AUDIT_WRITE",
+ },
+ },
+ Rlimits: []rspec.POSIXRlimit{
+ {
+ Type: "RLIMIT_NOFILE",
+ Hard: uint64(1024),
+ Soft: uint64(1024),
+ },
+ },
+ },
+ Hostname: "mrsdalloway",
+ Mounts: []rspec.Mount{
+ {
+ Destination: "/proc",
+ Type: "proc",
+ Source: "proc",
+ Options: nil,
+ },
+ {
+ Destination: "/dev",
+ Type: "tmpfs",
+ Source: "tmpfs",
+ Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
+ },
+ {
+ Destination: "/dev/pts",
+ Type: "devpts",
+ Source: "devpts",
+ Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
+ },
+ {
+ Destination: "/dev/shm",
+ Type: "tmpfs",
+ Source: "shm",
+ Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
+ },
+ {
+ Destination: "/dev/mqueue",
+ Type: "mqueue",
+ Source: "mqueue",
+ Options: []string{"nosuid", "noexec", "nodev"},
+ },
+ {
+ Destination: "/sys",
+ Type: "sysfs",
+ Source: "sysfs",
+ Options: []string{"nosuid", "noexec", "nodev", "ro"},
+ },
+ },
+ Linux: &rspec.Linux{
+ Resources: &rspec.LinuxResources{
+ Devices: []rspec.LinuxDeviceCgroup{
+ {
+ Allow: false,
+ Access: "rwm",
+ },
+ },
+ },
+ Namespaces: []rspec.LinuxNamespace{
+ {
+ Type: "pid",
+ },
+ {
+ Type: "network",
+ },
+ {
+ Type: "ipc",
+ },
+ {
+ Type: "uts",
+ },
+ {
+ Type: "mount",
+ },
+ },
+ Devices: []rspec.LinuxDevice{},
+ },
+ }
+ spec.Linux.Seccomp = seccomp.DefaultProfile(&spec)
+ return Generator{
+ spec: &spec,
+ }
+}
+
+// NewFromSpec creates a spec Generator from a given spec.
+func NewFromSpec(spec *rspec.Spec) Generator {
+ return Generator{
+ spec: spec,
+ }
+}
+
+// NewFromFile loads the template specified in a file into a spec Generator.
+func NewFromFile(path string) (Generator, error) {
+ cf, err := os.Open(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return Generator{}, fmt.Errorf("template configuration at %s not found", path)
+ }
+ }
+ defer cf.Close()
+
+ return NewFromTemplate(cf)
+}
+
+// NewFromTemplate loads the template from io.Reader into a spec Generator.
+func NewFromTemplate(r io.Reader) (Generator, error) {
+ var spec rspec.Spec
+ if err := json.NewDecoder(r).Decode(&spec); err != nil {
+ return Generator{}, err
+ }
+ return Generator{
+ spec: &spec,
+ }, nil
+}
+
+// SetSpec sets the spec in the Generator g.
+func (g *Generator) SetSpec(spec *rspec.Spec) {
+ g.spec = spec
+}
+
+// Spec gets the spec in the Generator g.
+func (g *Generator) Spec() *rspec.Spec {
+ return g.spec
+}
+
+// Save writes the spec into w.
+func (g *Generator) Save(w io.Writer, exportOpts ExportOptions) (err error) {
+ var data []byte
+
+ if g.spec.Linux != nil {
+ buf, err := json.Marshal(g.spec.Linux)
+ if err != nil {
+ return err
+ }
+ if string(buf) == "{}" {
+ g.spec.Linux = nil
+ }
+ }
+
+ if exportOpts.Seccomp {
+ data, err = json.MarshalIndent(g.spec.Linux.Seccomp, "", "\t")
+ } else {
+ data, err = json.MarshalIndent(g.spec, "", "\t")
+ }
+ if err != nil {
+ return err
+ }
+
+ _, err = w.Write(data)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// SaveToFile writes the spec into a file.
+func (g *Generator) SaveToFile(path string, exportOpts ExportOptions) error {
+ f, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ return g.Save(f, exportOpts)
+}
+
+// SetVersion sets g.spec.Version.
+func (g *Generator) SetVersion(version string) {
+ g.initSpec()
+ g.spec.Version = version
+}
+
+// SetRootPath sets g.spec.Root.Path.
+func (g *Generator) SetRootPath(path string) {
+ g.initSpecRoot()
+ g.spec.Root.Path = path
+}
+
+// SetRootReadonly sets g.spec.Root.Readonly.
+func (g *Generator) SetRootReadonly(b bool) {
+ g.initSpecRoot()
+ g.spec.Root.Readonly = b
+}
+
+// SetHostname sets g.spec.Hostname.
+func (g *Generator) SetHostname(s string) {
+ g.initSpec()
+ g.spec.Hostname = s
+}
+
+// ClearAnnotations clears g.spec.Annotations.
+func (g *Generator) ClearAnnotations() {
+ if g.spec == nil {
+ return
+ }
+ g.spec.Annotations = make(map[string]string)
+}
+
+// AddAnnotation adds an annotation into g.spec.Annotations.
+func (g *Generator) AddAnnotation(key, value string) {
+ g.initSpecAnnotations()
+ g.spec.Annotations[key] = value
+}
+
+// RemoveAnnotation remove an annotation from g.spec.Annotations.
+func (g *Generator) RemoveAnnotation(key string) {
+ if g.spec == nil || g.spec.Annotations == nil {
+ return
+ }
+ delete(g.spec.Annotations, key)
+}
+
+// SetProcessConsoleSize sets g.spec.Process.ConsoleSize.
+func (g *Generator) SetProcessConsoleSize(width, height uint) {
+ g.initSpecProcessConsoleSize()
+ g.spec.Process.ConsoleSize.Width = width
+ g.spec.Process.ConsoleSize.Height = height
+}
+
+// SetProcessUID sets g.spec.Process.User.UID.
+func (g *Generator) SetProcessUID(uid uint32) {
+ g.initSpecProcess()
+ g.spec.Process.User.UID = uid
+}
+
+// SetProcessGID sets g.spec.Process.User.GID.
+func (g *Generator) SetProcessGID(gid uint32) {
+ g.initSpecProcess()
+ g.spec.Process.User.GID = gid
+}
+
+// SetProcessCwd sets g.spec.Process.Cwd.
+func (g *Generator) SetProcessCwd(cwd string) {
+ g.initSpecProcess()
+ g.spec.Process.Cwd = cwd
+}
+
+// SetProcessNoNewPrivileges sets g.spec.Process.NoNewPrivileges.
+func (g *Generator) SetProcessNoNewPrivileges(b bool) {
+ g.initSpecProcess()
+ g.spec.Process.NoNewPrivileges = b
+}
+
+// SetProcessTerminal sets g.spec.Process.Terminal.
+func (g *Generator) SetProcessTerminal(b bool) {
+ g.initSpecProcess()
+ g.spec.Process.Terminal = b
+}
+
+// SetProcessApparmorProfile sets g.spec.Process.ApparmorProfile.
+func (g *Generator) SetProcessApparmorProfile(prof string) {
+ g.initSpecProcess()
+ g.spec.Process.ApparmorProfile = prof
+}
+
+// SetProcessArgs sets g.spec.Process.Args.
+func (g *Generator) SetProcessArgs(args []string) {
+ g.initSpecProcess()
+ g.spec.Process.Args = args
+}
+
+// ClearProcessEnv clears g.spec.Process.Env.
+func (g *Generator) ClearProcessEnv() {
+ if g.spec == nil {
+ return
+ }
+ g.spec.Process.Env = []string{}
+}
+
+// AddProcessEnv adds name=value into g.spec.Process.Env, or replaces an
+// existing entry with the given name.
+func (g *Generator) AddProcessEnv(name, value string) {
+ g.initSpecProcess()
+
+ env := fmt.Sprintf("%s=%s", name, value)
+ for idx := range g.spec.Process.Env {
+ if strings.HasPrefix(g.spec.Process.Env[idx], name+"=") {
+ g.spec.Process.Env[idx] = env
+ return
+ }
+ }
+ g.spec.Process.Env = append(g.spec.Process.Env, env)
+}
+
+// AddProcessRlimits adds rlimit into g.spec.Process.Rlimits.
+func (g *Generator) AddProcessRlimits(rType string, rHard uint64, rSoft uint64) {
+ g.initSpecProcess()
+ for i, rlimit := range g.spec.Process.Rlimits {
+ if rlimit.Type == rType {
+ g.spec.Process.Rlimits[i].Hard = rHard
+ g.spec.Process.Rlimits[i].Soft = rSoft
+ return
+ }
+ }
+
+ newRlimit := rspec.POSIXRlimit{
+ Type: rType,
+ Hard: rHard,
+ Soft: rSoft,
+ }
+ g.spec.Process.Rlimits = append(g.spec.Process.Rlimits, newRlimit)
+}
+
+// RemoveProcessRlimits removes a rlimit from g.spec.Process.Rlimits.
+func (g *Generator) RemoveProcessRlimits(rType string) error {
+ if g.spec == nil {
+ return nil
+ }
+ for i, rlimit := range g.spec.Process.Rlimits {
+ if rlimit.Type == rType {
+ g.spec.Process.Rlimits = append(g.spec.Process.Rlimits[:i], g.spec.Process.Rlimits[i+1:]...)
+ return nil
+ }
+ }
+ return nil
+}
+
+// ClearProcessRlimits clear g.spec.Process.Rlimits.
+func (g *Generator) ClearProcessRlimits() {
+ if g.spec == nil {
+ return
+ }
+ g.spec.Process.Rlimits = []rspec.POSIXRlimit{}
+}
+
+// ClearProcessAdditionalGids clear g.spec.Process.AdditionalGids.
+func (g *Generator) ClearProcessAdditionalGids() {
+ if g.spec == nil {
+ return
+ }
+ g.spec.Process.User.AdditionalGids = []uint32{}
+}
+
+// AddProcessAdditionalGid adds an additional gid into g.spec.Process.AdditionalGids.
+func (g *Generator) AddProcessAdditionalGid(gid uint32) {
+ g.initSpecProcess()
+ for _, group := range g.spec.Process.User.AdditionalGids {
+ if group == gid {
+ return
+ }
+ }
+ g.spec.Process.User.AdditionalGids = append(g.spec.Process.User.AdditionalGids, gid)
+}
+
+// SetProcessSelinuxLabel sets g.spec.Process.SelinuxLabel.
+func (g *Generator) SetProcessSelinuxLabel(label string) {
+ g.initSpecProcess()
+ g.spec.Process.SelinuxLabel = label
+}
+
+// SetLinuxCgroupsPath sets g.spec.Linux.CgroupsPath.
+func (g *Generator) SetLinuxCgroupsPath(path string) {
+ g.initSpecLinux()
+ g.spec.Linux.CgroupsPath = path
+}
+
+// SetLinuxMountLabel sets g.spec.Linux.MountLabel.
+func (g *Generator) SetLinuxMountLabel(label string) {
+ g.initSpecLinux()
+ g.spec.Linux.MountLabel = label
+}
+
+// SetProcessOOMScoreAdj sets g.spec.Process.OOMScoreAdj.
+func (g *Generator) SetProcessOOMScoreAdj(adj int) {
+ g.initSpecProcess()
+ g.spec.Process.OOMScoreAdj = &adj
+}
+
+// SetLinuxResourcesCPUShares sets g.spec.Linux.Resources.CPU.Shares.
+func (g *Generator) SetLinuxResourcesCPUShares(shares uint64) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.Shares = &shares
+}
+
+// SetLinuxResourcesCPUQuota sets g.spec.Linux.Resources.CPU.Quota.
+func (g *Generator) SetLinuxResourcesCPUQuota(quota int64) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.Quota = &quota
+}
+
+// SetLinuxResourcesCPUPeriod sets g.spec.Linux.Resources.CPU.Period.
+func (g *Generator) SetLinuxResourcesCPUPeriod(period uint64) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.Period = &period
+}
+
+// SetLinuxResourcesCPURealtimeRuntime sets g.spec.Linux.Resources.CPU.RealtimeRuntime.
+func (g *Generator) SetLinuxResourcesCPURealtimeRuntime(time int64) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.RealtimeRuntime = &time
+}
+
+// SetLinuxResourcesCPURealtimePeriod sets g.spec.Linux.Resources.CPU.RealtimePeriod.
+func (g *Generator) SetLinuxResourcesCPURealtimePeriod(period uint64) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.RealtimePeriod = &period
+}
+
+// SetLinuxResourcesCPUCpus sets g.spec.Linux.Resources.CPU.Cpus.
+func (g *Generator) SetLinuxResourcesCPUCpus(cpus string) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.Cpus = cpus
+}
+
+// SetLinuxResourcesCPUMems sets g.spec.Linux.Resources.CPU.Mems.
+func (g *Generator) SetLinuxResourcesCPUMems(mems string) {
+ g.initSpecLinuxResourcesCPU()
+ g.spec.Linux.Resources.CPU.Mems = mems
+}
+
+// AddLinuxResourcesHugepageLimit adds or sets g.spec.Linux.Resources.HugepageLimits.
+func (g *Generator) AddLinuxResourcesHugepageLimit(pageSize string, limit uint64) {
+ hugepageLimit := rspec.LinuxHugepageLimit{
+ Pagesize: pageSize,
+ Limit: limit,
+ }
+
+ g.initSpecLinuxResources()
+ for i, pageLimit := range g.spec.Linux.Resources.HugepageLimits {
+ if pageLimit.Pagesize == pageSize {
+ g.spec.Linux.Resources.HugepageLimits[i].Limit = limit
+ return
+ }
+ }
+ g.spec.Linux.Resources.HugepageLimits = append(g.spec.Linux.Resources.HugepageLimits, hugepageLimit)
+}
+
+// DropLinuxResourcesHugepageLimit drops a hugepage limit from g.spec.Linux.Resources.HugepageLimits.
+func (g *Generator) DropLinuxResourcesHugepageLimit(pageSize string) error {
+ g.initSpecLinuxResources()
+ for i, pageLimit := range g.spec.Linux.Resources.HugepageLimits {
+ if pageLimit.Pagesize == pageSize {
+ g.spec.Linux.Resources.HugepageLimits = append(g.spec.Linux.Resources.HugepageLimits[:i], g.spec.Linux.Resources.HugepageLimits[i+1:]...)
+ return nil
+ }
+ }
+
+ return nil
+}
+
+// SetLinuxResourcesMemoryLimit sets g.spec.Linux.Resources.Memory.Limit.
+func (g *Generator) SetLinuxResourcesMemoryLimit(limit int64) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.Limit = &limit
+}
+
+// SetLinuxResourcesMemoryReservation sets g.spec.Linux.Resources.Memory.Reservation.
+func (g *Generator) SetLinuxResourcesMemoryReservation(reservation int64) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.Reservation = &reservation
+}
+
+// SetLinuxResourcesMemorySwap sets g.spec.Linux.Resources.Memory.Swap.
+func (g *Generator) SetLinuxResourcesMemorySwap(swap int64) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.Swap = &swap
+}
+
+// SetLinuxResourcesMemoryKernel sets g.spec.Linux.Resources.Memory.Kernel.
+func (g *Generator) SetLinuxResourcesMemoryKernel(kernel int64) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.Kernel = &kernel
+}
+
+// SetLinuxResourcesMemoryKernelTCP sets g.spec.Linux.Resources.Memory.KernelTCP.
+func (g *Generator) SetLinuxResourcesMemoryKernelTCP(kernelTCP int64) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.KernelTCP = &kernelTCP
+}
+
+// SetLinuxResourcesMemorySwappiness sets g.spec.Linux.Resources.Memory.Swappiness.
+func (g *Generator) SetLinuxResourcesMemorySwappiness(swappiness uint64) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.Swappiness = &swappiness
+}
+
+// SetLinuxResourcesMemoryDisableOOMKiller sets g.spec.Linux.Resources.Memory.DisableOOMKiller.
+func (g *Generator) SetLinuxResourcesMemoryDisableOOMKiller(disable bool) {
+ g.initSpecLinuxResourcesMemory()
+ g.spec.Linux.Resources.Memory.DisableOOMKiller = &disable
+}
+
+// SetLinuxResourcesNetworkClassID sets g.spec.Linux.Resources.Network.ClassID.
+func (g *Generator) SetLinuxResourcesNetworkClassID(classid uint32) {
+ g.initSpecLinuxResourcesNetwork()
+ g.spec.Linux.Resources.Network.ClassID = &classid
+}
+
+// AddLinuxResourcesNetworkPriorities adds or sets g.spec.Linux.Resources.Network.Priorities.
+func (g *Generator) AddLinuxResourcesNetworkPriorities(name string, prio uint32) {
+ g.initSpecLinuxResourcesNetwork()
+ for i, netPriority := range g.spec.Linux.Resources.Network.Priorities {
+ if netPriority.Name == name {
+ g.spec.Linux.Resources.Network.Priorities[i].Priority = prio
+ return
+ }
+ }
+ interfacePrio := new(rspec.LinuxInterfacePriority)
+ interfacePrio.Name = name
+ interfacePrio.Priority = prio
+ g.spec.Linux.Resources.Network.Priorities = append(g.spec.Linux.Resources.Network.Priorities, *interfacePrio)
+}
+
+// DropLinuxResourcesNetworkPriorities drops one item from g.spec.Linux.Resources.Network.Priorities.
+func (g *Generator) DropLinuxResourcesNetworkPriorities(name string) {
+ g.initSpecLinuxResourcesNetwork()
+ for i, netPriority := range g.spec.Linux.Resources.Network.Priorities {
+ if netPriority.Name == name {
+ g.spec.Linux.Resources.Network.Priorities = append(g.spec.Linux.Resources.Network.Priorities[:i], g.spec.Linux.Resources.Network.Priorities[i+1:]...)
+ return
+ }
+ }
+}
+
+// SetLinuxResourcesPidsLimit sets g.spec.Linux.Resources.Pids.Limit.
+func (g *Generator) SetLinuxResourcesPidsLimit(limit int64) {
+ g.initSpecLinuxResourcesPids()
+ g.spec.Linux.Resources.Pids.Limit = limit
+}
+
+// ClearLinuxSysctl clears g.spec.Linux.Sysctl.
+func (g *Generator) ClearLinuxSysctl() {
+ if g.spec == nil || g.spec.Linux == nil {
+ return
+ }
+ g.spec.Linux.Sysctl = make(map[string]string)
+}
+
+// AddLinuxSysctl adds a new sysctl config into g.spec.Linux.Sysctl.
+func (g *Generator) AddLinuxSysctl(key, value string) {
+ g.initSpecLinuxSysctl()
+ g.spec.Linux.Sysctl[key] = value
+}
+
+// RemoveLinuxSysctl removes a sysctl config from g.spec.Linux.Sysctl.
+func (g *Generator) RemoveLinuxSysctl(key string) {
+ if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Sysctl == nil {
+ return
+ }
+ delete(g.spec.Linux.Sysctl, key)
+}
+
+// ClearLinuxUIDMappings clear g.spec.Linux.UIDMappings.
+func (g *Generator) ClearLinuxUIDMappings() {
+ if g.spec == nil || g.spec.Linux == nil {
+ return
+ }
+ g.spec.Linux.UIDMappings = []rspec.LinuxIDMapping{}
+}
+
+// AddLinuxUIDMapping adds uidMap into g.spec.Linux.UIDMappings.
+func (g *Generator) AddLinuxUIDMapping(hid, cid, size uint32) {
+ idMapping := rspec.LinuxIDMapping{
+ HostID: hid,
+ ContainerID: cid,
+ Size: size,
+ }
+
+ g.initSpecLinux()
+ g.spec.Linux.UIDMappings = append(g.spec.Linux.UIDMappings, idMapping)
+}
+
+// ClearLinuxGIDMappings clear g.spec.Linux.GIDMappings.
+func (g *Generator) ClearLinuxGIDMappings() {
+ if g.spec == nil || g.spec.Linux == nil {
+ return
+ }
+ g.spec.Linux.GIDMappings = []rspec.LinuxIDMapping{}
+}
+
+// AddLinuxGIDMapping adds gidMap into g.spec.Linux.GIDMappings.
+func (g *Generator) AddLinuxGIDMapping(hid, cid, size uint32) {
+ idMapping := rspec.LinuxIDMapping{
+ HostID: hid,
+ ContainerID: cid,
+ Size: size,
+ }
+
+ g.initSpecLinux()
+ g.spec.Linux.GIDMappings = append(g.spec.Linux.GIDMappings, idMapping)
+}
+
+// SetLinuxRootPropagation sets g.spec.Linux.RootfsPropagation.
+func (g *Generator) SetLinuxRootPropagation(rp string) error {
+ switch rp {
+ case "":
+ case "private":
+ case "rprivate":
+ case "slave":
+ case "rslave":
+ case "shared":
+ case "rshared":
+ default:
+ return fmt.Errorf("rootfs-propagation must be empty or one of private|rprivate|slave|rslave|shared|rshared")
+ }
+ g.initSpecLinux()
+ g.spec.Linux.RootfsPropagation = rp
+ return nil
+}
+
+// ClearPreStartHooks clear g.spec.Hooks.Prestart.
+func (g *Generator) ClearPreStartHooks() {
+ if g.spec == nil {
+ return
+ }
+ if g.spec.Hooks == nil {
+ return
+ }
+ g.spec.Hooks.Prestart = []rspec.Hook{}
+}
+
+// AddPreStartHook add a prestart hook into g.spec.Hooks.Prestart.
+func (g *Generator) AddPreStartHook(path string, args []string) {
+ g.initSpecHooks()
+ hook := rspec.Hook{Path: path, Args: args}
+ for i, hook := range g.spec.Hooks.Prestart {
+ if hook.Path == path {
+ g.spec.Hooks.Prestart[i] = hook
+ return
+ }
+ }
+ g.spec.Hooks.Prestart = append(g.spec.Hooks.Prestart, hook)
+}
+
+// AddPreStartHookEnv adds envs of a prestart hook into g.spec.Hooks.Prestart.
+func (g *Generator) AddPreStartHookEnv(path string, envs []string) {
+ g.initSpecHooks()
+ for i, hook := range g.spec.Hooks.Prestart {
+ if hook.Path == path {
+ g.spec.Hooks.Prestart[i].Env = envs
+ return
+ }
+ }
+ hook := rspec.Hook{Path: path, Env: envs}
+ g.spec.Hooks.Prestart = append(g.spec.Hooks.Prestart, hook)
+}
+
+// AddPreStartHookTimeout adds timeout of a prestart hook into g.spec.Hooks.Prestart.
+func (g *Generator) AddPreStartHookTimeout(path string, timeout int) {
+ g.initSpecHooks()
+ for i, hook := range g.spec.Hooks.Prestart {
+ if hook.Path == path {
+ g.spec.Hooks.Prestart[i].Timeout = &timeout
+ return
+ }
+ }
+ hook := rspec.Hook{Path: path, Timeout: &timeout}
+ g.spec.Hooks.Prestart = append(g.spec.Hooks.Prestart, hook)
+}
+
+// ClearPostStopHooks clear g.spec.Hooks.Poststop.
+func (g *Generator) ClearPostStopHooks() {
+ if g.spec == nil {
+ return
+ }
+ if g.spec.Hooks == nil {
+ return
+ }
+ g.spec.Hooks.Poststop = []rspec.Hook{}
+}
+
+// AddPostStopHook adds a poststop hook into g.spec.Hooks.Poststop.
+func (g *Generator) AddPostStopHook(path string, args []string) {
+ g.initSpecHooks()
+ hook := rspec.Hook{Path: path, Args: args}
+ for i, hook := range g.spec.Hooks.Poststop {
+ if hook.Path == path {
+ g.spec.Hooks.Poststop[i] = hook
+ return
+ }
+ }
+ g.spec.Hooks.Poststop = append(g.spec.Hooks.Poststop, hook)
+}
+
+// AddPostStopHookEnv adds envs of a poststop hook into g.spec.Hooks.Poststop.
+func (g *Generator) AddPostStopHookEnv(path string, envs []string) {
+ g.initSpecHooks()
+ for i, hook := range g.spec.Hooks.Poststop {
+ if hook.Path == path {
+ g.spec.Hooks.Poststop[i].Env = envs
+ return
+ }
+ }
+ hook := rspec.Hook{Path: path, Env: envs}
+ g.spec.Hooks.Poststop = append(g.spec.Hooks.Poststop, hook)
+}
+
+// AddPostStopHookTimeout adds timeout of a poststop hook into g.spec.Hooks.Poststop.
+func (g *Generator) AddPostStopHookTimeout(path string, timeout int) {
+ g.initSpecHooks()
+ for i, hook := range g.spec.Hooks.Poststop {
+ if hook.Path == path {
+ g.spec.Hooks.Poststop[i].Timeout = &timeout
+ return
+ }
+ }
+ hook := rspec.Hook{Path: path, Timeout: &timeout}
+ g.spec.Hooks.Poststop = append(g.spec.Hooks.Poststop, hook)
+}
+
+// ClearPostStartHooks clear g.spec.Hooks.Poststart.
+func (g *Generator) ClearPostStartHooks() {
+ if g.spec == nil {
+ return
+ }
+ if g.spec.Hooks == nil {
+ return
+ }
+ g.spec.Hooks.Poststart = []rspec.Hook{}
+}
+
+// AddPostStartHook adds a poststart hook into g.spec.Hooks.Poststart.
+func (g *Generator) AddPostStartHook(path string, args []string) {
+ g.initSpecHooks()
+ hook := rspec.Hook{Path: path, Args: args}
+ for i, hook := range g.spec.Hooks.Poststart {
+ if hook.Path == path {
+ g.spec.Hooks.Poststart[i] = hook
+ return
+ }
+ }
+ g.spec.Hooks.Poststart = append(g.spec.Hooks.Poststart, hook)
+}
+
+// AddPostStartHookEnv adds envs of a poststart hook into g.spec.Hooks.Poststart.
+func (g *Generator) AddPostStartHookEnv(path string, envs []string) {
+ g.initSpecHooks()
+ for i, hook := range g.spec.Hooks.Poststart {
+ if hook.Path == path {
+ g.spec.Hooks.Poststart[i].Env = envs
+ return
+ }
+ }
+ hook := rspec.Hook{Path: path, Env: envs}
+ g.spec.Hooks.Poststart = append(g.spec.Hooks.Poststart, hook)
+}
+
+// AddPostStartHookTimeout adds timeout of a poststart hook into g.spec.Hooks.Poststart.
+func (g *Generator) AddPostStartHookTimeout(path string, timeout int) {
+ g.initSpecHooks()
+ for i, hook := range g.spec.Hooks.Poststart {
+ if hook.Path == path {
+ g.spec.Hooks.Poststart[i].Timeout = &timeout
+ return
+ }
+ }
+ hook := rspec.Hook{Path: path, Timeout: &timeout}
+ g.spec.Hooks.Poststart = append(g.spec.Hooks.Poststart, hook)
+}
+
+// AddTmpfsMount adds a tmpfs mount into g.spec.Mounts.
+func (g *Generator) AddTmpfsMount(dest string, options []string) {
+ mnt := rspec.Mount{
+ Destination: dest,
+ Type: "tmpfs",
+ Source: "tmpfs",
+ Options: options,
+ }
+
+ g.initSpec()
+ g.spec.Mounts = append(g.spec.Mounts, mnt)
+}
+
+// AddCgroupsMount adds a cgroup mount into g.spec.Mounts.
+func (g *Generator) AddCgroupsMount(mountCgroupOption string) error {
+ switch mountCgroupOption {
+ case "ro":
+ case "rw":
+ case "no":
+ return nil
+ default:
+ return fmt.Errorf("--mount-cgroups should be one of (ro,rw,no)")
+ }
+
+ mnt := rspec.Mount{
+ Destination: "/sys/fs/cgroup",
+ Type: "cgroup",
+ Source: "cgroup",
+ Options: []string{"nosuid", "noexec", "nodev", "relatime", mountCgroupOption},
+ }
+ g.initSpec()
+ g.spec.Mounts = append(g.spec.Mounts, mnt)
+
+ return nil
+}
+
+// AddBindMount adds a bind mount into g.spec.Mounts.
+func (g *Generator) AddBindMount(source, dest string, options []string) {
+ if len(options) == 0 {
+ options = []string{"rw"}
+ }
+
+ // We have to make sure that there is a bind option set, otherwise it won't
+ // be an actual bindmount.
+ foundBindOption := false
+ for _, opt := range options {
+ if opt == "bind" || opt == "rbind" {
+ foundBindOption = true
+ break
+ }
+ }
+ if !foundBindOption {
+ options = append(options, "bind")
+ }
+
+ mnt := rspec.Mount{
+ Destination: dest,
+ Type: "bind",
+ Source: source,
+ Options: options,
+ }
+ g.initSpec()
+ g.spec.Mounts = append(g.spec.Mounts, mnt)
+}
+
+// SetupPrivileged sets up the privilege-related fields inside g.spec.
+func (g *Generator) SetupPrivileged(privileged bool) {
+ if privileged { // Add all capabilities in privileged mode.
+ var finalCapList []string
+ for _, cap := range capability.List() {
+ if g.HostSpecific && cap > validate.LastCap() {
+ continue
+ }
+ finalCapList = append(finalCapList, fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())))
+ }
+ g.initSpecLinux()
+ g.initSpecProcessCapabilities()
+ g.ClearProcessCapabilities()
+ g.spec.Process.Capabilities.Bounding = append(g.spec.Process.Capabilities.Bounding, finalCapList...)
+ g.spec.Process.Capabilities.Effective = append(g.spec.Process.Capabilities.Effective, finalCapList...)
+ g.spec.Process.Capabilities.Inheritable = append(g.spec.Process.Capabilities.Inheritable, finalCapList...)
+ g.spec.Process.Capabilities.Permitted = append(g.spec.Process.Capabilities.Permitted, finalCapList...)
+ g.spec.Process.Capabilities.Ambient = append(g.spec.Process.Capabilities.Ambient, finalCapList...)
+ g.spec.Process.SelinuxLabel = ""
+ g.spec.Process.ApparmorProfile = ""
+ g.spec.Linux.Seccomp = nil
+ }
+}
+
+// ClearProcessCapabilities clear g.spec.Process.Capabilities.
+func (g *Generator) ClearProcessCapabilities() {
+ if g.spec == nil {
+ return
+ }
+ g.spec.Process.Capabilities.Bounding = []string{}
+ g.spec.Process.Capabilities.Effective = []string{}
+ g.spec.Process.Capabilities.Inheritable = []string{}
+ g.spec.Process.Capabilities.Permitted = []string{}
+ g.spec.Process.Capabilities.Ambient = []string{}
+}
+
+// AddProcessCapability adds a process capability into g.spec.Process.Capabilities.
+func (g *Generator) AddProcessCapability(c string) error {
+ cp := strings.ToUpper(c)
+ if err := validate.CapValid(cp, g.HostSpecific); err != nil {
+ return err
+ }
+
+ g.initSpecProcessCapabilities()
+
+ var foundBounding bool
+ for _, cap := range g.spec.Process.Capabilities.Bounding {
+ if strings.ToUpper(cap) == cp {
+ foundBounding = true
+ break
+ }
+ }
+ if !foundBounding {
+ g.spec.Process.Capabilities.Bounding = append(g.spec.Process.Capabilities.Bounding, cp)
+ }
+
+ var foundEffective bool
+ for _, cap := range g.spec.Process.Capabilities.Effective {
+ if strings.ToUpper(cap) == cp {
+ foundEffective = true
+ break
+ }
+ }
+ if !foundEffective {
+ g.spec.Process.Capabilities.Effective = append(g.spec.Process.Capabilities.Effective, cp)
+ }
+
+ var foundInheritable bool
+ for _, cap := range g.spec.Process.Capabilities.Inheritable {
+ if strings.ToUpper(cap) == cp {
+ foundInheritable = true
+ break
+ }
+ }
+ if !foundInheritable {
+ g.spec.Process.Capabilities.Inheritable = append(g.spec.Process.Capabilities.Inheritable, cp)
+ }
+
+ var foundPermitted bool
+ for _, cap := range g.spec.Process.Capabilities.Permitted {
+ if strings.ToUpper(cap) == cp {
+ foundPermitted = true
+ break
+ }
+ }
+ if !foundPermitted {
+ g.spec.Process.Capabilities.Permitted = append(g.spec.Process.Capabilities.Permitted, cp)
+ }
+
+ var foundAmbient bool
+ for _, cap := range g.spec.Process.Capabilities.Ambient {
+ if strings.ToUpper(cap) == cp {
+ foundAmbient = true
+ break
+ }
+ }
+ if !foundAmbient {
+ g.spec.Process.Capabilities.Ambient = append(g.spec.Process.Capabilities.Ambient, cp)
+ }
+
+ return nil
+}
+
+// DropProcessCapability drops a process capability from g.spec.Process.Capabilities.
+func (g *Generator) DropProcessCapability(c string) error {
+ cp := strings.ToUpper(c)
+ if err := validate.CapValid(cp, g.HostSpecific); err != nil {
+ return err
+ }
+
+ g.initSpecProcessCapabilities()
+
+ // we don't care about order...and this is way faster...
+ removeFunc := func(s []string, i int) []string {
+ s[i] = s[len(s)-1]
+ return s[:len(s)-1]
+ }
+
+ for i, cap := range g.spec.Process.Capabilities.Bounding {
+ if strings.ToUpper(cap) == cp {
+ g.spec.Process.Capabilities.Bounding = removeFunc(g.spec.Process.Capabilities.Bounding, i)
+ }
+ }
+
+ for i, cap := range g.spec.Process.Capabilities.Effective {
+ if strings.ToUpper(cap) == cp {
+ g.spec.Process.Capabilities.Effective = removeFunc(g.spec.Process.Capabilities.Effective, i)
+ }
+ }
+
+ for i, cap := range g.spec.Process.Capabilities.Inheritable {
+ if strings.ToUpper(cap) == cp {
+ g.spec.Process.Capabilities.Inheritable = removeFunc(g.spec.Process.Capabilities.Inheritable, i)
+ }
+ }
+
+ for i, cap := range g.spec.Process.Capabilities.Permitted {
+ if strings.ToUpper(cap) == cp {
+ g.spec.Process.Capabilities.Permitted = removeFunc(g.spec.Process.Capabilities.Permitted, i)
+ }
+ }
+
+ for i, cap := range g.spec.Process.Capabilities.Ambient {
+ if strings.ToUpper(cap) == cp {
+ g.spec.Process.Capabilities.Ambient = removeFunc(g.spec.Process.Capabilities.Ambient, i)
+ }
+ }
+
+ return nil
+}
+
+func mapStrToNamespace(ns string, path string) (rspec.LinuxNamespace, error) {
+ switch ns {
+ case "network":
+ return rspec.LinuxNamespace{Type: rspec.NetworkNamespace, Path: path}, nil
+ case "pid":
+ return rspec.LinuxNamespace{Type: rspec.PIDNamespace, Path: path}, nil
+ case "mount":
+ return rspec.LinuxNamespace{Type: rspec.MountNamespace, Path: path}, nil
+ case "ipc":
+ return rspec.LinuxNamespace{Type: rspec.IPCNamespace, Path: path}, nil
+ case "uts":
+ return rspec.LinuxNamespace{Type: rspec.UTSNamespace, Path: path}, nil
+ case "user":
+ return rspec.LinuxNamespace{Type: rspec.UserNamespace, Path: path}, nil
+ case "cgroup":
+ return rspec.LinuxNamespace{Type: rspec.CgroupNamespace, Path: path}, nil
+ default:
+ return rspec.LinuxNamespace{}, fmt.Errorf("unrecognized namespace %q", ns)
+ }
+}
+
+// ClearLinuxNamespaces clear g.spec.Linux.Namespaces.
+func (g *Generator) ClearLinuxNamespaces() {
+ if g.spec == nil || g.spec.Linux == nil {
+ return
+ }
+ g.spec.Linux.Namespaces = []rspec.LinuxNamespace{}
+}
+
+// AddOrReplaceLinuxNamespace adds or replaces a namespace inside
+// g.spec.Linux.Namespaces.
+func (g *Generator) AddOrReplaceLinuxNamespace(ns string, path string) error {
+ namespace, err := mapStrToNamespace(ns, path)
+ if err != nil {
+ return err
+ }
+
+ g.initSpecLinux()
+ for i, ns := range g.spec.Linux.Namespaces {
+ if ns.Type == namespace.Type {
+ g.spec.Linux.Namespaces[i] = namespace
+ return nil
+ }
+ }
+ g.spec.Linux.Namespaces = append(g.spec.Linux.Namespaces, namespace)
+ return nil
+}
+
+// RemoveLinuxNamespace removes a namespace from g.spec.Linux.Namespaces.
+func (g *Generator) RemoveLinuxNamespace(ns string) error {
+ namespace, err := mapStrToNamespace(ns, "")
+ if err != nil {
+ return err
+ }
+
+ if g.spec == nil || g.spec.Linux == nil {
+ return nil
+ }
+ for i, ns := range g.spec.Linux.Namespaces {
+ if ns.Type == namespace.Type {
+ g.spec.Linux.Namespaces = append(g.spec.Linux.Namespaces[:i], g.spec.Linux.Namespaces[i+1:]...)
+ return nil
+ }
+ }
+ return nil
+}
+
+// AddDevice - add a device into g.spec.Linux.Devices
+func (g *Generator) AddDevice(device rspec.LinuxDevice) {
+ g.initSpecLinux()
+
+ for i, dev := range g.spec.Linux.Devices {
+ if dev.Path == device.Path {
+ g.spec.Linux.Devices[i] = device
+ return
+ }
+ if dev.Type == device.Type && dev.Major == device.Major && dev.Minor == device.Minor {
+ fmt.Fprintln(os.Stderr, "WARNING: The same type, major and minor should not be used for multiple devices.")
+ }
+ }
+
+ g.spec.Linux.Devices = append(g.spec.Linux.Devices, device)
+}
+
+// RemoveDevice remove a device from g.spec.Linux.Devices
+func (g *Generator) RemoveDevice(path string) error {
+ if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Devices == nil {
+ return nil
+ }
+
+ for i, device := range g.spec.Linux.Devices {
+ if device.Path == path {
+ g.spec.Linux.Devices = append(g.spec.Linux.Devices[:i], g.spec.Linux.Devices[i+1:]...)
+ return nil
+ }
+ }
+ return nil
+}
+
+// ClearLinuxDevices clears g.spec.Linux.Devices
+func (g *Generator) ClearLinuxDevices() {
+ if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Devices == nil {
+ return
+ }
+
+ g.spec.Linux.Devices = []rspec.LinuxDevice{}
+}
+
+// strPtr returns the pointer pointing to the string s.
+func strPtr(s string) *string { return &s }
+
+// SetSyscallAction adds rules for syscalls with the specified action
+func (g *Generator) SetSyscallAction(arguments seccomp.SyscallOpts) error {
+ g.initSpecLinuxSeccomp()
+ return seccomp.ParseSyscallFlag(arguments, g.spec.Linux.Seccomp)
+}
+
+// SetDefaultSeccompAction sets the default action for all syscalls not defined
+// and then removes any syscall rules with this action already specified.
+func (g *Generator) SetDefaultSeccompAction(action string) error {
+ g.initSpecLinuxSeccomp()
+ return seccomp.ParseDefaultAction(action, g.spec.Linux.Seccomp)
+}
+
+// SetDefaultSeccompActionForce only sets the default action for all syscalls not defined
+func (g *Generator) SetDefaultSeccompActionForce(action string) error {
+ g.initSpecLinuxSeccomp()
+ return seccomp.ParseDefaultActionForce(action, g.spec.Linux.Seccomp)
+}
+
+// SetSeccompArchitecture sets the supported seccomp architectures
+func (g *Generator) SetSeccompArchitecture(architecture string) error {
+ g.initSpecLinuxSeccomp()
+ return seccomp.ParseArchitectureFlag(architecture, g.spec.Linux.Seccomp)
+}
+
+// RemoveSeccompRule removes rules for any specified syscalls
+func (g *Generator) RemoveSeccompRule(arguments string) error {
+ g.initSpecLinuxSeccomp()
+ return seccomp.RemoveAction(arguments, g.spec.Linux.Seccomp)
+}
+
+// RemoveAllSeccompRules removes all syscall rules
+func (g *Generator) RemoveAllSeccompRules() error {
+ g.initSpecLinuxSeccomp()
+ return seccomp.RemoveAllSeccompRules(g.spec.Linux.Seccomp)
+}
+
+// AddLinuxMaskedPaths adds masked paths into g.spec.Linux.MaskedPaths.
+func (g *Generator) AddLinuxMaskedPaths(path string) {
+ g.initSpecLinux()
+ g.spec.Linux.MaskedPaths = append(g.spec.Linux.MaskedPaths, path)
+}
+
+// AddLinuxReadonlyPaths adds readonly paths into g.spec.Linux.MaskedPaths.
+func (g *Generator) AddLinuxReadonlyPaths(path string) {
+ g.initSpecLinux()
+ g.spec.Linux.ReadonlyPaths = append(g.spec.Linux.ReadonlyPaths, path)
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go
new file mode 100644
index 000000000..eade5718e
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/consts.go
@@ -0,0 +1,12 @@
+package seccomp
+
+const (
+ seccompOverwrite = "overwrite"
+ seccompAppend = "append"
+ nothing = "nothing"
+ kill = "kill"
+ trap = "trap"
+ trace = "trace"
+ allow = "allow"
+ errno = "errno"
+)
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go
new file mode 100644
index 000000000..25daf0752
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_action.go
@@ -0,0 +1,135 @@
+package seccomp
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// SyscallOpts contain options for parsing syscall rules
+type SyscallOpts struct {
+ Action string
+ Syscall string
+ Index string
+ Value string
+ ValueTwo string
+ Operator string
+}
+
+// ParseSyscallFlag takes a SyscallOpts struct and the seccomp configuration
+// and sets the new syscall rule accordingly
+func ParseSyscallFlag(args SyscallOpts, config *rspec.LinuxSeccomp) error {
+ var arguments []string
+ if args.Index != "" && args.Value != "" && args.ValueTwo != "" && args.Operator != "" {
+ arguments = []string{args.Action, args.Syscall, args.Index, args.Value,
+ args.ValueTwo, args.Operator}
+ } else {
+ arguments = []string{args.Action, args.Syscall}
+ }
+
+ action, _ := parseAction(arguments[0])
+ if action == config.DefaultAction && args.argsAreEmpty() {
+ // default already set, no need to make changes
+ return nil
+ }
+
+ var newSyscall rspec.LinuxSyscall
+ numOfArgs := len(arguments)
+ if numOfArgs == 6 || numOfArgs == 2 {
+ argStruct, err := parseArguments(arguments[1:])
+ if err != nil {
+ return err
+ }
+ newSyscall = newSyscallStruct(arguments[1], action, argStruct)
+ } else {
+ return fmt.Errorf("incorrect number of arguments to ParseSyscall: %d", numOfArgs)
+ }
+
+ descison, err := decideCourseOfAction(&newSyscall, config.Syscalls)
+ if err != nil {
+ return err
+ }
+ delimDescison := strings.Split(descison, ":")
+
+ if delimDescison[0] == seccompAppend {
+ config.Syscalls = append(config.Syscalls, newSyscall)
+ }
+
+ if delimDescison[0] == seccompOverwrite {
+ indexForOverwrite, err := strconv.ParseInt(delimDescison[1], 10, 32)
+ if err != nil {
+ return err
+ }
+ config.Syscalls[indexForOverwrite] = newSyscall
+ }
+
+ return nil
+}
+
+var actions = map[string]rspec.LinuxSeccompAction{
+ "allow": rspec.ActAllow,
+ "errno": rspec.ActErrno,
+ "kill": rspec.ActKill,
+ "trace": rspec.ActTrace,
+ "trap": rspec.ActTrap,
+}
+
+// Take passed action, return the SCMP_ACT_<ACTION> version of it
+func parseAction(action string) (rspec.LinuxSeccompAction, error) {
+ a, ok := actions[action]
+ if !ok {
+ return "", fmt.Errorf("unrecognized action: %s", action)
+ }
+ return a, nil
+}
+
+// ParseDefaultAction sets the default action of the seccomp configuration
+// and then removes any rules that were already specified with this action
+func ParseDefaultAction(action string, config *rspec.LinuxSeccomp) error {
+ if action == "" {
+ return nil
+ }
+
+ defaultAction, err := parseAction(action)
+ if err != nil {
+ return err
+ }
+ config.DefaultAction = defaultAction
+ err = RemoveAllMatchingRules(config, defaultAction)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// ParseDefaultActionForce simply sets the default action of the seccomp configuration
+func ParseDefaultActionForce(action string, config *rspec.LinuxSeccomp) error {
+ if action == "" {
+ return nil
+ }
+
+ defaultAction, err := parseAction(action)
+ if err != nil {
+ return err
+ }
+ config.DefaultAction = defaultAction
+ return nil
+}
+
+func newSyscallStruct(name string, action rspec.LinuxSeccompAction, args []rspec.LinuxSeccompArg) rspec.LinuxSyscall {
+ syscallStruct := rspec.LinuxSyscall{
+ Names: []string{name},
+ Action: action,
+ Args: args,
+ }
+ return syscallStruct
+}
+
+func (s SyscallOpts) argsAreEmpty() bool {
+ return (s.Index == "" &&
+ s.Value == "" &&
+ s.ValueTwo == "" &&
+ s.Operator == "")
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go
new file mode 100644
index 000000000..9b2bdfd2f
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_architecture.go
@@ -0,0 +1,55 @@
+package seccomp
+
+import (
+ "fmt"
+
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// ParseArchitectureFlag takes the raw string passed with the --arch flag, parses it
+// and updates the Seccomp config accordingly
+func ParseArchitectureFlag(architectureArg string, config *rspec.LinuxSeccomp) error {
+ correctedArch, err := parseArch(architectureArg)
+ if err != nil {
+ return err
+ }
+
+ shouldAppend := true
+ for _, alreadySpecified := range config.Architectures {
+ if correctedArch == alreadySpecified {
+ shouldAppend = false
+ }
+ }
+ if shouldAppend {
+ config.Architectures = append(config.Architectures, correctedArch)
+ }
+ return nil
+}
+
+func parseArch(arch string) (rspec.Arch, error) {
+ arches := map[string]rspec.Arch{
+ "x86": rspec.ArchX86,
+ "amd64": rspec.ArchX86_64,
+ "x32": rspec.ArchX32,
+ "arm": rspec.ArchARM,
+ "arm64": rspec.ArchAARCH64,
+ "mips": rspec.ArchMIPS,
+ "mips64": rspec.ArchMIPS64,
+ "mips64n32": rspec.ArchMIPS64N32,
+ "mipsel": rspec.ArchMIPSEL,
+ "mipsel64": rspec.ArchMIPSEL64,
+ "mipsel64n32": rspec.ArchMIPSEL64N32,
+ "parisc": rspec.ArchPARISC,
+ "parisc64": rspec.ArchPARISC64,
+ "ppc": rspec.ArchPPC,
+ "ppc64": rspec.ArchPPC64,
+ "ppc64le": rspec.ArchPPC64LE,
+ "s390": rspec.ArchS390,
+ "s390x": rspec.ArchS390X,
+ }
+ a, ok := arches[arch]
+ if !ok {
+ return "", fmt.Errorf("unrecognized architecture: %s", arch)
+ }
+ return a, nil
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go
new file mode 100644
index 000000000..2b4c394e6
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_arguments.go
@@ -0,0 +1,73 @@
+package seccomp
+
+import (
+ "fmt"
+ "strconv"
+
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// parseArguments takes a list of arguments (delimArgs). It parses and fills out
+// the argument information and returns a slice of arg structs
+func parseArguments(delimArgs []string) ([]rspec.LinuxSeccompArg, error) {
+ nilArgSlice := []rspec.LinuxSeccompArg{}
+ numberOfArgs := len(delimArgs)
+
+ // No parameters passed with syscall
+ if numberOfArgs == 1 {
+ return nilArgSlice, nil
+ }
+
+ // Correct number of parameters passed with syscall
+ if numberOfArgs == 5 {
+ syscallIndex, err := strconv.ParseUint(delimArgs[1], 10, 0)
+ if err != nil {
+ return nilArgSlice, err
+ }
+
+ syscallValue, err := strconv.ParseUint(delimArgs[2], 10, 64)
+ if err != nil {
+ return nilArgSlice, err
+ }
+
+ syscallValueTwo, err := strconv.ParseUint(delimArgs[3], 10, 64)
+ if err != nil {
+ return nilArgSlice, err
+ }
+
+ syscallOp, err := parseOperator(delimArgs[4])
+ if err != nil {
+ return nilArgSlice, err
+ }
+
+ argStruct := rspec.LinuxSeccompArg{
+ Index: uint(syscallIndex),
+ Value: syscallValue,
+ ValueTwo: syscallValueTwo,
+ Op: syscallOp,
+ }
+
+ argSlice := []rspec.LinuxSeccompArg{}
+ argSlice = append(argSlice, argStruct)
+ return argSlice, nil
+ }
+
+ return nilArgSlice, fmt.Errorf("incorrect number of arguments passed with syscall: %d", numberOfArgs)
+}
+
+func parseOperator(operator string) (rspec.LinuxSeccompOperator, error) {
+ operators := map[string]rspec.LinuxSeccompOperator{
+ "NE": rspec.OpNotEqual,
+ "LT": rspec.OpLessThan,
+ "LE": rspec.OpLessEqual,
+ "EQ": rspec.OpEqualTo,
+ "GE": rspec.OpGreaterEqual,
+ "GT": rspec.OpGreaterThan,
+ "ME": rspec.OpMaskedEqual,
+ }
+ o, ok := operators[operator]
+ if !ok {
+ return "", fmt.Errorf("unrecognized operator: %s", operator)
+ }
+ return o, nil
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go
new file mode 100644
index 000000000..59537d49c
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/parse_remove.go
@@ -0,0 +1,52 @@
+package seccomp
+
+import (
+ "fmt"
+ "reflect"
+ "strings"
+
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// RemoveAction takes the argument string that was passed with the --remove flag,
+// parses it, and updates the Seccomp config accordingly
+func RemoveAction(arguments string, config *rspec.LinuxSeccomp) error {
+ if config == nil {
+ return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
+ }
+
+ syscallsToRemove := strings.Split(arguments, ",")
+
+ for counter, syscallStruct := range config.Syscalls {
+ if reflect.DeepEqual(syscallsToRemove, syscallStruct.Names) {
+ config.Syscalls = append(config.Syscalls[:counter], config.Syscalls[counter+1:]...)
+ }
+ }
+
+ return nil
+}
+
+// RemoveAllSeccompRules removes all seccomp syscall rules
+func RemoveAllSeccompRules(config *rspec.LinuxSeccomp) error {
+ if config == nil {
+ return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
+ }
+ newSyscallSlice := []rspec.LinuxSyscall{}
+ config.Syscalls = newSyscallSlice
+ return nil
+}
+
+// RemoveAllMatchingRules will remove any syscall rules that match the specified action
+func RemoveAllMatchingRules(config *rspec.LinuxSeccomp, seccompAction rspec.LinuxSeccompAction) error {
+ if config == nil {
+ return fmt.Errorf("Cannot remove action from nil Seccomp pointer")
+ }
+
+ for _, syscall := range config.Syscalls {
+ if reflect.DeepEqual(syscall.Action, seccompAction) {
+ RemoveAction(strings.Join(syscall.Names, ","), config)
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
new file mode 100644
index 000000000..35b12cd65
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/seccomp_default.go
@@ -0,0 +1,577 @@
+package seccomp
+
+import (
+ "runtime"
+ "syscall"
+
+ "github.com/opencontainers/runtime-spec/specs-go"
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func arches() []rspec.Arch {
+ native := runtime.GOARCH
+
+ switch native {
+ case "amd64":
+ return []rspec.Arch{rspec.ArchX86_64, rspec.ArchX86, rspec.ArchX32}
+ case "arm64":
+ return []rspec.Arch{rspec.ArchARM, rspec.ArchAARCH64}
+ case "mips64":
+ return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32}
+ case "mips64n32":
+ return []rspec.Arch{rspec.ArchMIPS, rspec.ArchMIPS64, rspec.ArchMIPS64N32}
+ case "mipsel64":
+ return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32}
+ case "mipsel64n32":
+ return []rspec.Arch{rspec.ArchMIPSEL, rspec.ArchMIPSEL64, rspec.ArchMIPSEL64N32}
+ case "s390x":
+ return []rspec.Arch{rspec.ArchS390, rspec.ArchS390X}
+ default:
+ return []rspec.Arch{}
+ }
+}
+
+// DefaultProfile defines the whitelist for the default seccomp profile.
+func DefaultProfile(rs *specs.Spec) *rspec.LinuxSeccomp {
+
+ syscalls := []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "accept",
+ "accept4",
+ "access",
+ "alarm",
+ "bind",
+ "brk",
+ "capget",
+ "capset",
+ "chdir",
+ "chmod",
+ "chown",
+ "chown32",
+ "clock_getres",
+ "clock_gettime",
+ "clock_nanosleep",
+ "close",
+ "connect",
+ "copy_file_range",
+ "creat",
+ "dup",
+ "dup2",
+ "dup3",
+ "epoll_create",
+ "epoll_create1",
+ "epoll_ctl",
+ "epoll_ctl_old",
+ "epoll_pwait",
+ "epoll_wait",
+ "epoll_wait_old",
+ "eventfd",
+ "eventfd2",
+ "execve",
+ "execveat",
+ "exit",
+ "exit_group",
+ "faccessat",
+ "fadvise64",
+ "fadvise64_64",
+ "fallocate",
+ "fanotify_mark",
+ "fchdir",
+ "fchmod",
+ "fchmodat",
+ "fchown",
+ "fchown32",
+ "fchownat",
+ "fcntl",
+ "fcntl64",
+ "fdatasync",
+ "fgetxattr",
+ "flistxattr",
+ "flock",
+ "fork",
+ "fremovexattr",
+ "fsetxattr",
+ "fstat",
+ "fstat64",
+ "fstatat64",
+ "fstatfs",
+ "fstatfs64",
+ "fsync",
+ "ftruncate",
+ "ftruncate64",
+ "futex",
+ "futimesat",
+ "getcpu",
+ "getcwd",
+ "getdents",
+ "getdents64",
+ "getegid",
+ "getegid32",
+ "geteuid",
+ "geteuid32",
+ "getgid",
+ "getgid32",
+ "getgroups",
+ "getgroups32",
+ "getitimer",
+ "getpeername",
+ "getpgid",
+ "getpgrp",
+ "getpid",
+ "getppid",
+ "getpriority",
+ "getrandom",
+ "getresgid",
+ "getresgid32",
+ "getresuid",
+ "getresuid32",
+ "getrlimit",
+ "get_robust_list",
+ "getrusage",
+ "getsid",
+ "getsockname",
+ "getsockopt",
+ "get_thread_area",
+ "gettid",
+ "gettimeofday",
+ "getuid",
+ "getuid32",
+ "getxattr",
+ "inotify_add_watch",
+ "inotify_init",
+ "inotify_init1",
+ "inotify_rm_watch",
+ "io_cancel",
+ "ioctl",
+ "io_destroy",
+ "io_getevents",
+ "ioprio_get",
+ "ioprio_set",
+ "io_setup",
+ "io_submit",
+ "ipc",
+ "kill",
+ "lchown",
+ "lchown32",
+ "lgetxattr",
+ "link",
+ "linkat",
+ "listen",
+ "listxattr",
+ "llistxattr",
+ "_llseek",
+ "lremovexattr",
+ "lseek",
+ "lsetxattr",
+ "lstat",
+ "lstat64",
+ "madvise",
+ "memfd_create",
+ "mincore",
+ "mkdir",
+ "mkdirat",
+ "mknod",
+ "mknodat",
+ "mlock",
+ "mlock2",
+ "mlockall",
+ "mmap",
+ "mmap2",
+ "mprotect",
+ "mq_getsetattr",
+ "mq_notify",
+ "mq_open",
+ "mq_timedreceive",
+ "mq_timedsend",
+ "mq_unlink",
+ "mremap",
+ "msgctl",
+ "msgget",
+ "msgrcv",
+ "msgsnd",
+ "msync",
+ "munlock",
+ "munlockall",
+ "munmap",
+ "nanosleep",
+ "newfstatat",
+ "_newselect",
+ "open",
+ "openat",
+ "pause",
+ "pipe",
+ "pipe2",
+ "poll",
+ "ppoll",
+ "prctl",
+ "pread64",
+ "preadv",
+ "prlimit64",
+ "pselect6",
+ "pwrite64",
+ "pwritev",
+ "read",
+ "readahead",
+ "readlink",
+ "readlinkat",
+ "readv",
+ "recv",
+ "recvfrom",
+ "recvmmsg",
+ "recvmsg",
+ "remap_file_pages",
+ "removexattr",
+ "rename",
+ "renameat",
+ "renameat2",
+ "restart_syscall",
+ "rmdir",
+ "rt_sigaction",
+ "rt_sigpending",
+ "rt_sigprocmask",
+ "rt_sigqueueinfo",
+ "rt_sigreturn",
+ "rt_sigsuspend",
+ "rt_sigtimedwait",
+ "rt_tgsigqueueinfo",
+ "sched_getaffinity",
+ "sched_getattr",
+ "sched_getparam",
+ "sched_get_priority_max",
+ "sched_get_priority_min",
+ "sched_getscheduler",
+ "sched_rr_get_interval",
+ "sched_setaffinity",
+ "sched_setattr",
+ "sched_setparam",
+ "sched_setscheduler",
+ "sched_yield",
+ "seccomp",
+ "select",
+ "semctl",
+ "semget",
+ "semop",
+ "semtimedop",
+ "send",
+ "sendfile",
+ "sendfile64",
+ "sendmmsg",
+ "sendmsg",
+ "sendto",
+ "setfsgid",
+ "setfsgid32",
+ "setfsuid",
+ "setfsuid32",
+ "setgid",
+ "setgid32",
+ "setgroups",
+ "setgroups32",
+ "setitimer",
+ "setpgid",
+ "setpriority",
+ "setregid",
+ "setregid32",
+ "setresgid",
+ "setresgid32",
+ "setresuid",
+ "setresuid32",
+ "setreuid",
+ "setreuid32",
+ "setrlimit",
+ "set_robust_list",
+ "setsid",
+ "setsockopt",
+ "set_thread_area",
+ "set_tid_address",
+ "setuid",
+ "setuid32",
+ "setxattr",
+ "shmat",
+ "shmctl",
+ "shmdt",
+ "shmget",
+ "shutdown",
+ "sigaltstack",
+ "signalfd",
+ "signalfd4",
+ "sigreturn",
+ "socket",
+ "socketcall",
+ "socketpair",
+ "splice",
+ "stat",
+ "stat64",
+ "statfs",
+ "statfs64",
+ "symlink",
+ "symlinkat",
+ "sync",
+ "sync_file_range",
+ "syncfs",
+ "sysinfo",
+ "syslog",
+ "tee",
+ "tgkill",
+ "time",
+ "timer_create",
+ "timer_delete",
+ "timerfd_create",
+ "timerfd_gettime",
+ "timerfd_settime",
+ "timer_getoverrun",
+ "timer_gettime",
+ "timer_settime",
+ "times",
+ "tkill",
+ "truncate",
+ "truncate64",
+ "ugetrlimit",
+ "umask",
+ "uname",
+ "unlink",
+ "unlinkat",
+ "utime",
+ "utimensat",
+ "utimes",
+ "vfork",
+ "vmsplice",
+ "wait4",
+ "waitid",
+ "waitpid",
+ "write",
+ "writev",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ {
+ Names: []string{"personality"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{
+ {
+ Index: 0,
+ Value: 0x0,
+ Op: rspec.OpEqualTo,
+ },
+ {
+ Index: 0,
+ Value: 0x0008,
+ Op: rspec.OpEqualTo,
+ },
+ {
+ Index: 0,
+ Value: 0xffffffff,
+ Op: rspec.OpEqualTo,
+ },
+ },
+ },
+ }
+ var sysCloneFlagsIndex uint
+
+ capSysAdmin := false
+ caps := make(map[string]bool)
+
+ for _, cap := range rs.Process.Capabilities.Bounding {
+ caps[cap] = true
+ }
+ for _, cap := range rs.Process.Capabilities.Effective {
+ caps[cap] = true
+ }
+ for _, cap := range rs.Process.Capabilities.Inheritable {
+ caps[cap] = true
+ }
+ for _, cap := range rs.Process.Capabilities.Permitted {
+ caps[cap] = true
+ }
+ for _, cap := range rs.Process.Capabilities.Ambient {
+ caps[cap] = true
+ }
+
+ for cap := range caps {
+ switch cap {
+ case "CAP_DAC_READ_SEARCH":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"open_by_handle_at"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_ADMIN":
+ capSysAdmin = true
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "bpf",
+ "clone",
+ "fanotify_init",
+ "lookup_dcookie",
+ "mount",
+ "name_to_handle_at",
+ "perf_event_open",
+ "setdomainname",
+ "sethostname",
+ "setns",
+ "umount",
+ "umount2",
+ "unshare",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_BOOT":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"reboot"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_CHROOT":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"chroot"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_MODULE":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "delete_module",
+ "init_module",
+ "finit_module",
+ "query_module",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_PACCT":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"acct"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_PTRACE":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "kcmp",
+ "process_vm_readv",
+ "process_vm_writev",
+ "ptrace",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_RAWIO":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "iopl",
+ "ioperm",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_TIME":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "settimeofday",
+ "stime",
+ "adjtimex",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "CAP_SYS_TTY_CONFIG":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"vhangup"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ }
+ }
+
+ if !capSysAdmin {
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"clone"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{
+ {
+ Index: sysCloneFlagsIndex,
+ Value: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWUSER | syscall.CLONE_NEWPID | syscall.CLONE_NEWNET,
+ ValueTwo: 0,
+ Op: rspec.OpMaskedEqual,
+ },
+ },
+ },
+ }...)
+
+ }
+
+ arch := runtime.GOARCH
+ switch arch {
+ case "arm", "arm64":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "breakpoint",
+ "cacheflush",
+ "set_tls",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "amd64", "x32":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"arch_prctl"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ fallthrough
+ case "x86":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{"modify_ldt"},
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ case "s390", "s390x":
+ syscalls = append(syscalls, []rspec.LinuxSyscall{
+ {
+ Names: []string{
+ "s390_pci_mmio_read",
+ "s390_pci_mmio_write",
+ "s390_runtime_instr",
+ },
+ Action: rspec.ActAllow,
+ Args: []rspec.LinuxSeccompArg{},
+ },
+ }...)
+ /* Flags parameter of the clone syscall is the 2nd on s390 */
+ }
+
+ return &rspec.LinuxSeccomp{
+ DefaultAction: rspec.ActErrno,
+ Architectures: arches(),
+ Syscalls: syscalls,
+ }
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go
new file mode 100644
index 000000000..dbf2aec1c
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/seccomp/syscall_compare.go
@@ -0,0 +1,140 @@
+package seccomp
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// Determine if a new syscall rule should be appended, overwrite an existing rule
+// or if no action should be taken at all
+func decideCourseOfAction(newSyscall *rspec.LinuxSyscall, syscalls []rspec.LinuxSyscall) (string, error) {
+ ruleForSyscallAlreadyExists := false
+
+ var sliceOfDeterminedActions []string
+ for i, syscall := range syscalls {
+ if sameName(&syscall, newSyscall) {
+ ruleForSyscallAlreadyExists = true
+
+ if identical(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing)
+ }
+
+ if sameAction(newSyscall, &syscall) {
+ if bothHaveArgs(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
+ }
+ if onlyOneHasArgs(newSyscall, &syscall) {
+ if firstParamOnlyHasArgs(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i))
+ } else {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, nothing)
+ }
+ }
+ }
+
+ if !sameAction(newSyscall, &syscall) {
+ if bothHaveArgs(newSyscall, &syscall) {
+ if sameArgs(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i))
+ }
+ if !sameArgs(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
+ }
+ }
+ if onlyOneHasArgs(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
+ }
+ if neitherHasArgs(newSyscall, &syscall) {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, "overwrite:"+strconv.Itoa(i))
+ }
+ }
+ }
+ }
+
+ if !ruleForSyscallAlreadyExists {
+ sliceOfDeterminedActions = append(sliceOfDeterminedActions, seccompAppend)
+ }
+
+ // Nothing has highest priority
+ for _, determinedAction := range sliceOfDeterminedActions {
+ if determinedAction == nothing {
+ return determinedAction, nil
+ }
+ }
+
+ // Overwrite has second highest priority
+ for _, determinedAction := range sliceOfDeterminedActions {
+ if strings.Contains(determinedAction, seccompOverwrite) {
+ return determinedAction, nil
+ }
+ }
+
+ // Append has the lowest priority
+ for _, determinedAction := range sliceOfDeterminedActions {
+ if determinedAction == seccompAppend {
+ return determinedAction, nil
+ }
+ }
+
+ return "", fmt.Errorf("Trouble determining action: %s", sliceOfDeterminedActions)
+}
+
+func hasArguments(config *rspec.LinuxSyscall) bool {
+ nilSyscall := new(rspec.LinuxSyscall)
+ return !sameArgs(nilSyscall, config)
+}
+
+func identical(config1, config2 *rspec.LinuxSyscall) bool {
+ return reflect.DeepEqual(config1, config2)
+}
+
+func identicalExceptAction(config1, config2 *rspec.LinuxSyscall) bool {
+ samename := sameName(config1, config2)
+ sameAction := sameAction(config1, config2)
+ sameArgs := sameArgs(config1, config2)
+
+ return samename && !sameAction && sameArgs
+}
+
+func identicalExceptArgs(config1, config2 *rspec.LinuxSyscall) bool {
+ samename := sameName(config1, config2)
+ sameAction := sameAction(config1, config2)
+ sameArgs := sameArgs(config1, config2)
+
+ return samename && sameAction && !sameArgs
+}
+
+func sameName(config1, config2 *rspec.LinuxSyscall) bool {
+ return reflect.DeepEqual(config1.Names, config2.Names)
+}
+
+func sameAction(config1, config2 *rspec.LinuxSyscall) bool {
+ return config1.Action == config2.Action
+}
+
+func sameArgs(config1, config2 *rspec.LinuxSyscall) bool {
+ return reflect.DeepEqual(config1.Args, config2.Args)
+}
+
+func bothHaveArgs(config1, config2 *rspec.LinuxSyscall) bool {
+ return hasArguments(config1) && hasArguments(config2)
+}
+
+func onlyOneHasArgs(config1, config2 *rspec.LinuxSyscall) bool {
+ conf1 := hasArguments(config1)
+ conf2 := hasArguments(config2)
+
+ return (conf1 && !conf2) || (!conf1 && conf2)
+}
+
+func neitherHasArgs(config1, config2 *rspec.LinuxSyscall) bool {
+ return !hasArguments(config1) && !hasArguments(config2)
+}
+
+func firstParamOnlyHasArgs(config1, config2 *rspec.LinuxSyscall) bool {
+ return !hasArguments(config1) && hasArguments(config2)
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/generate/spec.go b/vendor/github.com/opencontainers/runtime-tools/generate/spec.go
new file mode 100644
index 000000000..519d25448
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/generate/spec.go
@@ -0,0 +1,109 @@
+package generate
+
+import (
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+func (g *Generator) initSpec() {
+ if g.spec == nil {
+ g.spec = &rspec.Spec{}
+ }
+}
+
+func (g *Generator) initSpecProcess() {
+ g.initSpec()
+ if g.spec.Process == nil {
+ g.spec.Process = &rspec.Process{}
+ }
+}
+
+func (g *Generator) initSpecProcessConsoleSize() {
+ g.initSpecProcess()
+ if g.spec.Process.ConsoleSize == nil {
+ g.spec.Process.ConsoleSize = &rspec.Box{}
+ }
+}
+
+func (g *Generator) initSpecProcessCapabilities() {
+ g.initSpecProcess()
+ if g.spec.Process.Capabilities == nil {
+ g.spec.Process.Capabilities = &rspec.LinuxCapabilities{}
+ }
+}
+
+func (g *Generator) initSpecRoot() {
+ g.initSpec()
+ if g.spec.Root == nil {
+ g.spec.Root = &rspec.Root{}
+ }
+}
+
+func (g *Generator) initSpecAnnotations() {
+ g.initSpec()
+ if g.spec.Annotations == nil {
+ g.spec.Annotations = make(map[string]string)
+ }
+}
+
+func (g *Generator) initSpecHooks() {
+ g.initSpec()
+ if g.spec.Hooks == nil {
+ g.spec.Hooks = &rspec.Hooks{}
+ }
+}
+
+func (g *Generator) initSpecLinux() {
+ g.initSpec()
+ if g.spec.Linux == nil {
+ g.spec.Linux = &rspec.Linux{}
+ }
+}
+
+func (g *Generator) initSpecLinuxSysctl() {
+ g.initSpecLinux()
+ if g.spec.Linux.Sysctl == nil {
+ g.spec.Linux.Sysctl = make(map[string]string)
+ }
+}
+
+func (g *Generator) initSpecLinuxSeccomp() {
+ g.initSpecLinux()
+ if g.spec.Linux.Seccomp == nil {
+ g.spec.Linux.Seccomp = &rspec.LinuxSeccomp{}
+ }
+}
+
+func (g *Generator) initSpecLinuxResources() {
+ g.initSpecLinux()
+ if g.spec.Linux.Resources == nil {
+ g.spec.Linux.Resources = &rspec.LinuxResources{}
+ }
+}
+
+func (g *Generator) initSpecLinuxResourcesCPU() {
+ g.initSpecLinuxResources()
+ if g.spec.Linux.Resources.CPU == nil {
+ g.spec.Linux.Resources.CPU = &rspec.LinuxCPU{}
+ }
+}
+
+func (g *Generator) initSpecLinuxResourcesMemory() {
+ g.initSpecLinuxResources()
+ if g.spec.Linux.Resources.Memory == nil {
+ g.spec.Linux.Resources.Memory = &rspec.LinuxMemory{}
+ }
+}
+
+func (g *Generator) initSpecLinuxResourcesNetwork() {
+ g.initSpecLinuxResources()
+ if g.spec.Linux.Resources.Network == nil {
+ g.spec.Linux.Resources.Network = &rspec.LinuxNetwork{}
+ }
+}
+
+func (g *Generator) initSpecLinuxResourcesPids() {
+ g.initSpecLinuxResources()
+ if g.spec.Linux.Resources.Pids == nil {
+ g.spec.Linux.Resources.Pids = &rspec.LinuxPids{}
+ }
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/specerror/error.go b/vendor/github.com/opencontainers/runtime-tools/specerror/error.go
new file mode 100644
index 000000000..c75bb6b14
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/specerror/error.go
@@ -0,0 +1,170 @@
+// Package specerror implements runtime-spec-specific tooling for
+// tracking RFC 2119 violations.
+package specerror
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/go-multierror"
+ rfc2119 "github.com/opencontainers/runtime-tools/error"
+)
+
+const referenceTemplate = "https://github.com/opencontainers/runtime-spec/blob/v%s/%s"
+
+// Code represents the spec violation, enumerating both
+// configuration violations and runtime violations.
+type Code int
+
+const (
+ // NonError represents that an input is not an error
+ NonError Code = iota
+ // NonRFCError represents that an error is not a rfc2119 error
+ NonRFCError
+
+ // ConfigFileExistence represents the error code of 'config.json' existence test
+ ConfigFileExistence
+ // ArtifactsInSingleDir represents the error code of artifacts place test
+ ArtifactsInSingleDir
+
+ // SpecVersion represents the error code of specfication version test
+ SpecVersion
+
+ // RootOnNonHyperV represents the error code of root setting test on non hyper-v containers
+ RootOnNonHyperV
+ // RootOnHyperV represents the error code of root setting test on hyper-v containers
+ RootOnHyperV
+ // PathFormatOnWindows represents the error code of the path format test on Window
+ PathFormatOnWindows
+ // PathName represents the error code of the path name test
+ PathName
+ // PathExistence represents the error code of the path existence test
+ PathExistence
+ // ReadonlyFilesystem represents the error code of readonly test
+ ReadonlyFilesystem
+ // ReadonlyOnWindows represents the error code of readonly setting test on Windows
+ ReadonlyOnWindows
+
+ // DefaultFilesystems represents the error code of default filesystems test
+ DefaultFilesystems
+
+ // CreateWithID represents the error code of 'create' lifecyle test with 'id' provided
+ CreateWithID
+ // CreateWithUniqueID represents the error code of 'create' lifecyle test with unique 'id' provided
+ CreateWithUniqueID
+ // CreateNewContainer represents the error code 'create' lifecyle test that creates new container
+ CreateNewContainer
+)
+
+type errorTemplate struct {
+ Level rfc2119.Level
+ Reference func(version string) (reference string, err error)
+}
+
+// Error represents a runtime-spec violation.
+type Error struct {
+ // Err holds the RFC 2119 violation.
+ Err rfc2119.Error
+
+ // Code is a matchable holds a Code
+ Code Code
+}
+
+var (
+ containerFormatRef = func(version string) (reference string, err error) {
+ return fmt.Sprintf(referenceTemplate, version, "bundle.md#container-format"), nil
+ }
+ specVersionRef = func(version string) (reference string, err error) {
+ return fmt.Sprintf(referenceTemplate, version, "config.md#specification-version"), nil
+ }
+ rootRef = func(version string) (reference string, err error) {
+ return fmt.Sprintf(referenceTemplate, version, "config.md#root"), nil
+ }
+ defaultFSRef = func(version string) (reference string, err error) {
+ return fmt.Sprintf(referenceTemplate, version, "config-linux.md#default-filesystems"), nil
+ }
+ runtimeCreateRef = func(version string) (reference string, err error) {
+ return fmt.Sprintf(referenceTemplate, version, "runtime.md#create"), nil
+ }
+)
+
+var ociErrors = map[Code]errorTemplate{
+ // Bundle.md
+ // Container Format
+ ConfigFileExistence: {Level: rfc2119.Must, Reference: containerFormatRef},
+ ArtifactsInSingleDir: {Level: rfc2119.Must, Reference: containerFormatRef},
+
+ // Config.md
+ // Specification Version
+ SpecVersion: {Level: rfc2119.Must, Reference: specVersionRef},
+ // Root
+ RootOnNonHyperV: {Level: rfc2119.Required, Reference: rootRef},
+ RootOnHyperV: {Level: rfc2119.Must, Reference: rootRef},
+ // TODO: add tests for 'PathFormatOnWindows'
+ PathFormatOnWindows: {Level: rfc2119.Must, Reference: rootRef},
+ PathName: {Level: rfc2119.Should, Reference: rootRef},
+ PathExistence: {Level: rfc2119.Must, Reference: rootRef},
+ ReadonlyFilesystem: {Level: rfc2119.Must, Reference: rootRef},
+ ReadonlyOnWindows: {Level: rfc2119.Must, Reference: rootRef},
+
+ // Config-Linux.md
+ // Default Filesystems
+ DefaultFilesystems: {Level: rfc2119.Should, Reference: defaultFSRef},
+
+ // Runtime.md
+ // Create
+ CreateWithID: {Level: rfc2119.Must, Reference: runtimeCreateRef},
+ CreateWithUniqueID: {Level: rfc2119.Must, Reference: runtimeCreateRef},
+ CreateNewContainer: {Level: rfc2119.Must, Reference: runtimeCreateRef},
+}
+
+// Error returns the error message with specification reference.
+func (err *Error) Error() string {
+ return err.Err.Error()
+}
+
+// NewError creates an Error referencing a spec violation. The error
+// can be cast to an *Error for extracting structured information
+// about the level of the violation and a reference to the violated
+// spec condition.
+//
+// A version string (for the version of the spec that was violated)
+// must be set to get a working URL.
+func NewError(code Code, err error, version string) error {
+ template := ociErrors[code]
+ reference, err2 := template.Reference(version)
+ if err2 != nil {
+ return err2
+ }
+ return &Error{
+ Err: rfc2119.Error{
+ Level: template.Level,
+ Reference: reference,
+ Err: err,
+ },
+ Code: code,
+ }
+}
+
+// FindError finds an error from a source error (multiple error) and
+// returns the error code if found.
+// If the source error is nil or empty, return NonError.
+// If the source error is not a multiple error, return NonRFCError.
+func FindError(err error, code Code) Code {
+ if err == nil {
+ return NonError
+ }
+
+ if merr, ok := err.(*multierror.Error); ok {
+ if merr.ErrorOrNil() == nil {
+ return NonError
+ }
+ for _, e := range merr.Errors {
+ if rfcErr, ok := e.(*Error); ok {
+ if rfcErr.Code == code {
+ return code
+ }
+ }
+ }
+ }
+ return NonRFCError
+}
diff --git a/vendor/github.com/opencontainers/runtime-tools/validate/validate.go b/vendor/github.com/opencontainers/runtime-tools/validate/validate.go
new file mode 100644
index 000000000..bbdb29c60
--- /dev/null
+++ b/vendor/github.com/opencontainers/runtime-tools/validate/validate.go
@@ -0,0 +1,1050 @@
+package validate
+
+import (
+ "bufio"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "path/filepath"
+ "reflect"
+ "regexp"
+ "runtime"
+ "strings"
+ "syscall"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/blang/semver"
+ "github.com/hashicorp/go-multierror"
+ rspec "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/sirupsen/logrus"
+ "github.com/syndtr/gocapability/capability"
+
+ "github.com/opencontainers/runtime-tools/specerror"
+)
+
+const specConfig = "config.json"
+
+var (
+ defaultRlimits = []string{
+ "RLIMIT_AS",
+ "RLIMIT_CORE",
+ "RLIMIT_CPU",
+ "RLIMIT_DATA",
+ "RLIMIT_FSIZE",
+ "RLIMIT_LOCKS",
+ "RLIMIT_MEMLOCK",
+ "RLIMIT_MSGQUEUE",
+ "RLIMIT_NICE",
+ "RLIMIT_NOFILE",
+ "RLIMIT_NPROC",
+ "RLIMIT_RSS",
+ "RLIMIT_RTPRIO",
+ "RLIMIT_RTTIME",
+ "RLIMIT_SIGPENDING",
+ "RLIMIT_STACK",
+ }
+)
+
+// Validator represents a validator for runtime bundle
+type Validator struct {
+ spec *rspec.Spec
+ bundlePath string
+ HostSpecific bool
+ platform string
+}
+
+// NewValidator creates a Validator
+func NewValidator(spec *rspec.Spec, bundlePath string, hostSpecific bool, platform string) Validator {
+ if hostSpecific && platform != runtime.GOOS {
+ platform = runtime.GOOS
+ }
+ return Validator{
+ spec: spec,
+ bundlePath: bundlePath,
+ HostSpecific: hostSpecific,
+ platform: platform,
+ }
+}
+
+// NewValidatorFromPath creates a Validator with specified bundle path
+func NewValidatorFromPath(bundlePath string, hostSpecific bool, platform string) (Validator, error) {
+ if hostSpecific && platform != runtime.GOOS {
+ platform = runtime.GOOS
+ }
+ if bundlePath == "" {
+ return Validator{}, fmt.Errorf("bundle path shouldn't be empty")
+ }
+
+ if _, err := os.Stat(bundlePath); err != nil {
+ return Validator{}, err
+ }
+
+ configPath := filepath.Join(bundlePath, specConfig)
+ content, err := ioutil.ReadFile(configPath)
+ if err != nil {
+ return Validator{}, specerror.NewError(specerror.ConfigFileExistence, err, rspec.Version)
+ }
+ if !utf8.Valid(content) {
+ return Validator{}, fmt.Errorf("%q is not encoded in UTF-8", configPath)
+ }
+ var spec rspec.Spec
+ if err = json.Unmarshal(content, &spec); err != nil {
+ return Validator{}, err
+ }
+
+ return NewValidator(&spec, bundlePath, hostSpecific, platform), nil
+}
+
+// CheckAll checks all parts of runtime bundle
+func (v *Validator) CheckAll() (errs error) {
+ errs = multierror.Append(errs, v.CheckPlatform())
+ errs = multierror.Append(errs, v.CheckRoot())
+ errs = multierror.Append(errs, v.CheckMandatoryFields())
+ errs = multierror.Append(errs, v.CheckSemVer())
+ errs = multierror.Append(errs, v.CheckMounts())
+ errs = multierror.Append(errs, v.CheckProcess())
+ errs = multierror.Append(errs, v.CheckHooks())
+ errs = multierror.Append(errs, v.CheckLinux())
+
+ return
+}
+
+// CheckRoot checks status of v.spec.Root
+func (v *Validator) CheckRoot() (errs error) {
+ logrus.Debugf("check root")
+
+ if v.platform == "windows" && v.spec.Windows != nil && v.spec.Windows.HyperV != nil {
+ if v.spec.Root != nil {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.RootOnHyperV, fmt.Errorf("for Hyper-V containers, Root must not be set"), rspec.Version))
+ return
+ }
+ return
+ } else if v.spec.Root == nil {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.RootOnNonHyperV, fmt.Errorf("for non-Hyper-V containers, Root must be set"), rspec.Version))
+ return
+ }
+
+ absBundlePath, err := filepath.Abs(v.bundlePath)
+ if err != nil {
+ errs = multierror.Append(errs, fmt.Errorf("unable to convert %q to an absolute path", v.bundlePath))
+ return
+ }
+
+ if filepath.Base(v.spec.Root.Path) != "rootfs" {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.PathName, fmt.Errorf("path name should be the conventional 'rootfs'"), rspec.Version))
+ }
+
+ var rootfsPath string
+ var absRootPath string
+ if filepath.IsAbs(v.spec.Root.Path) {
+ rootfsPath = v.spec.Root.Path
+ absRootPath = filepath.Clean(rootfsPath)
+ } else {
+ var err error
+ rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
+ absRootPath, err = filepath.Abs(rootfsPath)
+ if err != nil {
+ errs = multierror.Append(errs, fmt.Errorf("unable to convert %q to an absolute path", rootfsPath))
+ return
+ }
+ }
+
+ if fi, err := os.Stat(rootfsPath); err != nil {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.PathExistence, fmt.Errorf("cannot find the root path %q", rootfsPath), rspec.Version))
+ } else if !fi.IsDir() {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.PathExistence, fmt.Errorf("root.path %q is not a directory", rootfsPath), rspec.Version))
+ }
+
+ rootParent := filepath.Dir(absRootPath)
+ if absRootPath == string(filepath.Separator) || rootParent != absBundlePath {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.ArtifactsInSingleDir, fmt.Errorf("root.path is %q, but it MUST be a child of %q", v.spec.Root.Path, absBundlePath), rspec.Version))
+ }
+
+ if v.platform == "windows" {
+ if v.spec.Root.Readonly {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.ReadonlyOnWindows, fmt.Errorf("root.readonly field MUST be omitted or false when target platform is windows"), rspec.Version))
+ }
+ }
+
+ return
+}
+
+// CheckSemVer checks v.spec.Version
+func (v *Validator) CheckSemVer() (errs error) {
+ logrus.Debugf("check semver")
+
+ version := v.spec.Version
+ _, err := semver.Parse(version)
+ if err != nil {
+ errs = multierror.Append(errs,
+ specerror.NewError(specerror.SpecVersion, fmt.Errorf("%q is not valid SemVer: %s", version, err.Error()), rspec.Version))
+ }
+ if version != rspec.Version {
+ errs = multierror.Append(errs, fmt.Errorf("validate currently only handles version %s, but the supplied configuration targets %s", rspec.Version, version))
+ }
+
+ return
+}
+
+// CheckHooks check v.spec.Hooks
+func (v *Validator) CheckHooks() (errs error) {
+ logrus.Debugf("check hooks")
+
+ if v.spec.Hooks != nil {
+ errs = multierror.Append(errs, checkEventHooks("pre-start", v.spec.Hooks.Prestart, v.HostSpecific))
+ errs = multierror.Append(errs, checkEventHooks("post-start", v.spec.Hooks.Poststart, v.HostSpecific))
+ errs = multierror.Append(errs, checkEventHooks("post-stop", v.spec.Hooks.Poststop, v.HostSpecific))
+ }
+
+ return
+}
+
+func checkEventHooks(hookType string, hooks []rspec.Hook, hostSpecific bool) (errs error) {
+ for _, hook := range hooks {
+ if !filepath.IsAbs(hook.Path) {
+ errs = multierror.Append(errs, fmt.Errorf("the %s hook %v: is not absolute path", hookType, hook.Path))
+ }
+
+ if hostSpecific {
+ fi, err := os.Stat(hook.Path)
+ if err != nil {
+ errs = multierror.Append(errs, fmt.Errorf("cannot find %s hook: %v", hookType, hook.Path))
+ }
+ if fi.Mode()&0111 == 0 {
+ errs = multierror.Append(errs, fmt.Errorf("the %s hook %v: is not executable", hookType, hook.Path))
+ }
+ }
+
+ for _, env := range hook.Env {
+ if !envValid(env) {
+ errs = multierror.Append(errs, fmt.Errorf("env %q for hook %v is in the invalid form", env, hook.Path))
+ }
+ }
+ }
+
+ return
+}
+
+// CheckProcess checks v.spec.Process
+func (v *Validator) CheckProcess() (errs error) {
+ logrus.Debugf("check process")
+
+ if v.spec.Process == nil {
+ return
+ }
+
+ process := v.spec.Process
+ if !filepath.IsAbs(process.Cwd) {
+ errs = multierror.Append(errs, fmt.Errorf("cwd %q is not an absolute path", process.Cwd))
+ }
+
+ for _, env := range process.Env {
+ if !envValid(env) {
+ errs = multierror.Append(errs, fmt.Errorf("env %q should be in the form of 'key=value'. The left hand side must consist solely of letters, digits, and underscores '_'", env))
+ }
+ }
+
+ if len(process.Args) == 0 {
+ errs = multierror.Append(errs, fmt.Errorf("args must not be empty"))
+ } else {
+ if filepath.IsAbs(process.Args[0]) {
+ var rootfsPath string
+ if filepath.IsAbs(v.spec.Root.Path) {
+ rootfsPath = v.spec.Root.Path
+ } else {
+ rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
+ }
+ absPath := filepath.Join(rootfsPath, process.Args[0])
+ fileinfo, err := os.Stat(absPath)
+ if os.IsNotExist(err) {
+ logrus.Warnf("executable %q is not available in rootfs currently", process.Args[0])
+ } else if err != nil {
+ errs = multierror.Append(errs, err)
+ } else {
+ m := fileinfo.Mode()
+ if m.IsDir() || m&0111 == 0 {
+ errs = multierror.Append(errs, fmt.Errorf("arg %q is not executable", process.Args[0]))
+ }
+ }
+ }
+ }
+
+ if v.spec.Process.Capabilities != nil {
+ errs = multierror.Append(errs, v.CheckCapabilities())
+ }
+ errs = multierror.Append(errs, v.CheckRlimits())
+
+ if v.platform == "linux" {
+ if len(process.ApparmorProfile) > 0 {
+ profilePath := filepath.Join(v.bundlePath, v.spec.Root.Path, "/etc/apparmor.d", process.ApparmorProfile)
+ _, err := os.Stat(profilePath)
+ if err != nil {
+ errs = multierror.Append(errs, err)
+ }
+ }
+ }
+
+ return
+}
+
+// CheckCapabilities checks v.spec.Process.Capabilities
+func (v *Validator) CheckCapabilities() (errs error) {
+ process := v.spec.Process
+ if v.platform == "linux" {
+ var effective, permitted, inheritable, ambient bool
+ caps := make(map[string][]string)
+
+ for _, cap := range process.Capabilities.Bounding {
+ caps[cap] = append(caps[cap], "bounding")
+ }
+ for _, cap := range process.Capabilities.Effective {
+ caps[cap] = append(caps[cap], "effective")
+ }
+ for _, cap := range process.Capabilities.Inheritable {
+ caps[cap] = append(caps[cap], "inheritable")
+ }
+ for _, cap := range process.Capabilities.Permitted {
+ caps[cap] = append(caps[cap], "permitted")
+ }
+ for _, cap := range process.Capabilities.Ambient {
+ caps[cap] = append(caps[cap], "ambient")
+ }
+
+ for capability, owns := range caps {
+ if err := CapValid(capability, v.HostSpecific); err != nil {
+ errs = multierror.Append(errs, fmt.Errorf("capability %q is not valid, man capabilities(7)", capability))
+ }
+
+ effective, permitted, ambient, inheritable = false, false, false, false
+ for _, set := range owns {
+ if set == "effective" {
+ effective = true
+ continue
+ }
+ if set == "inheritable" {
+ inheritable = true
+ continue
+ }
+ if set == "permitted" {
+ permitted = true
+ continue
+ }
+ if set == "ambient" {
+ ambient = true
+ continue
+ }
+ }
+ if effective && !permitted {
+ errs = multierror.Append(errs, fmt.Errorf("effective capability %q is not allowed, as it's not permitted", capability))
+ }
+ if ambient && !(effective && inheritable) {
+ errs = multierror.Append(errs, fmt.Errorf("ambient capability %q is not allowed, as it's not permitted and inheribate", capability))
+ }
+ }
+ } else {
+ logrus.Warnf("process.capabilities validation not yet implemented for OS %q", v.platform)
+ }
+
+ return
+}
+
+// CheckRlimits checks v.spec.Process.Rlimits
+func (v *Validator) CheckRlimits() (errs error) {
+ process := v.spec.Process
+ for index, rlimit := range process.Rlimits {
+ for i := index + 1; i < len(process.Rlimits); i++ {
+ if process.Rlimits[index].Type == process.Rlimits[i].Type {
+ errs = multierror.Append(errs, fmt.Errorf("rlimit can not contain the same type %q", process.Rlimits[index].Type))
+ }
+ }
+ errs = multierror.Append(errs, v.rlimitValid(rlimit))
+ }
+
+ return
+}
+
+func supportedMountTypes(OS string, hostSpecific bool) (map[string]bool, error) {
+ supportedTypes := make(map[string]bool)
+
+ if OS != "linux" && OS != "windows" {
+ logrus.Warnf("%v is not supported to check mount type", OS)
+ return nil, nil
+ } else if OS == "windows" {
+ supportedTypes["ntfs"] = true
+ return supportedTypes, nil
+ }
+
+ if hostSpecific {
+ f, err := os.Open("/proc/filesystems")
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ s := bufio.NewScanner(f)
+ for s.Scan() {
+ if err := s.Err(); err != nil {
+ return supportedTypes, err
+ }
+
+ text := s.Text()
+ parts := strings.Split(text, "\t")
+ if len(parts) > 1 {
+ supportedTypes[parts[1]] = true
+ } else {
+ supportedTypes[parts[0]] = true
+ }
+ }
+
+ supportedTypes["bind"] = true
+
+ return supportedTypes, nil
+ }
+ logrus.Warn("Checking linux mount types without --host-specific is not supported yet")
+ return nil, nil
+}
+
+// CheckMounts checks v.spec.Mounts
+func (v *Validator) CheckMounts() (errs error) {
+ logrus.Debugf("check mounts")
+
+ supportedTypes, err := supportedMountTypes(v.platform, v.HostSpecific)
+ if err != nil {
+ errs = multierror.Append(errs, err)
+ return
+ }
+
+ for i, mountA := range v.spec.Mounts {
+ if supportedTypes != nil && !supportedTypes[mountA.Type] {
+ errs = multierror.Append(errs, fmt.Errorf("unsupported mount type %q", mountA.Type))
+ }
+ if v.platform == "windows" {
+ if err := pathValid(v.platform, mountA.Destination); err != nil {
+ errs = multierror.Append(errs, err)
+ }
+ if err := pathValid(v.platform, mountA.Source); err != nil {
+ errs = multierror.Append(errs, err)
+ }
+ } else {
+ if err := pathValid(v.platform, mountA.Destination); err != nil {
+ errs = multierror.Append(errs, err)
+ }
+ }
+ for j, mountB := range v.spec.Mounts {
+ if i == j {
+ continue
+ }
+ // whether B.Desination is nested within A.Destination
+ nested, err := nestedValid(v.platform, mountA.Destination, mountB.Destination)
+ if err != nil {
+ errs = multierror.Append(errs, err)
+ continue
+ }
+ if nested {
+ if v.platform == "windows" && i < j {
+ errs = multierror.Append(errs, fmt.Errorf("on Windows, %v nested within %v is forbidden", mountB.Destination, mountA.Destination))
+ }
+ if i > j {
+ logrus.Warnf("%v will be covered by %v", mountB.Destination, mountA.Destination)
+ }
+ }
+ }
+ }
+
+ return
+}
+
+// CheckPlatform checks v.platform
+func (v *Validator) CheckPlatform() (errs error) {
+ logrus.Debugf("check platform")
+
+ if v.platform != "linux" && v.platform != "solaris" && v.platform != "windows" {
+ errs = multierror.Append(errs, fmt.Errorf("platform %q is not supported", v.platform))
+ return
+ }
+
+ if v.platform == "windows" {
+ if v.spec.Windows == nil {
+ errs = multierror.Append(errs, errors.New("'windows' MUST be set when platform is `windows`"))
+ }
+ }
+
+ return
+}
+
+// CheckLinux checks v.spec.Linux
+func (v *Validator) CheckLinux() (errs error) {
+ logrus.Debugf("check linux")
+
+ if v.spec.Linux == nil {
+ return
+ }
+
+ var nsTypeList = map[rspec.LinuxNamespaceType]struct {
+ num int
+ newExist bool
+ }{
+ rspec.PIDNamespace: {0, false},
+ rspec.NetworkNamespace: {0, false},
+ rspec.MountNamespace: {0, false},
+ rspec.IPCNamespace: {0, false},
+ rspec.UTSNamespace: {0, false},
+ rspec.UserNamespace: {0, false},
+ rspec.CgroupNamespace: {0, false},
+ }
+
+ for index := 0; index < len(v.spec.Linux.Namespaces); index++ {
+ ns := v.spec.Linux.Namespaces[index]
+ if !namespaceValid(ns) {
+ errs = multierror.Append(errs, fmt.Errorf("namespace %v is invalid", ns))
+ }
+
+ tmpItem := nsTypeList[ns.Type]
+ tmpItem.num = tmpItem.num + 1
+ if tmpItem.num > 1 {
+ errs = multierror.Append(errs, fmt.Errorf("duplicated namespace %q", ns.Type))
+ }
+
+ if len(ns.Path) == 0 {
+ tmpItem.newExist = true
+ }
+ nsTypeList[ns.Type] = tmpItem
+ }
+
+ if (len(v.spec.Linux.UIDMappings) > 0 || len(v.spec.Linux.GIDMappings) > 0) && !nsTypeList[rspec.UserNamespace].newExist {
+ errs = multierror.Append(errs, errors.New("the UID/GID mappings requires a new User namespace to be specified as well"))
+ } else if len(v.spec.Linux.UIDMappings) > 5 {
+ errs = multierror.Append(errs, errors.New("only 5 UID mappings are allowed (linux kernel restriction)"))
+ } else if len(v.spec.Linux.GIDMappings) > 5 {
+ errs = multierror.Append(errs, errors.New("only 5 GID mappings are allowed (linux kernel restriction)"))
+ }
+
+ for k := range v.spec.Linux.Sysctl {
+ if strings.HasPrefix(k, "net.") && !nsTypeList[rspec.NetworkNamespace].newExist {
+ errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new Network namespace to be specified as well", k))
+ }
+ if strings.HasPrefix(k, "fs.mqueue.") {
+ if !nsTypeList[rspec.MountNamespace].newExist || !nsTypeList[rspec.IPCNamespace].newExist {
+ errs = multierror.Append(errs, fmt.Errorf("sysctl %v requires a new IPC namespace and Mount namespace to be specified as well", k))
+ }
+ }
+ }
+
+ if v.platform == "linux" && !nsTypeList[rspec.UTSNamespace].newExist && v.spec.Hostname != "" {
+ errs = multierror.Append(errs, fmt.Errorf("on Linux, hostname requires a new UTS namespace to be specified as well"))
+ }
+
+ // Linux devices validation
+ devList := make(map[string]bool)
+ devTypeList := make(map[string]bool)
+ for index := 0; index < len(v.spec.Linux.Devices); index++ {
+ device := v.spec.Linux.Devices[index]
+ if !deviceValid(device) {
+ errs = multierror.Append(errs, fmt.Errorf("device %v is invalid", device))
+ }
+
+ if _, exists := devList[device.Path]; exists {
+ errs = multierror.Append(errs, fmt.Errorf("device %s is duplicated", device.Path))
+ } else {
+ var rootfsPath string
+ if filepath.IsAbs(v.spec.Root.Path) {
+ rootfsPath = v.spec.Root.Path
+ } else {
+ rootfsPath = filepath.Join(v.bundlePath, v.spec.Root.Path)
+ }
+ absPath := filepath.Join(rootfsPath, device.Path)
+ fi, err := os.Stat(absPath)
+ if os.IsNotExist(err) {
+ devList[device.Path] = true
+ } else if err != nil {
+ errs = multierror.Append(errs, err)
+ } else {
+ fStat, ok := fi.Sys().(*syscall.Stat_t)
+ if !ok {
+ errs = multierror.Append(errs, fmt.Errorf("cannot determine state for device %s", device.Path))
+ continue
+ }
+ var devType string
+ switch fStat.Mode & syscall.S_IFMT {
+ case syscall.S_IFCHR:
+ devType = "c"
+ case syscall.S_IFBLK:
+ devType = "b"
+ case syscall.S_IFIFO:
+ devType = "p"
+ default:
+ devType = "unmatched"
+ }
+ if devType != device.Type || (devType == "c" && device.Type == "u") {
+ errs = multierror.Append(errs, fmt.Errorf("unmatched %s already exists in filesystem", device.Path))
+ continue
+ }
+ if devType != "p" {
+ dev := fStat.Rdev
+ major := (dev >> 8) & 0xfff
+ minor := (dev & 0xff) | ((dev >> 12) & 0xfff00)
+ if int64(major) != device.Major || int64(minor) != device.Minor {
+ errs = multierror.Append(errs, fmt.Errorf("unmatched %s already exists in filesystem", device.Path))
+ continue
+ }
+ }
+ if device.FileMode != nil {
+ expectedPerm := *device.FileMode & os.ModePerm
+ actualPerm := fi.Mode() & os.ModePerm
+ if expectedPerm != actualPerm {
+ errs = multierror.Append(errs, fmt.Errorf("unmatched %s already exists in filesystem", device.Path))
+ continue
+ }
+ }
+ if device.UID != nil {
+ if *device.UID != fStat.Uid {
+ errs = multierror.Append(errs, fmt.Errorf("unmatched %s already exists in filesystem", device.Path))
+ continue
+ }
+ }
+ if device.GID != nil {
+ if *device.GID != fStat.Gid {
+ errs = multierror.Append(errs, fmt.Errorf("unmatched %s already exists in filesystem", device.Path))
+ continue
+ }
+ }
+ }
+ }
+
+ // unify u->c when comparing, they are synonyms
+ var devID string
+ if device.Type == "u" {
+ devID = fmt.Sprintf("%s:%d:%d", "c", device.Major, device.Minor)
+ } else {
+ devID = fmt.Sprintf("%s:%d:%d", device.Type, device.Major, device.Minor)
+ }
+
+ if _, exists := devTypeList[devID]; exists {
+ logrus.Warnf("type:%s, major:%d and minor:%d for linux devices is duplicated", device.Type, device.Major, device.Minor)
+ } else {
+ devTypeList[devID] = true
+ }
+ }
+
+ if v.spec.Linux.Resources != nil {
+ errs = multierror.Append(errs, v.CheckLinuxResources())
+ }
+
+ if v.spec.Linux.Seccomp != nil {
+ errs = multierror.Append(errs, v.CheckSeccomp())
+ }
+
+ switch v.spec.Linux.RootfsPropagation {
+ case "":
+ case "private":
+ case "rprivate":
+ case "slave":
+ case "rslave":
+ case "shared":
+ case "rshared":
+ case "unbindable":
+ case "runbindable":
+ default:
+ errs = multierror.Append(errs, errors.New("rootfsPropagation must be empty or one of \"private|rprivate|slave|rslave|shared|rshared|unbindable|runbindable\""))
+ }
+
+ for _, maskedPath := range v.spec.Linux.MaskedPaths {
+ if !strings.HasPrefix(maskedPath, "/") {
+ errs = multierror.Append(errs, fmt.Errorf("maskedPath %v is not an absolute path", maskedPath))
+ }
+ }
+
+ for _, readonlyPath := range v.spec.Linux.ReadonlyPaths {
+ if !strings.HasPrefix(readonlyPath, "/") {
+ errs = multierror.Append(errs, fmt.Errorf("readonlyPath %v is not an absolute path", readonlyPath))
+ }
+ }
+
+ return
+}
+
+// CheckLinuxResources checks v.spec.Linux.Resources
+func (v *Validator) CheckLinuxResources() (errs error) {
+ logrus.Debugf("check linux resources")
+
+ r := v.spec.Linux.Resources
+ if r.Memory != nil {
+ if r.Memory.Limit != nil && r.Memory.Swap != nil && uint64(*r.Memory.Limit) > uint64(*r.Memory.Swap) {
+ errs = multierror.Append(errs, fmt.Errorf("minimum memoryswap should be larger than memory limit"))
+ }
+ if r.Memory.Limit != nil && r.Memory.Reservation != nil && uint64(*r.Memory.Reservation) > uint64(*r.Memory.Limit) {
+ errs = multierror.Append(errs, fmt.Errorf("minimum memory limit should be larger than memory reservation"))
+ }
+ }
+ if r.Network != nil && v.HostSpecific {
+ var exist bool
+ interfaces, err := net.Interfaces()
+ if err != nil {
+ errs = multierror.Append(errs, err)
+ return
+ }
+ for _, prio := range r.Network.Priorities {
+ exist = false
+ for _, ni := range interfaces {
+ if prio.Name == ni.Name {
+ exist = true
+ break
+ }
+ }
+ if !exist {
+ errs = multierror.Append(errs, fmt.Errorf("interface %s does not exist currently", prio.Name))
+ }
+ }
+ }
+ for index := 0; index < len(r.Devices); index++ {
+ switch r.Devices[index].Type {
+ case "a", "b", "c":
+ default:
+ errs = multierror.Append(errs, fmt.Errorf("type of devices %s is invalid", r.Devices[index].Type))
+ }
+
+ access := []byte(r.Devices[index].Access)
+ for i := 0; i < len(access); i++ {
+ switch access[i] {
+ case 'r', 'w', 'm':
+ default:
+ errs = multierror.Append(errs, fmt.Errorf("access %s is invalid", r.Devices[index].Access))
+ return
+ }
+ }
+ }
+
+ return
+}
+
+// CheckSeccomp checkc v.spec.Linux.Seccomp
+func (v *Validator) CheckSeccomp() (errs error) {
+ logrus.Debugf("check linux seccomp")
+
+ s := v.spec.Linux.Seccomp
+ if !seccompActionValid(s.DefaultAction) {
+ errs = multierror.Append(errs, fmt.Errorf("seccomp defaultAction %q is invalid", s.DefaultAction))
+ }
+ for index := 0; index < len(s.Syscalls); index++ {
+ if !syscallValid(s.Syscalls[index]) {
+ errs = multierror.Append(errs, fmt.Errorf("syscall %v is invalid", s.Syscalls[index]))
+ }
+ }
+ for index := 0; index < len(s.Architectures); index++ {
+ switch s.Architectures[index] {
+ case rspec.ArchX86:
+ case rspec.ArchX86_64:
+ case rspec.ArchX32:
+ case rspec.ArchARM:
+ case rspec.ArchAARCH64:
+ case rspec.ArchMIPS:
+ case rspec.ArchMIPS64:
+ case rspec.ArchMIPS64N32:
+ case rspec.ArchMIPSEL:
+ case rspec.ArchMIPSEL64:
+ case rspec.ArchMIPSEL64N32:
+ case rspec.ArchPPC:
+ case rspec.ArchPPC64:
+ case rspec.ArchPPC64LE:
+ case rspec.ArchS390:
+ case rspec.ArchS390X:
+ case rspec.ArchPARISC:
+ case rspec.ArchPARISC64:
+ default:
+ errs = multierror.Append(errs, fmt.Errorf("seccomp architecture %q is invalid", s.Architectures[index]))
+ }
+ }
+
+ return
+}
+
+// CapValid checks whether a capability is valid
+func CapValid(c string, hostSpecific bool) error {
+ isValid := false
+
+ if !strings.HasPrefix(c, "CAP_") {
+ return fmt.Errorf("capability %s must start with CAP_", c)
+ }
+ for _, cap := range capability.List() {
+ if c == fmt.Sprintf("CAP_%s", strings.ToUpper(cap.String())) {
+ if hostSpecific && cap > LastCap() {
+ return fmt.Errorf("%s is not supported on the current host", c)
+ }
+ isValid = true
+ break
+ }
+ }
+
+ if !isValid {
+ return fmt.Errorf("invalid capability: %s", c)
+ }
+ return nil
+}
+
+// LastCap return last cap of system
+func LastCap() capability.Cap {
+ last := capability.CAP_LAST_CAP
+ // hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
+ if last == capability.Cap(63) {
+ last = capability.CAP_BLOCK_SUSPEND
+ }
+
+ return last
+}
+
+func envValid(env string) bool {
+ items := strings.Split(env, "=")
+ if len(items) < 2 {
+ return false
+ }
+ for i, ch := range strings.TrimSpace(items[0]) {
+ if !unicode.IsDigit(ch) && !unicode.IsLetter(ch) && ch != '_' {
+ return false
+ }
+ if i == 0 && unicode.IsDigit(ch) {
+ logrus.Warnf("Env %v: variable name beginning with digit is not recommended.", env)
+ }
+ }
+ return true
+}
+
+func (v *Validator) rlimitValid(rlimit rspec.POSIXRlimit) (errs error) {
+ if rlimit.Hard < rlimit.Soft {
+ errs = multierror.Append(errs, fmt.Errorf("hard limit of rlimit %s should not be less than soft limit", rlimit.Type))
+ }
+
+ if v.platform == "linux" {
+ for _, val := range defaultRlimits {
+ if val == rlimit.Type {
+ return
+ }
+ }
+ errs = multierror.Append(errs, fmt.Errorf("rlimit type %q is invalid", rlimit.Type))
+ } else {
+ logrus.Warnf("process.rlimits validation not yet implemented for platform %q", v.platform)
+ }
+
+ return
+}
+
+func namespaceValid(ns rspec.LinuxNamespace) bool {
+ switch ns.Type {
+ case rspec.PIDNamespace:
+ case rspec.NetworkNamespace:
+ case rspec.MountNamespace:
+ case rspec.IPCNamespace:
+ case rspec.UTSNamespace:
+ case rspec.UserNamespace:
+ case rspec.CgroupNamespace:
+ default:
+ return false
+ }
+
+ if ns.Path != "" && !filepath.IsAbs(ns.Path) {
+ return false
+ }
+
+ return true
+}
+
+func pathValid(os, path string) error {
+ if os == "windows" {
+ matched, err := regexp.MatchString("^[a-zA-Z]:(\\\\[^\\\\/<>|:*?\"]+)+$", path)
+ if err != nil {
+ return err
+ }
+ if !matched {
+ return fmt.Errorf("invalid windows path %v", path)
+ }
+ return nil
+ }
+ if !filepath.IsAbs(path) {
+ return fmt.Errorf("%v is not an absolute path", path)
+ }
+ return nil
+}
+
+// Check whether pathB is nested whithin pathA
+func nestedValid(os, pathA, pathB string) (bool, error) {
+ if pathA == pathB {
+ return false, nil
+ }
+ if pathA == "/" && pathB != "" {
+ return true, nil
+ }
+
+ var sep string
+ if os == "windows" {
+ sep = "\\"
+ } else {
+ sep = "/"
+ }
+
+ splitedPathA := strings.Split(filepath.Clean(pathA), sep)
+ splitedPathB := strings.Split(filepath.Clean(pathB), sep)
+ lenA := len(splitedPathA)
+ lenB := len(splitedPathB)
+
+ if lenA > lenB {
+ if (lenA - lenB) == 1 {
+ // if pathA is longer but not end with separator
+ if splitedPathA[lenA-1] != "" {
+ return false, nil
+ }
+ splitedPathA = splitedPathA[:lenA-1]
+ } else {
+ return false, nil
+ }
+ }
+
+ for i, partA := range splitedPathA {
+ if partA != splitedPathB[i] {
+ return false, nil
+ }
+ }
+
+ return true, nil
+}
+
+func deviceValid(d rspec.LinuxDevice) bool {
+ switch d.Type {
+ case "b", "c", "u":
+ if d.Major <= 0 || d.Minor <= 0 {
+ return false
+ }
+ case "p":
+ if d.Major > 0 || d.Minor > 0 {
+ return false
+ }
+ default:
+ return false
+ }
+ return true
+}
+
+func seccompActionValid(secc rspec.LinuxSeccompAction) bool {
+ switch secc {
+ case "":
+ case rspec.ActKill:
+ case rspec.ActTrap:
+ case rspec.ActErrno:
+ case rspec.ActTrace:
+ case rspec.ActAllow:
+ default:
+ return false
+ }
+ return true
+}
+
+func syscallValid(s rspec.LinuxSyscall) bool {
+ if !seccompActionValid(s.Action) {
+ return false
+ }
+ for index := 0; index < len(s.Args); index++ {
+ arg := s.Args[index]
+ switch arg.Op {
+ case rspec.OpNotEqual:
+ case rspec.OpLessThan:
+ case rspec.OpLessEqual:
+ case rspec.OpEqualTo:
+ case rspec.OpGreaterEqual:
+ case rspec.OpGreaterThan:
+ case rspec.OpMaskedEqual:
+ default:
+ return false
+ }
+ }
+ return true
+}
+
+func isStruct(t reflect.Type) bool {
+ return t.Kind() == reflect.Struct
+}
+
+func isStructPtr(t reflect.Type) bool {
+ return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
+}
+
+func checkMandatoryUnit(field reflect.Value, tagField reflect.StructField, parent string) (errs error) {
+ mandatory := !strings.Contains(tagField.Tag.Get("json"), "omitempty")
+ switch field.Kind() {
+ case reflect.Ptr:
+ if mandatory && field.IsNil() {
+ errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
+ }
+ case reflect.String:
+ if mandatory && (field.Len() == 0) {
+ errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
+ }
+ case reflect.Slice:
+ if mandatory && (field.IsNil() || field.Len() == 0) {
+ errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
+ return
+ }
+ for index := 0; index < field.Len(); index++ {
+ mValue := field.Index(index)
+ if mValue.CanInterface() {
+ errs = multierror.Append(errs, checkMandatory(mValue.Interface()))
+ }
+ }
+ case reflect.Map:
+ if mandatory && (field.IsNil() || field.Len() == 0) {
+ errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", parent, tagField.Name))
+ return
+ }
+ keys := field.MapKeys()
+ for index := 0; index < len(keys); index++ {
+ mValue := field.MapIndex(keys[index])
+ if mValue.CanInterface() {
+ errs = multierror.Append(errs, checkMandatory(mValue.Interface()))
+ }
+ }
+ default:
+ }
+
+ return
+}
+
+func checkMandatory(obj interface{}) (errs error) {
+ objT := reflect.TypeOf(obj)
+ objV := reflect.ValueOf(obj)
+ if isStructPtr(objT) {
+ objT = objT.Elem()
+ objV = objV.Elem()
+ } else if !isStruct(objT) {
+ return
+ }
+
+ for i := 0; i < objT.NumField(); i++ {
+ t := objT.Field(i).Type
+ if isStructPtr(t) && objV.Field(i).IsNil() {
+ if !strings.Contains(objT.Field(i).Tag.Get("json"), "omitempty") {
+ errs = multierror.Append(errs, fmt.Errorf("'%s.%s' should not be empty", objT.Name(), objT.Field(i).Name))
+ }
+ } else if (isStruct(t) || isStructPtr(t)) && objV.Field(i).CanInterface() {
+ errs = multierror.Append(errs, checkMandatory(objV.Field(i).Interface()))
+ } else {
+ errs = multierror.Append(errs, checkMandatoryUnit(objV.Field(i), objT.Field(i), objT.Name()))
+ }
+
+ }
+ return
+}
+
+// CheckMandatoryFields checks mandatory field of container's config file
+func (v *Validator) CheckMandatoryFields() error {
+ logrus.Debugf("check mandatory fields")
+
+ return checkMandatory(v.spec)
+}