Skip to content

Commit ccd3f6e

Browse files
committed
sanitize: Add a config-sanitization command
Based on image-spec, which currently exposes [1]: * User (user and group by ID or name) Represented in runtime-spec by process.user.*, although I'm clearing additionalGids for now because the old formats gave no way to represent that. * Memory (limit) Represented in runtime-spec by linux.resources.memory.limit and solaris.cappedMemory.physical. * MemorySwap (memory + swap limit) Represented in runtime-spec by linux.resources.memory.swap and solaris.cappedMemory.physical + solaris.cappedMemory.swap. * CpuShares (relative weight vs. other containers) Represented in runtime-spec by linux.resources.cpu.shares. Solaris has an ncpus property, but no shares analog. * ExposedPorts (a set of port/protocol entries) This is not covered by runtime-spec, but image-spec was planning on stuffing it into annotations [2]. * Env (array of environment variables) Represented in runtime-spec by process.env. * Entrypoint (array of positional arguments) Represented in runtime-spec by process.cmd. * Cmd (array of positional arguments) Represented in runtime-spec by process.cmd. * Volumes (set of directories which should have data volumes mounted on them) Represented in runtime-spec by mounts, although Volumes doesn't include source locations. * WorkingDir (initial working directory of container process) Represented in runtime-spec by process.cwd. Entrypoint and Cmd are slightly different and have a few different forms each [3,4]. Both are represented in the runtime-spec config by process.args. This commit sets all other config settings to their default values, and it clears mounts[].source to mimic the Volumes information. image-spec currently sets up source-less bind-mounts when translating Volumes [5]. With the sanitization command, *any* runtime configuration can be sanitized to be just as safe and limited as the current image-spec config. [1]: https://github.com/opencontainers/image-spec/blob/v0.5.0/serialization.md#container-runconfig-field-descriptions [2]: opencontainers/image-spec#87 (comment) Subject: Convert a serialization config JSON to a OCI runtime configuration. [3]: https://docs.docker.com/engine/reference/builder/#entrypoint [4]: https://docs.docker.com/engine/reference/builder/#cmd [5]: https://github.com/opencontainers/image-spec/blob/v0.5.0/image/config.go#L127-L136 Signed-off-by: W. Trevor King <[email protected]>
1 parent 5c1fa31 commit ccd3f6e

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

cmd/oci-runtime-tool/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func main() {
2727
app.Commands = []cli.Command{
2828
generateCommand,
2929
bundleValidateCommand,
30+
sanitizeCommand,
3031
}
3132

3233
if err := app.Run(os.Args); err != nil {

cmd/oci-runtime-tool/sanitize.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"os"
8+
9+
rspec "github.com/opencontainers/runtime-spec/specs-go"
10+
"github.com/opencontainers/runtime-tools/sanitize"
11+
"github.com/urfave/cli"
12+
)
13+
14+
var sanitizeFlags = []cli.Flag{
15+
cli.StringFlag{Name: "output", Usage: "output file (defaults to stdout)"},
16+
}
17+
18+
var sanitizeCommand = cli.Command{
19+
Name: "sanitize",
20+
Usage: "sanitize an OCI runtime configuration file",
21+
Flags: sanitizeFlags,
22+
Before: before,
23+
Action: func(context *cli.Context) (err error) {
24+
var reader io.ReadCloser
25+
if context.NArg() == 0 {
26+
reader = os.Stdin
27+
} else if context.NArg() == 1 {
28+
reader, err = os.Open(context.Args().First())
29+
if err != nil {
30+
return err
31+
}
32+
defer reader.Close()
33+
} else {
34+
return fmt.Errorf("too many arguments (%d > 1)", context.NArg())
35+
}
36+
37+
var config rspec.Spec
38+
err = json.NewDecoder(reader).Decode(&config)
39+
if err != nil {
40+
return err
41+
}
42+
43+
err = reader.Close()
44+
if err != nil {
45+
return err
46+
}
47+
48+
err = sanitize.Sanitize(&config)
49+
if err != nil {
50+
return err
51+
}
52+
53+
var writer io.WriteCloser
54+
if context.IsSet("output") {
55+
writer, err = os.OpenFile(context.String("output"), os.O_WRONLY | os.O_TRUNC, 0)
56+
if err != nil {
57+
return err
58+
}
59+
defer writer.Close()
60+
} else {
61+
writer = os.Stdout
62+
}
63+
64+
encoder := json.NewEncoder(writer)
65+
return encoder.Encode(&config)
66+
},
67+
}

sanitize/sanitize.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Package sanitize removes dangerous and questionably-portable properties from container configurations.
2+
package sanitize
3+
4+
import (
5+
rspec "github.com/opencontainers/runtime-spec/specs-go"
6+
)
7+
8+
// Santize removes dangerous and questionably-portable properties from container configurations.
9+
func Sanitize(config *rspec.Spec) (err error) {
10+
config.Process.Terminal = false
11+
//config.Process.ConsoleSize = nil // needs runtime-spec#581
12+
config.Process.User.AdditionalGids = []uint32{}
13+
config.Process.Capabilities = []string{}
14+
config.Process.Rlimits = []rspec.Rlimit{}
15+
config.Process.NoNewPrivileges = false
16+
config.Process.ApparmorProfile = ""
17+
config.Process.SelinuxLabel = ""
18+
config.Root = rspec.Root{
19+
Path: "rootfs",
20+
}
21+
config.Hostname = ""
22+
//config.Hooks = nil // needs runtime-spec#427
23+
24+
for i, _ := range config.Mounts {
25+
config.Mounts[i].Source = ""
26+
}
27+
28+
if config.Linux != nil {
29+
config.Linux.UIDMappings = []rspec.IDMapping{}
30+
config.Linux.GIDMappings = []rspec.IDMapping{}
31+
config.Linux.Sysctl = map[string]string{}
32+
config.Linux.CgroupsPath = nil
33+
config.Linux.Namespaces = []rspec.Namespace{}
34+
config.Linux.Devices = []rspec.Device{}
35+
config.Linux.Seccomp = nil
36+
config.Linux.RootfsPropagation = ""
37+
config.Linux.MaskedPaths = []string{}
38+
config.Linux.MaskedPaths = []string{}
39+
config.Linux.MountLabel = ""
40+
41+
if config.Linux.Resources != nil {
42+
config.Linux.Resources.Devices = []rspec.DeviceCgroup{}
43+
config.Linux.Resources.DisableOOMKiller = nil
44+
config.Linux.Resources.OOMScoreAdj= nil
45+
config.Linux.Resources.Pids = nil
46+
config.Linux.Resources.BlockIO = nil
47+
config.Linux.Resources.HugepageLimits = []rspec.HugepageLimit{}
48+
config.Linux.Resources.Network = nil
49+
50+
if config.Linux.Resources.Memory != nil {
51+
config.Linux.Resources.Memory.Kernel = nil
52+
config.Linux.Resources.Memory.KernelTCP = nil
53+
config.Linux.Resources.Memory.Swappiness = nil
54+
}
55+
56+
if config.Linux.Resources.CPU != nil {
57+
config.Linux.Resources.CPU.Quota = nil
58+
config.Linux.Resources.CPU.Period = nil
59+
config.Linux.Resources.CPU.RealtimeRuntime = nil
60+
config.Linux.Resources.CPU.Period = nil
61+
config.Linux.Resources.CPU.Cpus = nil
62+
config.Linux.Resources.CPU.Mems = nil
63+
}
64+
}
65+
}
66+
67+
if config.Solaris != nil {
68+
config.Solaris.Milestone = ""
69+
config.Solaris.LimitPriv = ""
70+
config.Solaris.MaxShmMemory = ""
71+
config.Solaris.Anet = []rspec.Anet{}
72+
config.Solaris.CappedCPU = nil
73+
}
74+
75+
return nil
76+
}

0 commit comments

Comments
 (0)