github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/runsc/config/config.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package config provides basic infrastructure to set configuration settings 16 // for runsc. The configuration is set by flags to the command line. They can 17 // also propagate to a different process using the same flags. 18 package config 19 20 import ( 21 "fmt" 22 "path/filepath" 23 "runtime" 24 "strconv" 25 "strings" 26 "time" 27 28 "github.com/MerlinKodo/gvisor/pkg/refs" 29 "github.com/MerlinKodo/gvisor/pkg/sentry/watchdog" 30 "github.com/MerlinKodo/gvisor/runsc/flag" 31 "github.com/MerlinKodo/gvisor/runsc/version" 32 ) 33 34 // Config holds configuration that is not part of the runtime spec. 35 // 36 // Follow these steps to add a new flag: 37 // 1. Create a new field in Config. 38 // 2. Add a field tag with the flag name 39 // 3. Register a new flag in flags.go, with same name and add a description 40 // 4. Add any necessary validation into validate() 41 // 5. If adding an enum, follow the same pattern as FileAccessType 42 // 6. Evaluate if the flag can be changed with OCI annotations. See 43 // overrideAllowlist for more details 44 type Config struct { 45 // RootDir is the runtime root directory. 46 RootDir string `flag:"root"` 47 48 // Traceback changes the Go runtime's traceback level. 49 Traceback string `flag:"traceback"` 50 51 // Debug indicates that debug logging should be enabled. 52 Debug bool `flag:"debug"` 53 54 // LogFilename is the filename to log to, if not empty. 55 LogFilename string `flag:"log"` 56 57 // LogFormat is the log format. 58 LogFormat string `flag:"log-format"` 59 60 // DebugLog is the path to log debug information to, if not empty. 61 DebugLog string `flag:"debug-log"` 62 63 // DebugCommand is a comma-separated list of commands to be debugged if 64 // --debug-log is also set. Empty means debug all. "!" negates the expression. 65 // E.g. "create,start" or "!boot,events". 66 DebugCommand string `flag:"debug-command"` 67 68 // PanicLog is the path to log GO's runtime messages, if not empty. 69 PanicLog string `flag:"panic-log"` 70 71 // CoverageReport is the path to write Go coverage information, if not empty. 72 CoverageReport string `flag:"coverage-report"` 73 74 // DebugLogFormat is the log format for debug. 75 DebugLogFormat string `flag:"debug-log-format"` 76 77 // FileAccess indicates how the root filesystem is accessed. 78 FileAccess FileAccessType `flag:"file-access"` 79 80 // FileAccessMounts indicates how non-root volumes are accessed. 81 FileAccessMounts FileAccessType `flag:"file-access-mounts"` 82 83 // Overlay is whether to wrap all mounts in an overlay. The upper tmpfs layer 84 // will be backed by application memory. 85 Overlay bool `flag:"overlay"` 86 87 // Overlay2 holds configuration about wrapping mounts in overlayfs. 88 // DO NOT call it directly, use GetOverlay2() instead. 89 Overlay2 Overlay2 `flag:"overlay2"` 90 91 // FSGoferHostUDS is deprecated: use host-uds=all. 92 FSGoferHostUDS bool `flag:"fsgofer-host-uds"` 93 94 // HostUDS controls permission to access host Unix-domain sockets. 95 // DO NOT call it directly, use GetHostUDS() instead. 96 HostUDS HostUDS `flag:"host-uds"` 97 98 // HostFifo controls permission to access host FIFO (or named pipes). 99 HostFifo HostFifo `flag:"host-fifo"` 100 101 // Network indicates what type of network to use. 102 Network NetworkType `flag:"network"` 103 104 // EnableRaw indicates whether raw sockets should be enabled. Raw 105 // sockets are disabled by stripping CAP_NET_RAW from the list of 106 // capabilities. 107 EnableRaw bool `flag:"net-raw"` 108 109 // AllowPacketEndpointWrite enables write operations on packet endpoints. 110 AllowPacketEndpointWrite bool `flag:"TESTONLY-allow-packet-endpoint-write"` 111 112 // HostGSO indicates that host segmentation offload is enabled. 113 HostGSO bool `flag:"gso"` 114 115 // GvisorGSO indicates that gVisor segmentation offload is enabled. The flag 116 // retains its old name of "software" GSO for API consistency. 117 GvisorGSO bool `flag:"software-gso"` 118 119 // GvisorGROTimeout sets gVisor's generic receive offload timeout. Zero 120 // bypasses GRO. 121 GvisorGROTimeout time.Duration `flag:"gvisor-gro"` 122 123 // TXChecksumOffload indicates that TX Checksum Offload is enabled. 124 TXChecksumOffload bool `flag:"tx-checksum-offload"` 125 126 // RXChecksumOffload indicates that RX Checksum Offload is enabled. 127 RXChecksumOffload bool `flag:"rx-checksum-offload"` 128 129 // QDisc indicates the type of queuening discipline to use by default 130 // for non-loopback interfaces. 131 QDisc QueueingDiscipline `flag:"qdisc"` 132 133 // LogPackets indicates that all network packets should be logged. 134 LogPackets bool `flag:"log-packets"` 135 136 // PCAP is a file to which network packets should be logged in PCAP format. 137 PCAP string `flag:"pcap-log"` 138 139 // Platform is the platform to run on. 140 Platform string `flag:"platform"` 141 142 // PlatformDevicePath is the path to the device file used by the platform. 143 // e.g. "/dev/kvm" for the KVM platform. 144 // If unset, a sane platform-specific default will be used. 145 PlatformDevicePath string `flag:"platform_device_path"` 146 147 // MetricServer, if set, indicates that metrics should be exported on this address. 148 // This may either be 1) "addr:port" to export metrics on a specific network interface address, 149 // 2) ":port" for exporting metrics on all addresses, or 3) an absolute path to a Unix Domain 150 // Socket. 151 // The substring "%ID%" will be replaced by the container ID, and "%RUNTIME_ROOT%" by the root. 152 // This flag must be specified *both* as part of the `runsc metric-server` arguments (so that the 153 // metric server knows which address to bind to), and as part of the `runsc create` arguments (as 154 // an indication that the container being created wishes that its metrics should be exported). 155 // The value of this flag must also match across the two command lines. 156 MetricServer string `flag:"metric-server"` 157 158 // ProfilingMetrics is a comma separated list of metric names which are 159 // going to be written to the ProfilingMetricsLog file from within the 160 // sentry in CSV format. ProfilingMetrics will be snapshotted at a rate 161 // specified by ProfilingMetricsRate. Requires ProfilingMetricsLog to be 162 // set. 163 ProfilingMetrics string `flag:"profiling-metrics"` 164 165 // ProfilingMetricsLog is the file name to use for ProfilingMetrics 166 // output. 167 ProfilingMetricsLog string `flag:"profiling-metrics-log"` 168 169 // ProfilingMetricsRate is the target rate (in microseconds) at which 170 // profiling metrics will be snapshotted. 171 ProfilingMetricsRate int `flag:"profiling-metrics-rate-us"` 172 173 // Strace indicates that strace should be enabled. 174 Strace bool `flag:"strace"` 175 176 // StraceSyscalls is the set of syscalls to trace (comma-separated values). 177 // If StraceEnable is true and this string is empty, then all syscalls will 178 // be traced. 179 StraceSyscalls string `flag:"strace-syscalls"` 180 181 // StraceLogSize is the max size of data blobs to display. 182 StraceLogSize uint `flag:"strace-log-size"` 183 184 // StraceEvent indicates sending strace to events if true. Strace is 185 // sent to log if false. 186 StraceEvent bool `flag:"strace-event"` 187 188 // DisableSeccomp indicates whether seccomp syscall filters should be 189 // disabled. Pardon the double negation, but default to enabled is important. 190 DisableSeccomp bool 191 192 // EnableCoreTags indicates whether the Sentry process and children will be 193 // run in a core tagged process. This isolates the sentry from sharing 194 // physical cores with other core tagged processes. This is useful as a 195 // mitigation for hyperthreading side channel based attacks. Requires host 196 // linux kernel >= 5.14. 197 EnableCoreTags bool `flag:"enable-core-tags"` 198 199 // WatchdogAction sets what action the watchdog takes when triggered. 200 WatchdogAction watchdog.Action `flag:"watchdog-action"` 201 202 // PanicSignal registers signal handling that panics. Usually set to 203 // SIGUSR2(12) to troubleshoot hangs. -1 disables it. 204 PanicSignal int `flag:"panic-signal"` 205 206 // ProfileEnable is set to prepare the sandbox to be profiled. 207 ProfileEnable bool `flag:"profile"` 208 209 // ProfileBlock collects a block profile to the passed file for the 210 // duration of the container execution. Requires ProfileEnabled. 211 ProfileBlock string `flag:"profile-block"` 212 213 // ProfileCPU collects a CPU profile to the passed file for the 214 // duration of the container execution. Requires ProfileEnabled. 215 ProfileCPU string `flag:"profile-cpu"` 216 217 // ProfileHeap collects a heap profile to the passed file for the 218 // duration of the container execution. Requires ProfileEnabled. 219 ProfileHeap string `flag:"profile-heap"` 220 221 // ProfileMutex collects a mutex profile to the passed file for the 222 // duration of the container execution. Requires ProfileEnabled. 223 ProfileMutex string `flag:"profile-mutex"` 224 225 // TraceFile collects a Go runtime execution trace to the passed file 226 // for the duration of the container execution. 227 TraceFile string `flag:"trace"` 228 229 // RestoreFile is the path to the saved container image. 230 RestoreFile string 231 232 // NumNetworkChannels controls the number of AF_PACKET sockets that map 233 // to the same underlying network device. This allows netstack to better 234 // scale for high throughput use cases. 235 NumNetworkChannels int `flag:"num-network-channels"` 236 237 // Rootless allows the sandbox to be started with a user that is not root. 238 // Defense in depth measures are weaker in rootless mode. Specifically, the 239 // sandbox and Gofer process run as root inside a user namespace with root 240 // mapped to the caller's user. When using rootless, the container root path 241 // should not have a symlink. 242 Rootless bool `flag:"rootless"` 243 244 // AlsoLogToStderr allows to send log messages to stderr. 245 AlsoLogToStderr bool `flag:"alsologtostderr"` 246 247 // ReferenceLeakMode sets reference leak check mode 248 ReferenceLeak refs.LeakMode `flag:"ref-leak-mode"` 249 250 // CPUNumFromQuota sets CPU number count to available CPU quota, using 251 // least integer value greater than or equal to quota. 252 // 253 // E.g. 0.2 CPU quota will result in 1, and 1.9 in 2. 254 CPUNumFromQuota bool `flag:"cpu-num-from-quota"` 255 256 // Allows overriding of flags in OCI annotations. 257 AllowFlagOverride bool `flag:"allow-flag-override"` 258 259 // Enables seccomp inside the sandbox. 260 OCISeccomp bool `flag:"oci-seccomp"` 261 262 // Mounts the cgroup filesystem backed by the sentry's cgroupfs. 263 Cgroupfs bool `flag:"cgroupfs"` 264 265 // Don't configure cgroups. 266 IgnoreCgroups bool `flag:"ignore-cgroups"` 267 268 // Use systemd to configure cgroups. 269 SystemdCgroup bool `flag:"systemd-cgroup"` 270 271 // PodInitConfig is the path to configuration file with additional steps to 272 // take during pod creation. 273 PodInitConfig string `flag:"pod-init-config"` 274 275 // Use pools to manage buffer memory instead of heap. 276 BufferPooling bool `flag:"buffer-pooling"` 277 278 // AFXDP defines whether to use an AF_XDP socket to receive packets 279 // (rather than AF_PACKET). Enabling it disables RX checksum offload. 280 AFXDP bool `flag:"EXPERIMENTAL-afxdp"` 281 282 // FDLimit specifies a limit on the number of host file descriptors that can 283 // be open simultaneously by the sentry and gofer. It applies separately to 284 // each. 285 FDLimit int `flag:"fdlimit"` 286 287 // DCache sets the global dirent cache size. If zero, per-mount caches are 288 // used. 289 DCache int `flag:"dcache"` 290 291 // IOUring enables support for the IO_URING API calls to perform 292 // asynchronous I/O operations. 293 IOUring bool `flag:"iouring"` 294 295 // DirectFS sets up the sandbox to directly access/mutate the filesystem from 296 // the sentry. Sentry runs with escalated privileges. Gofer process still 297 // exists, but is mostly idle. Not supported in rootless mode. 298 DirectFS bool `flag:"directfs"` 299 300 // NVProxy enables support for Nvidia GPUs. 301 NVProxy bool `flag:"nvproxy"` 302 303 // NVProxyDocker exposes GPUs to containers based on the 304 // NVIDIA_VISIBLE_DEVICES container environment variable, as requested by 305 // containers or set by `docker --gpus`. 306 NVProxyDocker bool `flag:"nvproxy-docker"` 307 308 // TPUProxy enables support for TPUs. 309 TPUProxy bool `flag:"tpuproxy"` 310 311 // TestOnlyAllowRunAsCurrentUserWithoutChroot should only be used in 312 // tests. It allows runsc to start the sandbox process as the current 313 // user, and without chrooting the sandbox process. This can be 314 // necessary in test environments that have limited capabilities. When 315 // disabling chroot, the container root path should not have a symlink. 316 TestOnlyAllowRunAsCurrentUserWithoutChroot bool `flag:"TESTONLY-unsafe-nonroot"` 317 318 // TestOnlyTestNameEnv should only be used in tests. It looks up for the 319 // test name in the container environment variables and adds it to the debug 320 // log file name. This is done to help identify the log with the test when 321 // multiple tests are run in parallel, since there is no way to pass 322 // parameters to the runtime from docker. 323 TestOnlyTestNameEnv string `flag:"TESTONLY-test-name-env"` 324 325 // TestOnlyAFSSyscallPanic should only be used in tests. It enables the 326 // alternate behaviour for afs_syscall to trigger a Go-runtime panic upon being 327 // called. This is useful for tests exercising gVisor panic-reporting. 328 TestOnlyAFSSyscallPanic bool `flag:"TESTONLY-afs-syscall-panic"` 329 330 // explicitlySet contains whether a flag was explicitly set on the command-line from which this 331 // Config was constructed. Nil when the Config was not initialized from a FlagSet. 332 explicitlySet map[string]struct{} 333 } 334 335 func (c *Config) validate() error { 336 if c.Overlay && c.Overlay2.Enabled() { 337 // Deprecated flag was used together with flag that replaced it. 338 return fmt.Errorf("overlay flag has been replaced with overlay2 flag") 339 } 340 if overlay2 := c.GetOverlay2(); c.FileAccess == FileAccessShared && overlay2.Enabled() { 341 return fmt.Errorf("overlay flag is incompatible with shared file access for rootfs") 342 } 343 if c.NumNetworkChannels <= 0 { 344 return fmt.Errorf("num_network_channels must be > 0, got: %d", c.NumNetworkChannels) 345 } 346 // Require profile flags to explicitly opt-in to profiling with 347 // -profile rather than implying it since these options have security 348 // implications. 349 if c.ProfileBlock != "" && !c.ProfileEnable { 350 return fmt.Errorf("profile-block flag requires enabling profiling with profile flag") 351 } 352 if c.ProfileCPU != "" && !c.ProfileEnable { 353 return fmt.Errorf("profile-cpu flag requires enabling profiling with profile flag") 354 } 355 if c.ProfileHeap != "" && !c.ProfileEnable { 356 return fmt.Errorf("profile-heap flag requires enabling profiling with profile flag") 357 } 358 if c.ProfileMutex != "" && !c.ProfileEnable { 359 return fmt.Errorf("profile-mutex flag requires enabling profiling with profile flag") 360 } 361 if c.FSGoferHostUDS && c.HostUDS != HostUDSNone { 362 // Deprecated flag was used together with flag that replaced it. 363 return fmt.Errorf("fsgofer-host-uds has been replaced with host-uds flag") 364 } 365 if len(c.ProfilingMetrics) > 0 && len(c.ProfilingMetricsLog) == 0 { 366 return fmt.Errorf("profiling-metrics flag requires defining a profiling-metrics-log for output") 367 } 368 return nil 369 } 370 371 // GetHostUDS returns the FS gofer communication that is allowed, taking into 372 // consideration all flags what affect the result. 373 func (c *Config) GetHostUDS() HostUDS { 374 if c.FSGoferHostUDS { 375 if c.HostUDS != HostUDSNone { 376 panic(fmt.Sprintf("HostUDS cannot be set when --fsgofer-host-uds=true")) 377 } 378 // Using deprecated flag, honor it to avoid breaking users. 379 return HostUDSOpen 380 } 381 return c.HostUDS 382 } 383 384 // GetOverlay2 returns the overlay configuration, taking into consideration all 385 // flags that affect the result. 386 func (c *Config) GetOverlay2() Overlay2 { 387 if c.Overlay { 388 if c.Overlay2.Enabled() { 389 panic(fmt.Sprintf("Overlay2 cannot be set when --overlay=true")) 390 } 391 // Using a deprecated flag, honor it to avoid breaking users. 392 return Overlay2{rootMount: true, subMounts: true, medium: "memory"} 393 } 394 return c.Overlay2 395 } 396 397 // Bundle is a set of flag name-value pairs. 398 type Bundle map[string]string 399 400 // BundleName is a human-friendly name for a Bundle. 401 // It is used as part of an annotation to specify that the user wants to apply a Bundle. 402 type BundleName string 403 404 // Validate validates that given flag string values map to actual flags in runsc. 405 func (b Bundle) Validate() error { 406 flagSet := flag.NewFlagSet("tmp", flag.ContinueOnError) 407 RegisterFlags(flagSet) 408 for key, val := range b { 409 flag := flagSet.Lookup(key) 410 if flag == nil { 411 return fmt.Errorf("unknown flag %q", key) 412 } 413 if err := flagSet.Set(key, val); err != nil { 414 return err 415 } 416 } 417 return nil 418 } 419 420 // MetricMetadataKeys is the set of keys of metric metadata labels 421 // as returned by `Config.MetricMetadata`. 422 var MetricMetadataKeys = []string{ 423 "version", 424 "platform", 425 "network", 426 "numcores", 427 "coretags", 428 "overlay", 429 "fsmode", 430 "cpuarch", 431 "go", 432 "experiment", 433 } 434 435 // MetricMetadata returns key-value pairs that are useful to include in metrics 436 // exported about the sandbox this config represents. 437 // It must return the same set of labels as listed in `MetricMetadataKeys`. 438 func (c *Config) MetricMetadata() map[string]string { 439 var fsMode = "goferfs" 440 if c.DirectFS { 441 fsMode = "directfs" 442 } 443 return map[string]string{ 444 "version": version.Version(), 445 "platform": c.Platform, 446 "network": c.Network.String(), 447 "numcores": strconv.Itoa(runtime.NumCPU()), 448 "coretags": strconv.FormatBool(c.EnableCoreTags), 449 "overlay": c.Overlay2.String(), 450 "fsmode": fsMode, 451 "cpuarch": runtime.GOARCH, 452 "go": runtime.Version(), 453 // The "experiment" label is currently unused, but may be used to contain 454 // extra information about e.g. an experiment that may be enabled. 455 "experiment": "", 456 } 457 } 458 459 // FileAccessType tells how the filesystem is accessed. 460 type FileAccessType int 461 462 const ( 463 // FileAccessExclusive gives the sandbox exclusive access over files and 464 // directories in the filesystem. No external modifications are permitted and 465 // can lead to undefined behavior. 466 // 467 // Exclusive filesystem access enables more aggressive caching and offers 468 // significantly better performance. This is the default mode for the root 469 // volume. 470 FileAccessExclusive FileAccessType = iota 471 472 // FileAccessShared is used for volumes that can have external changes. It 473 // requires revalidation on every filesystem access to detect external 474 // changes, and reduces the amount of caching that can be done. This is the 475 // default mode for non-root volumes. 476 FileAccessShared 477 ) 478 479 func fileAccessTypePtr(v FileAccessType) *FileAccessType { 480 return &v 481 } 482 483 // Set implements flag.Value. Set(String()) should be idempotent. 484 func (f *FileAccessType) Set(v string) error { 485 switch v { 486 case "shared": 487 *f = FileAccessShared 488 case "exclusive": 489 *f = FileAccessExclusive 490 default: 491 return fmt.Errorf("invalid file access type %q", v) 492 } 493 return nil 494 } 495 496 // Get implements flag.Value. 497 func (f *FileAccessType) Get() any { 498 return *f 499 } 500 501 // String implements flag.Value. 502 func (f FileAccessType) String() string { 503 switch f { 504 case FileAccessShared: 505 return "shared" 506 case FileAccessExclusive: 507 return "exclusive" 508 } 509 panic(fmt.Sprintf("Invalid file access type %d", f)) 510 } 511 512 // NetworkType tells which network stack to use. 513 type NetworkType int 514 515 const ( 516 // NetworkSandbox uses internal network stack, isolated from the host. 517 NetworkSandbox NetworkType = iota 518 519 // NetworkHost redirects network related syscalls to the host network. 520 NetworkHost 521 522 // NetworkNone sets up just loopback using netstack. 523 NetworkNone 524 ) 525 526 func networkTypePtr(v NetworkType) *NetworkType { 527 return &v 528 } 529 530 // Set implements flag.Value. Set(String()) should be idempotent. 531 func (n *NetworkType) Set(v string) error { 532 switch v { 533 case "sandbox": 534 *n = NetworkSandbox 535 case "host": 536 *n = NetworkHost 537 case "none": 538 *n = NetworkNone 539 default: 540 return fmt.Errorf("invalid network type %q", v) 541 } 542 return nil 543 } 544 545 // Get implements flag.Value. 546 func (n *NetworkType) Get() any { 547 return *n 548 } 549 550 // String implements flag.Value. 551 func (n NetworkType) String() string { 552 switch n { 553 case NetworkSandbox: 554 return "sandbox" 555 case NetworkHost: 556 return "host" 557 case NetworkNone: 558 return "none" 559 } 560 panic(fmt.Sprintf("Invalid network type %d", n)) 561 } 562 563 // QueueingDiscipline is used to specify the kind of Queueing Discipline to 564 // apply for a give FDBasedLink. 565 type QueueingDiscipline int 566 567 const ( 568 // QDiscNone disables any queueing for the underlying FD. 569 QDiscNone QueueingDiscipline = iota 570 571 // QDiscFIFO applies a simple fifo based queue to the underlying FD. 572 QDiscFIFO 573 ) 574 575 func queueingDisciplinePtr(v QueueingDiscipline) *QueueingDiscipline { 576 return &v 577 } 578 579 // Set implements flag.Value. Set(String()) should be idempotent. 580 func (q *QueueingDiscipline) Set(v string) error { 581 switch v { 582 case "none": 583 *q = QDiscNone 584 case "fifo": 585 *q = QDiscFIFO 586 default: 587 return fmt.Errorf("invalid qdisc %q", v) 588 } 589 return nil 590 } 591 592 // Get implements flag.Value. 593 func (q *QueueingDiscipline) Get() any { 594 return *q 595 } 596 597 // String implements flag.Value. 598 func (q QueueingDiscipline) String() string { 599 switch q { 600 case QDiscNone: 601 return "none" 602 case QDiscFIFO: 603 return "fifo" 604 } 605 panic(fmt.Sprintf("Invalid qdisc %d", q)) 606 } 607 608 func leakModePtr(v refs.LeakMode) *refs.LeakMode { 609 return &v 610 } 611 612 func watchdogActionPtr(v watchdog.Action) *watchdog.Action { 613 return &v 614 } 615 616 // HostUDS tells how much of the host UDS the file system has access to. 617 type HostUDS int 618 619 const ( 620 // HostUDSNone doesn't allows UDS from the host to be manipulated. 621 HostUDSNone HostUDS = 0x0 622 623 // HostUDSOpen allows UDS from the host to be opened, e.g. connect(2). 624 HostUDSOpen HostUDS = 0x1 625 626 // HostUDSCreate allows UDS from the host to be created, e.g. bind(2). 627 HostUDSCreate HostUDS = 0x2 628 629 // HostUDSAll allows all form of communication with the host through UDS. 630 HostUDSAll = HostUDSOpen | HostUDSCreate 631 ) 632 633 func hostUDSPtr(v HostUDS) *HostUDS { 634 return &v 635 } 636 637 // Set implements flag.Value. Set(String()) should be idempotent. 638 func (g *HostUDS) Set(v string) error { 639 switch v { 640 case "", "none": 641 *g = HostUDSNone 642 case "open": 643 *g = HostUDSOpen 644 case "create": 645 *g = HostUDSCreate 646 case "all": 647 *g = HostUDSAll 648 default: 649 return fmt.Errorf("invalid host UDS type %q", v) 650 } 651 return nil 652 } 653 654 // Get implements flag.Value. 655 func (g *HostUDS) Get() any { 656 return *g 657 } 658 659 // String implements flag.Value. 660 func (g HostUDS) String() string { 661 switch g { 662 case HostUDSNone: 663 return "none" 664 case HostUDSOpen: 665 return "open" 666 case HostUDSCreate: 667 return "create" 668 case HostUDSAll: 669 return "all" 670 default: 671 panic(fmt.Sprintf("Invalid host UDS type %d", g)) 672 } 673 } 674 675 // AllowOpen returns true if it can consume UDS from the host. 676 func (g HostUDS) AllowOpen() bool { 677 return g&HostUDSOpen != 0 678 } 679 680 // AllowCreate returns true if it can create UDS in the host. 681 func (g HostUDS) AllowCreate() bool { 682 return g&HostUDSCreate != 0 683 } 684 685 // HostFifo tells how much of the host FIFO (or named pipes) the file system has 686 // access to. 687 type HostFifo int 688 689 const ( 690 // HostFifoNone doesn't allow FIFO from the host to be manipulated. 691 HostFifoNone HostFifo = 0x0 692 693 // HostFifoOpen allows FIFOs from the host to be opened. 694 HostFifoOpen HostFifo = 0x1 695 ) 696 697 func hostFifoPtr(v HostFifo) *HostFifo { 698 return &v 699 } 700 701 // Set implements flag.Value. Set(String()) should be idempotent. 702 func (g *HostFifo) Set(v string) error { 703 switch v { 704 case "", "none": 705 *g = HostFifoNone 706 case "open": 707 *g = HostFifoOpen 708 default: 709 return fmt.Errorf("invalid host fifo type %q", v) 710 } 711 return nil 712 } 713 714 // Get implements flag.Value. 715 func (g *HostFifo) Get() any { 716 return *g 717 } 718 719 // String implements flag.Value. 720 func (g HostFifo) String() string { 721 switch g { 722 case HostFifoNone: 723 return "none" 724 case HostFifoOpen: 725 return "open" 726 default: 727 panic(fmt.Sprintf("Invalid host fifo type %d", g)) 728 } 729 } 730 731 // AllowOpen returns true if it can consume FIFOs from the host. 732 func (g HostFifo) AllowOpen() bool { 733 return g&HostFifoOpen != 0 734 } 735 736 // Overlay2 holds the configuration for setting up overlay filesystems for the 737 // container. 738 type Overlay2 struct { 739 rootMount bool 740 subMounts bool 741 medium string 742 } 743 744 func defaultOverlay2() *Overlay2 { 745 // Rootfs overlay is enabled by default and backed by a file in rootfs itself. 746 return &Overlay2{rootMount: true, subMounts: false, medium: "self"} 747 } 748 749 // Set implements flag.Value. Set(String()) should be idempotent. 750 func (o *Overlay2) Set(v string) error { 751 if v == "none" { 752 o.rootMount = false 753 o.subMounts = false 754 o.medium = "" 755 return nil 756 } 757 vs := strings.Split(v, ":") 758 if len(vs) != 2 { 759 return fmt.Errorf("expected format is --overlay2={mount}:{medium}, got %q", v) 760 } 761 762 switch mount := vs[0]; mount { 763 case "root": 764 o.rootMount = true 765 case "all": 766 o.rootMount = true 767 o.subMounts = true 768 default: 769 return fmt.Errorf("unexpected mount specifier for --overlay2: %q", mount) 770 } 771 772 o.medium = vs[1] 773 switch o.medium { 774 case "memory", "self": // OK 775 default: 776 if !strings.HasPrefix(o.medium, "dir=") { 777 return fmt.Errorf("unexpected medium specifier for --overlay2: %q", o.medium) 778 } 779 if hostFileDir := strings.TrimPrefix(o.medium, "dir="); !filepath.IsAbs(hostFileDir) { 780 return fmt.Errorf("overlay host file directory should be an absolute path, got %q", hostFileDir) 781 } 782 } 783 return nil 784 } 785 786 // Get implements flag.Value. 787 func (o *Overlay2) Get() any { 788 return *o 789 } 790 791 // String implements flag.Value. 792 func (o Overlay2) String() string { 793 if !o.rootMount && !o.subMounts { 794 return "none" 795 } 796 res := "" 797 switch { 798 case o.rootMount && o.subMounts: 799 res = "all" 800 case o.rootMount: 801 res = "root" 802 default: 803 panic("invalid state of subMounts = true and rootMount = false") 804 } 805 806 return res + ":" + o.medium 807 } 808 809 // Enabled returns true if the overlay option is enabled for any mounts. 810 func (o *Overlay2) Enabled() bool { 811 return o.rootMount || o.subMounts 812 } 813 814 // RootEnabled returns true if the overlay is enabled for the root mount. 815 func (o *Overlay2) RootEnabled() bool { 816 return o.rootMount 817 } 818 819 // SubMountEnabled returns true if the overlay is enabled for submounts. 820 func (o *Overlay2) SubMountEnabled() bool { 821 return o.subMounts 822 } 823 824 // IsBackedByMemory indicates whether the overlay is backed by app memory. 825 func (o *Overlay2) IsBackedByMemory() bool { 826 return o.Enabled() && o.medium == "memory" 827 } 828 829 // IsBackedBySelf indicates whether the overlaid mounts are backed by 830 // themselves. 831 func (o *Overlay2) IsBackedBySelf() bool { 832 return o.Enabled() && o.medium == "self" 833 } 834 835 // HostFileDir indicates the directory in which the overlay-backing host file 836 // should be created. 837 // 838 // Precondition: o.IsBackedByHostFile() && !o.IsBackedBySelf(). 839 func (o *Overlay2) HostFileDir() string { 840 if !strings.HasPrefix(o.medium, "dir=") { 841 panic(fmt.Sprintf("Overlay2.Medium = %q does not have dir= prefix when overlay is backed by a host file", o.medium)) 842 } 843 hostFileDir := strings.TrimPrefix(o.medium, "dir=") 844 if !filepath.IsAbs(hostFileDir) { 845 panic(fmt.Sprintf("overlay host file directory should be an absolute path, got %q", hostFileDir)) 846 } 847 return hostFileDir 848 }