// Copyright 2020 The gVisor Authors. // // 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. // Package config provides basic infrastructure to set configuration settings // for runsc. The configuration is set by flags to the command line. They can // also propagate to a different process using the same flags. package config import ( "fmt" "strconv" "strings" "gvisor.dev/gvisor/pkg/refs" "gvisor.dev/gvisor/pkg/sentry/watchdog" ) // FileAccessType tells how the filesystem is accessed. type FileAccessType int const ( // FileAccessShared sends IO requests to a Gofer process that validates the // requests and forwards them to the host. FileAccessShared FileAccessType = iota // FileAccessExclusive is the same as FileAccessShared, but enables // extra caching for improved performance. It should only be used if // the sandbox has exclusive access to the filesystem. FileAccessExclusive ) // MakeFileAccessType converts type from string. func MakeFileAccessType(s string) (FileAccessType, error) { switch s { case "shared": return FileAccessShared, nil case "exclusive": return FileAccessExclusive, nil default: return 0, fmt.Errorf("invalid file access type %q", s) } } func (f FileAccessType) String() string { switch f { case FileAccessShared: return "shared" case FileAccessExclusive: return "exclusive" default: return fmt.Sprintf("unknown(%d)", f) } } // NetworkType tells which network stack to use. type NetworkType int const ( // NetworkSandbox uses internal network stack, isolated from the host. NetworkSandbox NetworkType = iota // NetworkHost redirects network related syscalls to the host network. NetworkHost // NetworkNone sets up just loopback using netstack. NetworkNone ) // MakeNetworkType converts type from string. func MakeNetworkType(s string) (NetworkType, error) { switch s { case "sandbox": return NetworkSandbox, nil case "host": return NetworkHost, nil case "none": return NetworkNone, nil default: return 0, fmt.Errorf("invalid network type %q", s) } } func (n NetworkType) String() string { switch n { case NetworkSandbox: return "sandbox" case NetworkHost: return "host" case NetworkNone: return "none" default: return fmt.Sprintf("unknown(%d)", n) } } // MakeWatchdogAction converts type from string. func MakeWatchdogAction(s string) (watchdog.Action, error) { switch strings.ToLower(s) { case "log", "logwarning": return watchdog.LogWarning, nil case "panic": return watchdog.Panic, nil default: return 0, fmt.Errorf("invalid watchdog action %q", s) } } // MakeRefsLeakMode converts type from string. func MakeRefsLeakMode(s string) (refs.LeakMode, error) { switch strings.ToLower(s) { case "disabled": return refs.NoLeakChecking, nil case "log-names": return refs.LeaksLogWarning, nil case "log-traces": return refs.LeaksLogTraces, nil default: return 0, fmt.Errorf("invalid refs leakmode %q", s) } } func refsLeakModeToString(mode refs.LeakMode) string { switch mode { // If not set, default it to disabled. case refs.UninitializedLeakChecking, refs.NoLeakChecking: return "disabled" case refs.LeaksLogWarning: return "log-names" case refs.LeaksLogTraces: return "log-traces" default: panic(fmt.Sprintf("Invalid leakmode: %d", mode)) } } // QueueingDiscipline is used to specify the kind of Queueing Discipline to // apply for a give FDBasedLink. type QueueingDiscipline int const ( // QDiscNone disables any queueing for the underlying FD. QDiscNone QueueingDiscipline = iota // QDiscFIFO applies a simple fifo based queue to the underlying // FD. QDiscFIFO ) // MakeQueueingDiscipline if possible the equivalent QueuingDiscipline for s // else returns an error. func MakeQueueingDiscipline(s string) (QueueingDiscipline, error) { switch s { case "none": return QDiscNone, nil case "fifo": return QDiscFIFO, nil default: return 0, fmt.Errorf("unsupported qdisc specified: %q", s) } } // String implements fmt.Stringer. func (q QueueingDiscipline) String() string { switch q { case QDiscNone: return "none" case QDiscFIFO: return "fifo" default: panic(fmt.Sprintf("Invalid queueing discipline: %d", q)) } } // Config holds configuration that is not part of the runtime spec. type Config struct { // RootDir is the runtime root directory. RootDir string // Debug indicates that debug logging should be enabled. Debug bool // LogFilename is the filename to log to, if not empty. LogFilename string // LogFormat is the log format. LogFormat string // DebugLog is the path to log debug information to, if not empty. DebugLog string // PanicLog is the path to log GO's runtime messages, if not empty. PanicLog string // DebugLogFormat is the log format for debug. DebugLogFormat string // FileAccess indicates how the filesystem is accessed. FileAccess FileAccessType // Overlay is whether to wrap the root filesystem in an overlay. Overlay bool // FSGoferHostUDS enables the gofer to mount a host UDS. FSGoferHostUDS bool // Network indicates what type of network to use. Network NetworkType // EnableRaw indicates whether raw sockets should be enabled. Raw // sockets are disabled by stripping CAP_NET_RAW from the list of // capabilities. EnableRaw bool // HardwareGSO indicates that hardware segmentation offload is enabled. HardwareGSO bool // SoftwareGSO indicates that software segmentation offload is enabled. SoftwareGSO bool // TXChecksumOffload indicates that TX Checksum Offload is enabled. TXChecksumOffload bool // RXChecksumOffload indicates that RX Checksum Offload is enabled. RXChecksumOffload bool // QDisc indicates the type of queuening discipline to use by default // for non-loopback interfaces. QDisc QueueingDiscipline // LogPackets indicates that all network packets should be logged. LogPackets bool // Platform is the platform to run on. Platform string // Strace indicates that strace should be enabled. Strace bool // StraceSyscalls is the set of syscalls to trace. If StraceEnable is // true and this list is empty, then all syscalls will be traced. StraceSyscalls []string // StraceLogSize is the max size of data blobs to display. StraceLogSize uint // DisableSeccomp indicates whether seccomp syscall filters should be // disabled. Pardon the double negation, but default to enabled is important. DisableSeccomp bool // WatchdogAction sets what action the watchdog takes when triggered. WatchdogAction watchdog.Action // PanicSignal registers signal handling that panics. Usually set to // SIGUSR2(12) to troubleshoot hangs. -1 disables it. PanicSignal int // ProfileEnable is set to prepare the sandbox to be profiled. ProfileEnable bool // RestoreFile is the path to the saved container image RestoreFile string // NumNetworkChannels controls the number of AF_PACKET sockets that map // to the same underlying network device. This allows netstack to better // scale for high throughput use cases. NumNetworkChannels int // Rootless allows the sandbox to be started with a user that is not root. // Defense is depth measures are weaker with rootless. Specifically, the // sandbox and Gofer process run as root inside a user namespace with root // mapped to the caller's user. Rootless bool // AlsoLogToStderr allows to send log messages to stderr. AlsoLogToStderr bool // ReferenceLeakMode sets reference leak check mode ReferenceLeakMode refs.LeakMode // OverlayfsStaleRead instructs the sandbox to assume that the root mount // is on a Linux overlayfs mount, which does not necessarily preserve // coherence between read-only and subsequent writable file descriptors // representing the "same" file. OverlayfsStaleRead bool // CPUNumFromQuota sets CPU number count to available CPU quota, using // least integer value greater than or equal to quota. // // E.g. 0.2 CPU quota will result in 1, and 1.9 in 2. CPUNumFromQuota bool // Enables VFS2 (not plumbed through yet). VFS2 bool // Enables FUSE usage (not plumbed through yet). FUSE bool // TestOnlyAllowRunAsCurrentUserWithoutChroot should only be used in // tests. It allows runsc to start the sandbox process as the current // user, and without chrooting the sandbox process. This can be // necessary in test environments that have limited capabilities. TestOnlyAllowRunAsCurrentUserWithoutChroot bool // TestOnlyTestNameEnv should only be used in tests. It looks up for the // test name in the container environment variables and adds it to the debug // log file name. This is done to help identify the log with the test when // multiple tests are run in parallel, since there is no way to pass // parameters to the runtime from docker. TestOnlyTestNameEnv string } // ToFlags returns a slice of flags that correspond to the given Config. func (c *Config) ToFlags() []string { f := []string{ "--root=" + c.RootDir, "--debug=" + strconv.FormatBool(c.Debug), "--log=" + c.LogFilename, "--log-format=" + c.LogFormat, "--debug-log=" + c.DebugLog, "--panic-log=" + c.PanicLog, "--debug-log-format=" + c.DebugLogFormat, "--file-access=" + c.FileAccess.String(), "--overlay=" + strconv.FormatBool(c.Overlay), "--fsgofer-host-uds=" + strconv.FormatBool(c.FSGoferHostUDS), "--network=" + c.Network.String(), "--log-packets=" + strconv.FormatBool(c.LogPackets), "--platform=" + c.Platform, "--strace=" + strconv.FormatBool(c.Strace), "--strace-syscalls=" + strings.Join(c.StraceSyscalls, ","), "--strace-log-size=" + strconv.Itoa(int(c.StraceLogSize)), "--watchdog-action=" + c.WatchdogAction.String(), "--panic-signal=" + strconv.Itoa(c.PanicSignal), "--profile=" + strconv.FormatBool(c.ProfileEnable), "--net-raw=" + strconv.FormatBool(c.EnableRaw), "--num-network-channels=" + strconv.Itoa(c.NumNetworkChannels), "--rootless=" + strconv.FormatBool(c.Rootless), "--alsologtostderr=" + strconv.FormatBool(c.AlsoLogToStderr), "--ref-leak-mode=" + refsLeakModeToString(c.ReferenceLeakMode), "--gso=" + strconv.FormatBool(c.HardwareGSO), "--software-gso=" + strconv.FormatBool(c.SoftwareGSO), "--rx-checksum-offload=" + strconv.FormatBool(c.RXChecksumOffload), "--tx-checksum-offload=" + strconv.FormatBool(c.TXChecksumOffload), "--overlayfs-stale-read=" + strconv.FormatBool(c.OverlayfsStaleRead), "--qdisc=" + c.QDisc.String(), "--vfs2=" + strconv.FormatBool(c.VFS2), "--fuse=" + strconv.FormatBool(c.FUSE), } if c.CPUNumFromQuota { f = append(f, "--cpu-num-from-quota") } if c.VFS2 { f = append(f, "--vfs2=true") } if c.FUSE { f = append(f, "--fuse=true") } // Only include these if set since it is never to be used by users. if c.TestOnlyAllowRunAsCurrentUserWithoutChroot { f = append(f, "--TESTONLY-unsafe-nonroot=true") } if len(c.TestOnlyTestNameEnv) != 0 { f = append(f, "--TESTONLY-test-name-env="+c.TestOnlyTestNameEnv) } return f }