From 0166feef2a0205967eb95867a7d953f9171b27b7 Mon Sep 17 00:00:00 2001
From: Doug Rabson <dfr@rabson.org>
Date: Fri, 26 Aug 2022 08:33:18 +0100
Subject: specgen/generate: Move security.go to security_linux.go and add stubs

The security features (selinux, apparmor, capabilities) are linux
specific.

[NO NEW TESTS NEEDED]

Signed-off-by: Doug Rabson <dfr@rabson.org>
---
 pkg/specgen/generate/security.go             | 265 ---------------------------
 pkg/specgen/generate/security_linux.go       | 265 +++++++++++++++++++++++++++
 pkg/specgen/generate/security_unsupported.go |  24 +++
 3 files changed, 289 insertions(+), 265 deletions(-)
 delete mode 100644 pkg/specgen/generate/security.go
 create mode 100644 pkg/specgen/generate/security_linux.go
 create mode 100644 pkg/specgen/generate/security_unsupported.go

(limited to 'pkg/specgen')

diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go
deleted file mode 100644
index aacefcbac..000000000
--- a/pkg/specgen/generate/security.go
+++ /dev/null
@@ -1,265 +0,0 @@
-package generate
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/containers/common/libimage"
-	"github.com/containers/common/pkg/apparmor"
-	"github.com/containers/common/pkg/capabilities"
-	"github.com/containers/common/pkg/config"
-	cutil "github.com/containers/common/pkg/util"
-	"github.com/containers/podman/v4/libpod"
-	"github.com/containers/podman/v4/libpod/define"
-	"github.com/containers/podman/v4/pkg/specgen"
-	"github.com/containers/podman/v4/pkg/util"
-	"github.com/opencontainers/runtime-tools/generate"
-	"github.com/opencontainers/selinux/go-selinux/label"
-	"github.com/sirupsen/logrus"
-)
-
-// setLabelOpts sets the label options of the SecurityConfig according to the
-// input.
-func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
-	if !runtime.EnableLabeling() || s.Privileged {
-		s.SelinuxOpts = label.DisableSecOpt()
-		return nil
-	}
-
-	var labelOpts []string
-	if pidConfig.IsHost() {
-		labelOpts = append(labelOpts, label.DisableSecOpt()...)
-	} else if pidConfig.IsContainer() {
-		ctr, err := runtime.LookupContainer(pidConfig.Value)
-		if err != nil {
-			return fmt.Errorf("container %q not found: %w", pidConfig.Value, err)
-		}
-		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
-		if err != nil {
-			return fmt.Errorf("failed to duplicate label %q : %w", ctr.ProcessLabel(), err)
-		}
-		labelOpts = append(labelOpts, secopts...)
-	}
-
-	if ipcConfig.IsHost() {
-		labelOpts = append(labelOpts, label.DisableSecOpt()...)
-	} else if ipcConfig.IsContainer() {
-		ctr, err := runtime.LookupContainer(ipcConfig.Value)
-		if err != nil {
-			return fmt.Errorf("container %q not found: %w", ipcConfig.Value, err)
-		}
-		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
-		if err != nil {
-			return fmt.Errorf("failed to duplicate label %q : %w", ctr.ProcessLabel(), err)
-		}
-		labelOpts = append(labelOpts, secopts...)
-	}
-
-	s.SelinuxOpts = append(s.SelinuxOpts, labelOpts...)
-	return nil
-}
-
-func setupApparmor(s *specgen.SpecGenerator, rtc *config.Config, g *generate.Generator) error {
-	hasProfile := len(s.ApparmorProfile) > 0
-	if !apparmor.IsEnabled() {
-		if hasProfile && s.ApparmorProfile != "unconfined" {
-			return fmt.Errorf("apparmor profile %q specified, but Apparmor is not enabled on this system", s.ApparmorProfile)
-		}
-		return nil
-	}
-	// If privileged and caller did not specify apparmor profiles return
-	if s.Privileged && !hasProfile {
-		return nil
-	}
-	if !hasProfile {
-		s.ApparmorProfile = rtc.Containers.ApparmorProfile
-	}
-	if len(s.ApparmorProfile) > 0 {
-		g.SetProcessApparmorProfile(s.ApparmorProfile)
-	}
-
-	return nil
-}
-
-func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
-	var (
-		caplist []string
-		err     error
-	)
-	// HANDLE CAPABILITIES
-	// NOTE: Must happen before SECCOMP
-	if s.Privileged {
-		g.SetupPrivileged(true)
-		caplist, err = capabilities.BoundingSet()
-		if err != nil {
-			return err
-		}
-	} else {
-		mergedCaps, err := capabilities.MergeCapabilities(rtc.Containers.DefaultCapabilities, s.CapAdd, s.CapDrop)
-		if err != nil {
-			return err
-		}
-		boundingSet, err := capabilities.BoundingSet()
-		if err != nil {
-			return err
-		}
-		boundingCaps := make(map[string]interface{})
-		for _, b := range boundingSet {
-			boundingCaps[b] = b
-		}
-		for _, c := range mergedCaps {
-			if _, ok := boundingCaps[c]; ok {
-				caplist = append(caplist, c)
-			}
-		}
-
-		privCapsRequired := []string{}
-
-		// If the container image specifies an label with a
-		// capabilities.ContainerImageLabel then split the comma separated list
-		// of capabilities and record them.  This list indicates the only
-		// capabilities, required to run the container.
-		var capsRequiredRequested []string
-		for key, val := range s.Labels {
-			if cutil.StringInSlice(key, capabilities.ContainerImageLabels) {
-				capsRequiredRequested = strings.Split(val, ",")
-			}
-		}
-		if !s.Privileged && len(capsRequiredRequested) > 0 {
-			// Pass capRequiredRequested in CapAdd field to normalize capabilities names
-			capsRequired, err := capabilities.MergeCapabilities(nil, capsRequiredRequested, nil)
-			if err != nil {
-				return fmt.Errorf("capabilities requested by user or image are not valid: %q: %w", strings.Join(capsRequired, ","), err)
-			}
-			// Verify all capRequired are in the capList
-			for _, cap := range capsRequired {
-				if !cutil.StringInSlice(cap, caplist) {
-					privCapsRequired = append(privCapsRequired, cap)
-				}
-			}
-			if len(privCapsRequired) == 0 {
-				caplist = capsRequired
-			} else {
-				logrus.Errorf("Capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ","))
-			}
-		}
-	}
-
-	configSpec := g.Config
-	configSpec.Process.Capabilities.Ambient = []string{}
-
-	// Always unset the inheritable capabilities similarly to what the Linux kernel does
-	// They are used only when using capabilities with uid != 0.
-	configSpec.Process.Capabilities.Inheritable = []string{}
-	configSpec.Process.Capabilities.Bounding = caplist
-
-	user := strings.Split(s.User, ":")[0]
-
-	if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" {
-		configSpec.Process.Capabilities.Effective = caplist
-		configSpec.Process.Capabilities.Permitted = caplist
-	} else {
-		mergedCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
-		if err != nil {
-			return fmt.Errorf("capabilities requested by user are not valid: %q: %w", strings.Join(s.CapAdd, ","), err)
-		}
-		boundingSet, err := capabilities.BoundingSet()
-		if err != nil {
-			return err
-		}
-		boundingCaps := make(map[string]interface{})
-		for _, b := range boundingSet {
-			boundingCaps[b] = b
-		}
-		var userCaps []string
-		for _, c := range mergedCaps {
-			if _, ok := boundingCaps[c]; ok {
-				userCaps = append(userCaps, c)
-			}
-		}
-		configSpec.Process.Capabilities.Effective = userCaps
-		configSpec.Process.Capabilities.Permitted = userCaps
-
-		// Ambient capabilities were added to Linux 4.3.  Set ambient
-		// capabilities only when the kernel supports them.
-		if supportAmbientCapabilities() {
-			configSpec.Process.Capabilities.Ambient = userCaps
-			configSpec.Process.Capabilities.Inheritable = userCaps
-		}
-	}
-
-	g.SetProcessNoNewPrivileges(s.NoNewPrivileges)
-
-	if err := setupApparmor(s, rtc, g); err != nil {
-		return err
-	}
-
-	// HANDLE SECCOMP
-	if s.SeccompProfilePath != "unconfined" {
-		seccompConfig, err := getSeccompConfig(s, configSpec, newImage)
-		if err != nil {
-			return err
-		}
-		configSpec.Linux.Seccomp = seccompConfig
-	}
-
-	// Clear default Seccomp profile from Generator for unconfined containers
-	// and privileged containers which do not specify a seccomp profile.
-	if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == "" || s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) {
-		configSpec.Linux.Seccomp = nil
-	}
-
-	g.SetRootReadonly(s.ReadOnlyFilesystem)
-
-	noUseIPC := s.IpcNS.NSMode == specgen.FromContainer || s.IpcNS.NSMode == specgen.FromPod || s.IpcNS.NSMode == specgen.Host
-	noUseNet := s.NetNS.NSMode == specgen.FromContainer || s.NetNS.NSMode == specgen.FromPod || s.NetNS.NSMode == specgen.Host
-	noUseUTS := s.UtsNS.NSMode == specgen.FromContainer || s.UtsNS.NSMode == specgen.FromPod || s.UtsNS.NSMode == specgen.Host
-
-	// Add default sysctls
-	defaultSysctls, err := util.ValidateSysctls(rtc.Sysctls())
-	if err != nil {
-		return err
-	}
-	for sysctlKey, sysctlVal := range defaultSysctls {
-		// Ignore mqueue sysctls if --ipc=host
-		if noUseIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
-			logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to %q", sysctlKey, sysctlVal, s.IpcNS.NSMode)
-
-			continue
-		}
-
-		// Ignore net sysctls if --net=host
-		if noUseNet && strings.HasPrefix(sysctlKey, "net.") {
-			logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctlKey, sysctlVal)
-			continue
-		}
-
-		// Ignore uts sysctls if --uts=host
-		if noUseUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
-			logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace set to host", sysctlKey, sysctlVal)
-			continue
-		}
-
-		g.AddLinuxSysctl(sysctlKey, sysctlVal)
-	}
-
-	for sysctlKey, sysctlVal := range s.Sysctl {
-		if s.IpcNS.IsHost() && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
-			return fmt.Errorf("sysctl %s=%s can't be set since IPC Namespace set to host: %w", sysctlKey, sysctlVal, define.ErrInvalidArg)
-		}
-
-		// Ignore net sysctls if --net=host
-		if s.NetNS.IsHost() && strings.HasPrefix(sysctlKey, "net.") {
-			return fmt.Errorf("sysctl %s=%s can't be set since Network Namespace set to host: %w", sysctlKey, sysctlVal, define.ErrInvalidArg)
-		}
-
-		// Ignore uts sysctls if --uts=host
-		if s.UtsNS.IsHost() && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
-			return fmt.Errorf("sysctl %s=%s can't be set since UTS Namespace set to host: %w", sysctlKey, sysctlVal, define.ErrInvalidArg)
-		}
-
-		g.AddLinuxSysctl(sysctlKey, sysctlVal)
-	}
-
-	return nil
-}
diff --git a/pkg/specgen/generate/security_linux.go b/pkg/specgen/generate/security_linux.go
new file mode 100644
index 000000000..aacefcbac
--- /dev/null
+++ b/pkg/specgen/generate/security_linux.go
@@ -0,0 +1,265 @@
+package generate
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/apparmor"
+	"github.com/containers/common/pkg/capabilities"
+	"github.com/containers/common/pkg/config"
+	cutil "github.com/containers/common/pkg/util"
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/libpod/define"
+	"github.com/containers/podman/v4/pkg/specgen"
+	"github.com/containers/podman/v4/pkg/util"
+	"github.com/opencontainers/runtime-tools/generate"
+	"github.com/opencontainers/selinux/go-selinux/label"
+	"github.com/sirupsen/logrus"
+)
+
+// setLabelOpts sets the label options of the SecurityConfig according to the
+// input.
+func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
+	if !runtime.EnableLabeling() || s.Privileged {
+		s.SelinuxOpts = label.DisableSecOpt()
+		return nil
+	}
+
+	var labelOpts []string
+	if pidConfig.IsHost() {
+		labelOpts = append(labelOpts, label.DisableSecOpt()...)
+	} else if pidConfig.IsContainer() {
+		ctr, err := runtime.LookupContainer(pidConfig.Value)
+		if err != nil {
+			return fmt.Errorf("container %q not found: %w", pidConfig.Value, err)
+		}
+		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
+		if err != nil {
+			return fmt.Errorf("failed to duplicate label %q : %w", ctr.ProcessLabel(), err)
+		}
+		labelOpts = append(labelOpts, secopts...)
+	}
+
+	if ipcConfig.IsHost() {
+		labelOpts = append(labelOpts, label.DisableSecOpt()...)
+	} else if ipcConfig.IsContainer() {
+		ctr, err := runtime.LookupContainer(ipcConfig.Value)
+		if err != nil {
+			return fmt.Errorf("container %q not found: %w", ipcConfig.Value, err)
+		}
+		secopts, err := label.DupSecOpt(ctr.ProcessLabel())
+		if err != nil {
+			return fmt.Errorf("failed to duplicate label %q : %w", ctr.ProcessLabel(), err)
+		}
+		labelOpts = append(labelOpts, secopts...)
+	}
+
+	s.SelinuxOpts = append(s.SelinuxOpts, labelOpts...)
+	return nil
+}
+
+func setupApparmor(s *specgen.SpecGenerator, rtc *config.Config, g *generate.Generator) error {
+	hasProfile := len(s.ApparmorProfile) > 0
+	if !apparmor.IsEnabled() {
+		if hasProfile && s.ApparmorProfile != "unconfined" {
+			return fmt.Errorf("apparmor profile %q specified, but Apparmor is not enabled on this system", s.ApparmorProfile)
+		}
+		return nil
+	}
+	// If privileged and caller did not specify apparmor profiles return
+	if s.Privileged && !hasProfile {
+		return nil
+	}
+	if !hasProfile {
+		s.ApparmorProfile = rtc.Containers.ApparmorProfile
+	}
+	if len(s.ApparmorProfile) > 0 {
+		g.SetProcessApparmorProfile(s.ApparmorProfile)
+	}
+
+	return nil
+}
+
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
+	var (
+		caplist []string
+		err     error
+	)
+	// HANDLE CAPABILITIES
+	// NOTE: Must happen before SECCOMP
+	if s.Privileged {
+		g.SetupPrivileged(true)
+		caplist, err = capabilities.BoundingSet()
+		if err != nil {
+			return err
+		}
+	} else {
+		mergedCaps, err := capabilities.MergeCapabilities(rtc.Containers.DefaultCapabilities, s.CapAdd, s.CapDrop)
+		if err != nil {
+			return err
+		}
+		boundingSet, err := capabilities.BoundingSet()
+		if err != nil {
+			return err
+		}
+		boundingCaps := make(map[string]interface{})
+		for _, b := range boundingSet {
+			boundingCaps[b] = b
+		}
+		for _, c := range mergedCaps {
+			if _, ok := boundingCaps[c]; ok {
+				caplist = append(caplist, c)
+			}
+		}
+
+		privCapsRequired := []string{}
+
+		// If the container image specifies an label with a
+		// capabilities.ContainerImageLabel then split the comma separated list
+		// of capabilities and record them.  This list indicates the only
+		// capabilities, required to run the container.
+		var capsRequiredRequested []string
+		for key, val := range s.Labels {
+			if cutil.StringInSlice(key, capabilities.ContainerImageLabels) {
+				capsRequiredRequested = strings.Split(val, ",")
+			}
+		}
+		if !s.Privileged && len(capsRequiredRequested) > 0 {
+			// Pass capRequiredRequested in CapAdd field to normalize capabilities names
+			capsRequired, err := capabilities.MergeCapabilities(nil, capsRequiredRequested, nil)
+			if err != nil {
+				return fmt.Errorf("capabilities requested by user or image are not valid: %q: %w", strings.Join(capsRequired, ","), err)
+			}
+			// Verify all capRequired are in the capList
+			for _, cap := range capsRequired {
+				if !cutil.StringInSlice(cap, caplist) {
+					privCapsRequired = append(privCapsRequired, cap)
+				}
+			}
+			if len(privCapsRequired) == 0 {
+				caplist = capsRequired
+			} else {
+				logrus.Errorf("Capabilities requested by user or image are not allowed by default: %q", strings.Join(privCapsRequired, ","))
+			}
+		}
+	}
+
+	configSpec := g.Config
+	configSpec.Process.Capabilities.Ambient = []string{}
+
+	// Always unset the inheritable capabilities similarly to what the Linux kernel does
+	// They are used only when using capabilities with uid != 0.
+	configSpec.Process.Capabilities.Inheritable = []string{}
+	configSpec.Process.Capabilities.Bounding = caplist
+
+	user := strings.Split(s.User, ":")[0]
+
+	if (user == "" && s.UserNS.NSMode != specgen.KeepID) || user == "root" || user == "0" {
+		configSpec.Process.Capabilities.Effective = caplist
+		configSpec.Process.Capabilities.Permitted = caplist
+	} else {
+		mergedCaps, err := capabilities.MergeCapabilities(nil, s.CapAdd, nil)
+		if err != nil {
+			return fmt.Errorf("capabilities requested by user are not valid: %q: %w", strings.Join(s.CapAdd, ","), err)
+		}
+		boundingSet, err := capabilities.BoundingSet()
+		if err != nil {
+			return err
+		}
+		boundingCaps := make(map[string]interface{})
+		for _, b := range boundingSet {
+			boundingCaps[b] = b
+		}
+		var userCaps []string
+		for _, c := range mergedCaps {
+			if _, ok := boundingCaps[c]; ok {
+				userCaps = append(userCaps, c)
+			}
+		}
+		configSpec.Process.Capabilities.Effective = userCaps
+		configSpec.Process.Capabilities.Permitted = userCaps
+
+		// Ambient capabilities were added to Linux 4.3.  Set ambient
+		// capabilities only when the kernel supports them.
+		if supportAmbientCapabilities() {
+			configSpec.Process.Capabilities.Ambient = userCaps
+			configSpec.Process.Capabilities.Inheritable = userCaps
+		}
+	}
+
+	g.SetProcessNoNewPrivileges(s.NoNewPrivileges)
+
+	if err := setupApparmor(s, rtc, g); err != nil {
+		return err
+	}
+
+	// HANDLE SECCOMP
+	if s.SeccompProfilePath != "unconfined" {
+		seccompConfig, err := getSeccompConfig(s, configSpec, newImage)
+		if err != nil {
+			return err
+		}
+		configSpec.Linux.Seccomp = seccompConfig
+	}
+
+	// Clear default Seccomp profile from Generator for unconfined containers
+	// and privileged containers which do not specify a seccomp profile.
+	if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == "" || s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) {
+		configSpec.Linux.Seccomp = nil
+	}
+
+	g.SetRootReadonly(s.ReadOnlyFilesystem)
+
+	noUseIPC := s.IpcNS.NSMode == specgen.FromContainer || s.IpcNS.NSMode == specgen.FromPod || s.IpcNS.NSMode == specgen.Host
+	noUseNet := s.NetNS.NSMode == specgen.FromContainer || s.NetNS.NSMode == specgen.FromPod || s.NetNS.NSMode == specgen.Host
+	noUseUTS := s.UtsNS.NSMode == specgen.FromContainer || s.UtsNS.NSMode == specgen.FromPod || s.UtsNS.NSMode == specgen.Host
+
+	// Add default sysctls
+	defaultSysctls, err := util.ValidateSysctls(rtc.Sysctls())
+	if err != nil {
+		return err
+	}
+	for sysctlKey, sysctlVal := range defaultSysctls {
+		// Ignore mqueue sysctls if --ipc=host
+		if noUseIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
+			logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to %q", sysctlKey, sysctlVal, s.IpcNS.NSMode)
+
+			continue
+		}
+
+		// Ignore net sysctls if --net=host
+		if noUseNet && strings.HasPrefix(sysctlKey, "net.") {
+			logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctlKey, sysctlVal)
+			continue
+		}
+
+		// Ignore uts sysctls if --uts=host
+		if noUseUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
+			logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace set to host", sysctlKey, sysctlVal)
+			continue
+		}
+
+		g.AddLinuxSysctl(sysctlKey, sysctlVal)
+	}
+
+	for sysctlKey, sysctlVal := range s.Sysctl {
+		if s.IpcNS.IsHost() && strings.HasPrefix(sysctlKey, "fs.mqueue.") {
+			return fmt.Errorf("sysctl %s=%s can't be set since IPC Namespace set to host: %w", sysctlKey, sysctlVal, define.ErrInvalidArg)
+		}
+
+		// Ignore net sysctls if --net=host
+		if s.NetNS.IsHost() && strings.HasPrefix(sysctlKey, "net.") {
+			return fmt.Errorf("sysctl %s=%s can't be set since Network Namespace set to host: %w", sysctlKey, sysctlVal, define.ErrInvalidArg)
+		}
+
+		// Ignore uts sysctls if --uts=host
+		if s.UtsNS.IsHost() && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) {
+			return fmt.Errorf("sysctl %s=%s can't be set since UTS Namespace set to host: %w", sysctlKey, sysctlVal, define.ErrInvalidArg)
+		}
+
+		g.AddLinuxSysctl(sysctlKey, sysctlVal)
+	}
+
+	return nil
+}
diff --git a/pkg/specgen/generate/security_unsupported.go b/pkg/specgen/generate/security_unsupported.go
new file mode 100644
index 000000000..84a1cdab8
--- /dev/null
+++ b/pkg/specgen/generate/security_unsupported.go
@@ -0,0 +1,24 @@
+//go:build !linux
+// +build !linux
+
+package generate
+
+import (
+	"errors"
+
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/config"
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/pkg/specgen"
+	"github.com/opencontainers/runtime-tools/generate"
+)
+
+// setLabelOpts sets the label options of the SecurityConfig according to the
+// input.
+func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
+	return errors.New("unsupported setLabelOpts")
+}
+
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
+	return errors.New("unsupported securityConfigureGenerator")
+}
-- 
cgit v1.2.3-54-g00ecf


From 39880670cdde8482baf69e6a0f98b33bf34669f3 Mon Sep 17 00:00:00 2001
From: Doug Rabson <dfr@rabson.org>
Date: Fri, 26 Aug 2022 10:04:18 +0100
Subject: specgen/generate: Move SpecGenToOCI, WeightDevices to oci_linux.go
 and add stubs.

Almost all of SpecGenToOCI deals with linux-specific aspects of the
runtime spec. Rather than try to factor this out piecemeal, I think it
is cleaner to move the whole function along with its implementation
helper functions. This also meams we don't need non-linux stubs for
functions called from oci_linux.go

[NO NEW TESTS NEEDED]

Signed-off-by: Doug Rabson <dfr@rabson.org>
---
 pkg/specgen/generate/config_unsupported.go |  29 ---
 pkg/specgen/generate/oci.go                | 317 ---------------------------
 pkg/specgen/generate/oci_linux.go          | 331 +++++++++++++++++++++++++++++
 pkg/specgen/generate/oci_unsupported.go    |  24 +++
 4 files changed, 355 insertions(+), 346 deletions(-)
 delete mode 100644 pkg/specgen/generate/config_unsupported.go
 create mode 100644 pkg/specgen/generate/oci_linux.go
 create mode 100644 pkg/specgen/generate/oci_unsupported.go

(limited to 'pkg/specgen')

diff --git a/pkg/specgen/generate/config_unsupported.go b/pkg/specgen/generate/config_unsupported.go
deleted file mode 100644
index a97ae0709..000000000
--- a/pkg/specgen/generate/config_unsupported.go
+++ /dev/null
@@ -1,29 +0,0 @@
-//go:build !linux
-// +build !linux
-
-package generate
-
-import (
-	"errors"
-
-	"github.com/containers/common/libimage"
-	"github.com/containers/podman/v4/pkg/specgen"
-	spec "github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/opencontainers/runtime-tools/generate"
-)
-
-// DevicesFromPath computes a list of devices
-func DevicesFromPath(g *generate.Generator, devicePath string) error {
-	return errors.New("unsupported DevicesFromPath")
-}
-
-func BlockAccessToKernelFilesystems(privileged, pidModeIsHost bool, mask, unmask []string, g *generate.Generator) {
-}
-
-func supportAmbientCapabilities() bool {
-	return false
-}
-
-func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *libimage.Image) (*spec.LinuxSeccomp, error) {
-	return nil, errors.New("not implemented getSeccompConfig")
-}
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index a531494c9..3ac1a9b3f 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -1,37 +1,19 @@
 package generate
 
 import (
-	"context"
-	"encoding/json"
 	"fmt"
-	"path"
 	"strings"
 
 	"github.com/containers/common/libimage"
-	"github.com/containers/common/pkg/cgroups"
 	"github.com/containers/common/pkg/config"
-	"github.com/containers/podman/v4/libpod"
 	"github.com/containers/podman/v4/libpod/define"
 	"github.com/containers/podman/v4/pkg/rootless"
 	"github.com/containers/podman/v4/pkg/specgen"
-	spec "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/opencontainers/runtime-tools/generate"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
 
-func setProcOpts(s *specgen.SpecGenerator, g *generate.Generator) {
-	if s.ProcOpts == nil {
-		return
-	}
-	for i := range g.Config.Mounts {
-		if g.Config.Mounts[i].Destination == "/proc" {
-			g.Config.Mounts[i].Options = s.ProcOpts
-			return
-		}
-	}
-}
-
 func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) {
 	var (
 		isRootless = rootless.IsRootless()
@@ -133,302 +115,3 @@ func makeCommand(s *specgen.SpecGenerator, imageData *libimage.ImageData, rtc *c
 
 	return finalCommand, nil
 }
-
-// canMountSys is a best-effort heuristic to detect whether mounting a new sysfs is permitted in the container
-func canMountSys(isRootless, isNewUserns bool, s *specgen.SpecGenerator) bool {
-	if s.NetNS.IsHost() && (isRootless || isNewUserns) {
-		return false
-	}
-	if isNewUserns {
-		switch s.NetNS.NSMode {
-		case specgen.Slirp, specgen.Private, specgen.NoNetwork, specgen.Bridge:
-			return true
-		default:
-			return false
-		}
-	}
-	return true
-}
-
-func getCgroupPermissons(unmask []string) string {
-	ro := "ro"
-	rw := "rw"
-	cgroup := "/sys/fs/cgroup"
-
-	cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
-	if !cgroupv2 {
-		return ro
-	}
-
-	if unmask != nil && unmask[0] == "ALL" {
-		return rw
-	}
-
-	for _, p := range unmask {
-		if path.Clean(p) == cgroup {
-			return rw
-		}
-	}
-	return ro
-}
-
-// SpecGenToOCI returns the base configuration for the container.
-func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
-	cgroupPerm := getCgroupPermissons(s.Unmask)
-
-	g, err := generate.New("linux")
-	if err != nil {
-		return nil, err
-	}
-	// Remove the default /dev/shm mount to ensure we overwrite it
-	g.RemoveMount("/dev/shm")
-	g.HostSpecific = true
-	addCgroup := true
-
-	isRootless := rootless.IsRootless()
-	isNewUserns := s.UserNS.IsContainer() || s.UserNS.IsPath() || s.UserNS.IsPrivate()
-
-	canMountSys := canMountSys(isRootless, isNewUserns, s)
-
-	if s.Privileged && canMountSys {
-		cgroupPerm = "rw"
-		g.RemoveMount("/sys")
-		sysMnt := spec.Mount{
-			Destination: "/sys",
-			Type:        "sysfs",
-			Source:      "sysfs",
-			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", "rw"},
-		}
-		g.AddMount(sysMnt)
-	}
-	if !canMountSys {
-		addCgroup = false
-		g.RemoveMount("/sys")
-		r := "ro"
-		if s.Privileged {
-			r = "rw"
-		}
-		sysMnt := spec.Mount{
-			Destination: "/sys",
-			Type:        "bind", // should we use a constant for this, like createconfig?
-			Source:      "/sys",
-			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
-		}
-		g.AddMount(sysMnt)
-		if !s.Privileged && isRootless {
-			g.AddLinuxMaskedPaths("/sys/kernel")
-		}
-	}
-	gid5Available := true
-	if isRootless {
-		nGids, err := rootless.GetAvailableGids()
-		if err != nil {
-			return nil, err
-		}
-		gid5Available = nGids >= 5
-	}
-	// When using a different user namespace, check that the GID 5 is mapped inside
-	// the container.
-	if gid5Available && (s.IDMappings != nil && len(s.IDMappings.GIDMap) > 0) {
-		mappingFound := false
-		for _, r := range s.IDMappings.GIDMap {
-			if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
-				mappingFound = true
-				break
-			}
-		}
-		if !mappingFound {
-			gid5Available = false
-		}
-	}
-	if !gid5Available {
-		// If we have no GID mappings, the gid=5 default option would fail, so drop it.
-		g.RemoveMount("/dev/pts")
-		devPts := spec.Mount{
-			Destination: "/dev/pts",
-			Type:        "devpts",
-			Source:      "devpts",
-			Options:     []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
-		}
-		g.AddMount(devPts)
-	}
-
-	inUserNS := isRootless || isNewUserns
-
-	if inUserNS && s.IpcNS.IsHost() {
-		g.RemoveMount("/dev/mqueue")
-		devMqueue := spec.Mount{
-			Destination: "/dev/mqueue",
-			Type:        "bind", // constant ?
-			Source:      "/dev/mqueue",
-			Options:     []string{"bind", "nosuid", "noexec", "nodev"},
-		}
-		g.AddMount(devMqueue)
-	}
-	if inUserNS && s.PidNS.IsHost() {
-		g.RemoveMount("/proc")
-		procMount := spec.Mount{
-			Destination: "/proc",
-			Type:        define.TypeBind,
-			Source:      "/proc",
-			Options:     []string{"rbind", "nosuid", "noexec", "nodev"},
-		}
-		g.AddMount(procMount)
-	}
-
-	if addCgroup {
-		cgroupMnt := spec.Mount{
-			Destination: "/sys/fs/cgroup",
-			Type:        "cgroup",
-			Source:      "cgroup",
-			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", "relatime", cgroupPerm},
-		}
-		g.AddMount(cgroupMnt)
-	}
-
-	g.Config.Linux.Personality = s.Personality
-
-	g.SetProcessCwd(s.WorkDir)
-
-	g.SetProcessArgs(finalCmd)
-
-	g.SetProcessTerminal(s.Terminal)
-
-	for key, val := range s.Annotations {
-		g.AddAnnotation(key, val)
-	}
-
-	if s.ResourceLimits != nil {
-		out, err := json.Marshal(s.ResourceLimits)
-		if err != nil {
-			return nil, err
-		}
-		err = json.Unmarshal(out, g.Config.Linux.Resources)
-		if err != nil {
-			return nil, err
-		}
-		g.Config.Linux.Resources = s.ResourceLimits
-	}
-
-	weightDevices, err := WeightDevices(s.WeightDevice)
-	if err != nil {
-		return nil, err
-	}
-	if len(weightDevices) > 0 {
-		for _, dev := range weightDevices {
-			g.AddLinuxResourcesBlockIOWeightDevice(dev.Major, dev.Minor, *dev.Weight)
-		}
-	}
-
-	// Devices
-	// set the default rule at the beginning of device configuration
-	if !inUserNS && !s.Privileged {
-		g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
-	}
-
-	var userDevices []spec.LinuxDevice
-
-	if !s.Privileged {
-		// add default devices from containers.conf
-		for _, device := range rtc.Containers.Devices {
-			if err = DevicesFromPath(&g, device); err != nil {
-				return nil, err
-			}
-		}
-		if len(compatibleOptions.HostDeviceList) > 0 && len(s.Devices) == 0 {
-			userDevices = compatibleOptions.HostDeviceList
-		} else {
-			userDevices = s.Devices
-		}
-		// add default devices specified by caller
-		for _, device := range userDevices {
-			if err = DevicesFromPath(&g, device.Path); err != nil {
-				return nil, err
-			}
-		}
-	}
-	s.HostDeviceList = userDevices
-
-	// set the devices cgroup when not running in a user namespace
-	if !inUserNS && !s.Privileged {
-		for _, dev := range s.DeviceCgroupRule {
-			g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
-		}
-	}
-
-	BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
-
-	g.ClearProcessEnv()
-	for name, val := range s.Env {
-		g.AddProcessEnv(name, val)
-	}
-
-	addRlimits(s, &g)
-
-	// NAMESPACES
-	if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
-		return nil, err
-	}
-	configSpec := g.Config
-
-	if err := securityConfigureGenerator(s, &g, newImage, rtc); err != nil {
-		return nil, err
-	}
-
-	// BIND MOUNTS
-	configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
-	// Process mounts to ensure correct options
-	if err := InitFSMounts(configSpec.Mounts); err != nil {
-		return nil, err
-	}
-
-	// Add annotations
-	if configSpec.Annotations == nil {
-		configSpec.Annotations = make(map[string]string)
-	}
-
-	if s.Remove {
-		configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
-	} else {
-		configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
-	}
-
-	if len(s.VolumesFrom) > 0 {
-		configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
-	}
-
-	if s.Privileged {
-		configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
-	} else {
-		configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
-	}
-
-	if s.Init {
-		configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
-	} else {
-		configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
-	}
-
-	if s.OOMScoreAdj != nil {
-		g.SetProcessOOMScoreAdj(*s.OOMScoreAdj)
-	}
-	setProcOpts(s, &g)
-
-	return configSpec, nil
-}
-
-func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
-	devs := []spec.LinuxWeightDevice{}
-	for k, v := range wtDevices {
-		statT := unix.Stat_t{}
-		if err := unix.Stat(k, &statT); err != nil {
-			return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
-		}
-		dev := new(spec.LinuxWeightDevice)
-		dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
-		dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
-		dev.Weight = v.Weight
-		devs = append(devs, *dev)
-	}
-	return devs, nil
-}
diff --git a/pkg/specgen/generate/oci_linux.go b/pkg/specgen/generate/oci_linux.go
new file mode 100644
index 000000000..341853de5
--- /dev/null
+++ b/pkg/specgen/generate/oci_linux.go
@@ -0,0 +1,331 @@
+package generate
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"path"
+	"strings"
+
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/cgroups"
+	"github.com/containers/common/pkg/config"
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/libpod/define"
+	"github.com/containers/podman/v4/pkg/rootless"
+	"github.com/containers/podman/v4/pkg/specgen"
+	spec "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/opencontainers/runtime-tools/generate"
+	"golang.org/x/sys/unix"
+)
+
+func setProcOpts(s *specgen.SpecGenerator, g *generate.Generator) {
+	if s.ProcOpts == nil {
+		return
+	}
+	for i := range g.Config.Mounts {
+		if g.Config.Mounts[i].Destination == "/proc" {
+			g.Config.Mounts[i].Options = s.ProcOpts
+			return
+		}
+	}
+}
+
+// canMountSys is a best-effort heuristic to detect whether mounting a new sysfs is permitted in the container
+func canMountSys(isRootless, isNewUserns bool, s *specgen.SpecGenerator) bool {
+	if s.NetNS.IsHost() && (isRootless || isNewUserns) {
+		return false
+	}
+	if isNewUserns {
+		switch s.NetNS.NSMode {
+		case specgen.Slirp, specgen.Private, specgen.NoNetwork, specgen.Bridge:
+			return true
+		default:
+			return false
+		}
+	}
+	return true
+}
+
+func getCgroupPermissons(unmask []string) string {
+	ro := "ro"
+	rw := "rw"
+	cgroup := "/sys/fs/cgroup"
+
+	cgroupv2, _ := cgroups.IsCgroup2UnifiedMode()
+	if !cgroupv2 {
+		return ro
+	}
+
+	if unmask != nil && unmask[0] == "ALL" {
+		return rw
+	}
+
+	for _, p := range unmask {
+		if path.Clean(p) == cgroup {
+			return rw
+		}
+	}
+	return ro
+}
+
+// SpecGenToOCI returns the base configuration for the container.
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
+	cgroupPerm := getCgroupPermissons(s.Unmask)
+
+	g, err := generate.New("linux")
+	if err != nil {
+		return nil, err
+	}
+	// Remove the default /dev/shm mount to ensure we overwrite it
+	g.RemoveMount("/dev/shm")
+	g.HostSpecific = true
+	addCgroup := true
+
+	isRootless := rootless.IsRootless()
+	isNewUserns := s.UserNS.IsContainer() || s.UserNS.IsPath() || s.UserNS.IsPrivate()
+
+	canMountSys := canMountSys(isRootless, isNewUserns, s)
+
+	if s.Privileged && canMountSys {
+		cgroupPerm = "rw"
+		g.RemoveMount("/sys")
+		sysMnt := spec.Mount{
+			Destination: "/sys",
+			Type:        "sysfs",
+			Source:      "sysfs",
+			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", "rw"},
+		}
+		g.AddMount(sysMnt)
+	}
+	if !canMountSys {
+		addCgroup = false
+		g.RemoveMount("/sys")
+		r := "ro"
+		if s.Privileged {
+			r = "rw"
+		}
+		sysMnt := spec.Mount{
+			Destination: "/sys",
+			Type:        "bind", // should we use a constant for this, like createconfig?
+			Source:      "/sys",
+			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", r, "rbind"},
+		}
+		g.AddMount(sysMnt)
+		if !s.Privileged && isRootless {
+			g.AddLinuxMaskedPaths("/sys/kernel")
+		}
+	}
+	gid5Available := true
+	if isRootless {
+		nGids, err := rootless.GetAvailableGids()
+		if err != nil {
+			return nil, err
+		}
+		gid5Available = nGids >= 5
+	}
+	// When using a different user namespace, check that the GID 5 is mapped inside
+	// the container.
+	if gid5Available && (s.IDMappings != nil && len(s.IDMappings.GIDMap) > 0) {
+		mappingFound := false
+		for _, r := range s.IDMappings.GIDMap {
+			if r.ContainerID <= 5 && 5 < r.ContainerID+r.Size {
+				mappingFound = true
+				break
+			}
+		}
+		if !mappingFound {
+			gid5Available = false
+		}
+	}
+	if !gid5Available {
+		// If we have no GID mappings, the gid=5 default option would fail, so drop it.
+		g.RemoveMount("/dev/pts")
+		devPts := spec.Mount{
+			Destination: "/dev/pts",
+			Type:        "devpts",
+			Source:      "devpts",
+			Options:     []string{"rprivate", "nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620"},
+		}
+		g.AddMount(devPts)
+	}
+
+	inUserNS := isRootless || isNewUserns
+
+	if inUserNS && s.IpcNS.IsHost() {
+		g.RemoveMount("/dev/mqueue")
+		devMqueue := spec.Mount{
+			Destination: "/dev/mqueue",
+			Type:        "bind", // constant ?
+			Source:      "/dev/mqueue",
+			Options:     []string{"bind", "nosuid", "noexec", "nodev"},
+		}
+		g.AddMount(devMqueue)
+	}
+	if inUserNS && s.PidNS.IsHost() {
+		g.RemoveMount("/proc")
+		procMount := spec.Mount{
+			Destination: "/proc",
+			Type:        define.TypeBind,
+			Source:      "/proc",
+			Options:     []string{"rbind", "nosuid", "noexec", "nodev"},
+		}
+		g.AddMount(procMount)
+	}
+
+	if addCgroup {
+		cgroupMnt := spec.Mount{
+			Destination: "/sys/fs/cgroup",
+			Type:        "cgroup",
+			Source:      "cgroup",
+			Options:     []string{"rprivate", "nosuid", "noexec", "nodev", "relatime", cgroupPerm},
+		}
+		g.AddMount(cgroupMnt)
+	}
+
+	g.Config.Linux.Personality = s.Personality
+
+	g.SetProcessCwd(s.WorkDir)
+
+	g.SetProcessArgs(finalCmd)
+
+	g.SetProcessTerminal(s.Terminal)
+
+	for key, val := range s.Annotations {
+		g.AddAnnotation(key, val)
+	}
+
+	if s.ResourceLimits != nil {
+		out, err := json.Marshal(s.ResourceLimits)
+		if err != nil {
+			return nil, err
+		}
+		err = json.Unmarshal(out, g.Config.Linux.Resources)
+		if err != nil {
+			return nil, err
+		}
+		g.Config.Linux.Resources = s.ResourceLimits
+	}
+
+	weightDevices, err := WeightDevices(s.WeightDevice)
+	if err != nil {
+		return nil, err
+	}
+	if len(weightDevices) > 0 {
+		for _, dev := range weightDevices {
+			g.AddLinuxResourcesBlockIOWeightDevice(dev.Major, dev.Minor, *dev.Weight)
+		}
+	}
+
+	// Devices
+	// set the default rule at the beginning of device configuration
+	if !inUserNS && !s.Privileged {
+		g.AddLinuxResourcesDevice(false, "", nil, nil, "rwm")
+	}
+
+	var userDevices []spec.LinuxDevice
+
+	if !s.Privileged {
+		// add default devices from containers.conf
+		for _, device := range rtc.Containers.Devices {
+			if err = DevicesFromPath(&g, device); err != nil {
+				return nil, err
+			}
+		}
+		if len(compatibleOptions.HostDeviceList) > 0 && len(s.Devices) == 0 {
+			userDevices = compatibleOptions.HostDeviceList
+		} else {
+			userDevices = s.Devices
+		}
+		// add default devices specified by caller
+		for _, device := range userDevices {
+			if err = DevicesFromPath(&g, device.Path); err != nil {
+				return nil, err
+			}
+		}
+	}
+	s.HostDeviceList = userDevices
+
+	// set the devices cgroup when not running in a user namespace
+	if !inUserNS && !s.Privileged {
+		for _, dev := range s.DeviceCgroupRule {
+			g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access)
+		}
+	}
+
+	BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g)
+
+	g.ClearProcessEnv()
+	for name, val := range s.Env {
+		g.AddProcessEnv(name, val)
+	}
+
+	addRlimits(s, &g)
+
+	// NAMESPACES
+	if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
+		return nil, err
+	}
+	configSpec := g.Config
+
+	if err := securityConfigureGenerator(s, &g, newImage, rtc); err != nil {
+		return nil, err
+	}
+
+	// BIND MOUNTS
+	configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
+	// Process mounts to ensure correct options
+	if err := InitFSMounts(configSpec.Mounts); err != nil {
+		return nil, err
+	}
+
+	// Add annotations
+	if configSpec.Annotations == nil {
+		configSpec.Annotations = make(map[string]string)
+	}
+
+	if s.Remove {
+		configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
+	} else {
+		configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
+	}
+
+	if len(s.VolumesFrom) > 0 {
+		configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
+	}
+
+	if s.Privileged {
+		configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
+	} else {
+		configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
+	}
+
+	if s.Init {
+		configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
+	} else {
+		configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
+	}
+
+	if s.OOMScoreAdj != nil {
+		g.SetProcessOOMScoreAdj(*s.OOMScoreAdj)
+	}
+	setProcOpts(s, &g)
+
+	return configSpec, nil
+}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+	devs := []spec.LinuxWeightDevice{}
+	for k, v := range wtDevices {
+		statT := unix.Stat_t{}
+		if err := unix.Stat(k, &statT); err != nil {
+			return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err)
+		}
+		dev := new(spec.LinuxWeightDevice)
+		dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert
+		dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert
+		dev.Weight = v.Weight
+		devs = append(devs, *dev)
+	}
+	return devs, nil
+}
diff --git a/pkg/specgen/generate/oci_unsupported.go b/pkg/specgen/generate/oci_unsupported.go
new file mode 100644
index 000000000..3902f9c9f
--- /dev/null
+++ b/pkg/specgen/generate/oci_unsupported.go
@@ -0,0 +1,24 @@
+//go:build !linux
+// +build !linux
+
+package generate
+
+import (
+	"context"
+	"errors"
+
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/config"
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/pkg/specgen"
+	spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// SpecGenToOCI returns the base configuration for the container.
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
+	return nil, errors.New("unsupported SpecGenToOCI")
+}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+	return []spec.LinuxWeightDevice{}, errors.New("unsupported WeightDevices")
+}
-- 
cgit v1.2.3-54-g00ecf


From 68f4dcf00ab8520bfd89e118700f3fe3b4b0304d Mon Sep 17 00:00:00 2001
From: Doug Rabson <dfr@rabson.org>
Date: Fri, 26 Aug 2022 10:32:11 +0100
Subject: specgen/generate: Move specConfigNamespaces to namespace_linux.go and
 add stubs

Everthing except for hostname management is linux-specific.

[NO NEW TESTS NEEDED]

Signed-off-by: Doug Rabson <dfr@rabson.org>
---
 pkg/specgen/generate/namespaces.go             | 149 -----------------------
 pkg/specgen/generate/namespaces_linux.go       | 160 +++++++++++++++++++++++++
 pkg/specgen/generate/namespaces_unsupported.go |  16 +++
 3 files changed, 176 insertions(+), 149 deletions(-)
 create mode 100644 pkg/specgen/generate/namespaces_linux.go
 create mode 100644 pkg/specgen/generate/namespaces_unsupported.go

(limited to 'pkg/specgen')

diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index f0d4e9153..aee4db0e6 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -3,7 +3,6 @@ package generate
 import (
 	"errors"
 	"fmt"
-	"os"
 	"strings"
 
 	"github.com/containers/common/libimage"
@@ -15,7 +14,6 @@ import (
 	"github.com/containers/podman/v4/pkg/specgen"
 	"github.com/containers/podman/v4/pkg/util"
 	spec "github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/opencontainers/runtime-tools/generate"
 	"github.com/sirupsen/logrus"
 )
 
@@ -357,153 +355,6 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod.
 	return toReturn, nil
 }
 
-func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
-	// PID
-	switch s.PidNS.NSMode {
-	case specgen.Path:
-		if _, err := os.Stat(s.PidNS.Value); err != nil {
-			return fmt.Errorf("cannot find specified PID namespace path: %w", err)
-		}
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil {
-			return err
-		}
-	case specgen.Host:
-		if err := g.RemoveLinuxNamespace(string(spec.PIDNamespace)); err != nil {
-			return err
-		}
-	case specgen.Private:
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), ""); err != nil {
-			return err
-		}
-	}
-
-	// IPC
-	switch s.IpcNS.NSMode {
-	case specgen.Path:
-		if _, err := os.Stat(s.IpcNS.Value); err != nil {
-			return fmt.Errorf("cannot find specified IPC namespace path: %w", err)
-		}
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil {
-			return err
-		}
-	case specgen.Host:
-		if err := g.RemoveLinuxNamespace(string(spec.IPCNamespace)); err != nil {
-			return err
-		}
-	case specgen.Private:
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), ""); err != nil {
-			return err
-		}
-	}
-
-	// UTS
-	switch s.UtsNS.NSMode {
-	case specgen.Path:
-		if _, err := os.Stat(s.UtsNS.Value); err != nil {
-			return fmt.Errorf("cannot find specified UTS namespace path: %w", err)
-		}
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil {
-			return err
-		}
-	case specgen.Host:
-		if err := g.RemoveLinuxNamespace(string(spec.UTSNamespace)); err != nil {
-			return err
-		}
-	case specgen.Private:
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), ""); err != nil {
-			return err
-		}
-	}
-
-	hostname := s.Hostname
-	if hostname == "" {
-		switch {
-		case s.UtsNS.NSMode == specgen.FromPod:
-			hostname = pod.Hostname()
-		case s.UtsNS.NSMode == specgen.FromContainer:
-			utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
-			if err != nil {
-				return fmt.Errorf("error looking up container to share uts namespace with: %w", err)
-			}
-			hostname = utsCtr.Hostname()
-		case (s.NetNS.NSMode == specgen.Host && hostname == "") || s.UtsNS.NSMode == specgen.Host:
-			tmpHostname, err := os.Hostname()
-			if err != nil {
-				return fmt.Errorf("unable to retrieve hostname of the host: %w", err)
-			}
-			hostname = tmpHostname
-		default:
-			logrus.Debug("No hostname set; container's hostname will default to runtime default")
-		}
-	}
-
-	g.RemoveHostname()
-	if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
-		// Set the hostname in the OCI configuration only if specified by
-		// the user or if we are creating a new UTS namespace.
-		// TODO: Should we be doing this for pod or container shared
-		// namespaces?
-		g.SetHostname(hostname)
-	}
-	if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
-		g.AddProcessEnv("HOSTNAME", hostname)
-	}
-
-	// User
-	if _, err := specgen.SetupUserNS(s.IDMappings, s.UserNS, g); err != nil {
-		return err
-	}
-
-	// Cgroup
-	switch s.CgroupNS.NSMode {
-	case specgen.Path:
-		if _, err := os.Stat(s.CgroupNS.Value); err != nil {
-			return fmt.Errorf("cannot find specified cgroup namespace path: %w", err)
-		}
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil {
-			return err
-		}
-	case specgen.Host:
-		if err := g.RemoveLinuxNamespace(string(spec.CgroupNamespace)); err != nil {
-			return err
-		}
-	case specgen.Private:
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), ""); err != nil {
-			return err
-		}
-	}
-
-	// Net
-	switch s.NetNS.NSMode {
-	case specgen.Path:
-		if _, err := os.Stat(s.NetNS.Value); err != nil {
-			return fmt.Errorf("cannot find specified network namespace path: %w", err)
-		}
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
-			return err
-		}
-	case specgen.Host:
-		if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
-			return err
-		}
-	case specgen.Private, specgen.NoNetwork:
-		if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), ""); err != nil {
-			return err
-		}
-	}
-
-	if g.Config.Annotations == nil {
-		g.Config.Annotations = make(map[string]string)
-	}
-	if s.PublishExposedPorts {
-		g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
-	} else {
-		g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
-	}
-
-	return nil
-}
-
 // GetNamespaceOptions transforms a slice of kernel namespaces
 // into a slice of pod create options. Currently, not all
 // kernel namespaces are supported, and they will be returned in an error
diff --git a/pkg/specgen/generate/namespaces_linux.go b/pkg/specgen/generate/namespaces_linux.go
new file mode 100644
index 000000000..5c056e52c
--- /dev/null
+++ b/pkg/specgen/generate/namespaces_linux.go
@@ -0,0 +1,160 @@
+package generate
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/libpod/define"
+	"github.com/containers/podman/v4/pkg/specgen"
+	spec "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/opencontainers/runtime-tools/generate"
+	"github.com/sirupsen/logrus"
+)
+
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
+	// PID
+	switch s.PidNS.NSMode {
+	case specgen.Path:
+		if _, err := os.Stat(s.PidNS.Value); err != nil {
+			return fmt.Errorf("cannot find specified PID namespace path: %w", err)
+		}
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), s.PidNS.Value); err != nil {
+			return err
+		}
+	case specgen.Host:
+		if err := g.RemoveLinuxNamespace(string(spec.PIDNamespace)); err != nil {
+			return err
+		}
+	case specgen.Private:
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), ""); err != nil {
+			return err
+		}
+	}
+
+	// IPC
+	switch s.IpcNS.NSMode {
+	case specgen.Path:
+		if _, err := os.Stat(s.IpcNS.Value); err != nil {
+			return fmt.Errorf("cannot find specified IPC namespace path: %w", err)
+		}
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), s.IpcNS.Value); err != nil {
+			return err
+		}
+	case specgen.Host:
+		if err := g.RemoveLinuxNamespace(string(spec.IPCNamespace)); err != nil {
+			return err
+		}
+	case specgen.Private:
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), ""); err != nil {
+			return err
+		}
+	}
+
+	// UTS
+	switch s.UtsNS.NSMode {
+	case specgen.Path:
+		if _, err := os.Stat(s.UtsNS.Value); err != nil {
+			return fmt.Errorf("cannot find specified UTS namespace path: %w", err)
+		}
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), s.UtsNS.Value); err != nil {
+			return err
+		}
+	case specgen.Host:
+		if err := g.RemoveLinuxNamespace(string(spec.UTSNamespace)); err != nil {
+			return err
+		}
+	case specgen.Private:
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), ""); err != nil {
+			return err
+		}
+	}
+
+	hostname := s.Hostname
+	if hostname == "" {
+		switch {
+		case s.UtsNS.NSMode == specgen.FromPod:
+			hostname = pod.Hostname()
+		case s.UtsNS.NSMode == specgen.FromContainer:
+			utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
+			if err != nil {
+				return fmt.Errorf("error looking up container to share uts namespace with: %w", err)
+			}
+			hostname = utsCtr.Hostname()
+		case (s.NetNS.NSMode == specgen.Host && hostname == "") || s.UtsNS.NSMode == specgen.Host:
+			tmpHostname, err := os.Hostname()
+			if err != nil {
+				return fmt.Errorf("unable to retrieve hostname of the host: %w", err)
+			}
+			hostname = tmpHostname
+		default:
+			logrus.Debug("No hostname set; container's hostname will default to runtime default")
+		}
+	}
+
+	g.RemoveHostname()
+	if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
+		// Set the hostname in the OCI configuration only if specified by
+		// the user or if we are creating a new UTS namespace.
+		// TODO: Should we be doing this for pod or container shared
+		// namespaces?
+		g.SetHostname(hostname)
+	}
+	if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
+		g.AddProcessEnv("HOSTNAME", hostname)
+	}
+
+	// User
+	if _, err := specgen.SetupUserNS(s.IDMappings, s.UserNS, g); err != nil {
+		return err
+	}
+
+	// Cgroup
+	switch s.CgroupNS.NSMode {
+	case specgen.Path:
+		if _, err := os.Stat(s.CgroupNS.Value); err != nil {
+			return fmt.Errorf("cannot find specified cgroup namespace path: %w", err)
+		}
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), s.CgroupNS.Value); err != nil {
+			return err
+		}
+	case specgen.Host:
+		if err := g.RemoveLinuxNamespace(string(spec.CgroupNamespace)); err != nil {
+			return err
+		}
+	case specgen.Private:
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), ""); err != nil {
+			return err
+		}
+	}
+
+	// Net
+	switch s.NetNS.NSMode {
+	case specgen.Path:
+		if _, err := os.Stat(s.NetNS.Value); err != nil {
+			return fmt.Errorf("cannot find specified network namespace path: %w", err)
+		}
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), s.NetNS.Value); err != nil {
+			return err
+		}
+	case specgen.Host:
+		if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil {
+			return err
+		}
+	case specgen.Private, specgen.NoNetwork:
+		if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), ""); err != nil {
+			return err
+		}
+	}
+
+	if g.Config.Annotations == nil {
+		g.Config.Annotations = make(map[string]string)
+	}
+	if s.PublishExposedPorts {
+		g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
+	} else {
+		g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
+	}
+
+	return nil
+}
diff --git a/pkg/specgen/generate/namespaces_unsupported.go b/pkg/specgen/generate/namespaces_unsupported.go
new file mode 100644
index 000000000..be5805ad6
--- /dev/null
+++ b/pkg/specgen/generate/namespaces_unsupported.go
@@ -0,0 +1,16 @@
+//go:build !linux
+// +build !linux
+
+package generate
+
+import (
+	"errors"
+
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/pkg/specgen"
+	"github.com/opencontainers/runtime-tools/generate"
+)
+
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
+	return errors.New("unsupported specConfigureNamespaces")
+}
-- 
cgit v1.2.3-54-g00ecf


From 4781bc7fe7ef33c5d1f1892b2da274ed3d4bd6c8 Mon Sep 17 00:00:00 2001
From: Doug Rabson <dfr@rabson.org>
Date: Fri, 26 Aug 2022 11:17:32 +0100
Subject: specgen/generate: Add support for FreeBSD

[NO NEW TESTS NEEDED]

Signed-off-by: Doug Rabson <dfr@rabson.org>
---
 pkg/specgen/generate/namespaces_freebsd.go     | 51 ++++++++++++++
 pkg/specgen/generate/namespaces_unsupported.go |  4 +-
 pkg/specgen/generate/oci_freebsd.go            | 96 ++++++++++++++++++++++++++
 pkg/specgen/generate/oci_unsupported.go        |  4 +-
 pkg/specgen/generate/security_freebsd.go       | 19 +++++
 pkg/specgen/generate/security_unsupported.go   |  4 +-
 6 files changed, 172 insertions(+), 6 deletions(-)
 create mode 100644 pkg/specgen/generate/namespaces_freebsd.go
 create mode 100644 pkg/specgen/generate/oci_freebsd.go
 create mode 100644 pkg/specgen/generate/security_freebsd.go

(limited to 'pkg/specgen')

diff --git a/pkg/specgen/generate/namespaces_freebsd.go b/pkg/specgen/generate/namespaces_freebsd.go
new file mode 100644
index 000000000..d821d9daa
--- /dev/null
+++ b/pkg/specgen/generate/namespaces_freebsd.go
@@ -0,0 +1,51 @@
+package generate
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/pkg/specgen"
+	"github.com/opencontainers/runtime-tools/generate"
+	"github.com/sirupsen/logrus"
+)
+
+func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt *libpod.Runtime, pod *libpod.Pod) error {
+	// UTS
+
+	hostname := s.Hostname
+	if hostname == "" {
+		switch {
+		case s.UtsNS.NSMode == specgen.FromPod:
+			hostname = pod.Hostname()
+		case s.UtsNS.NSMode == specgen.FromContainer:
+			utsCtr, err := rt.LookupContainer(s.UtsNS.Value)
+			if err != nil {
+				return fmt.Errorf("error looking up container to share uts namespace with: %w", err)
+			}
+			hostname = utsCtr.Hostname()
+		case (s.NetNS.NSMode == specgen.Host && hostname == "") || s.UtsNS.NSMode == specgen.Host:
+			tmpHostname, err := os.Hostname()
+			if err != nil {
+				return fmt.Errorf("unable to retrieve hostname of the host: %w", err)
+			}
+			hostname = tmpHostname
+		default:
+			logrus.Debug("No hostname set; container's hostname will default to runtime default")
+		}
+	}
+
+	g.RemoveHostname()
+	if s.Hostname != "" || s.UtsNS.NSMode != specgen.Host {
+		// Set the hostname in the OCI configuration only if specified by
+		// the user or if we are creating a new UTS namespace.
+		// TODO: Should we be doing this for pod or container shared
+		// namespaces?
+		g.SetHostname(hostname)
+	}
+	if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" {
+		g.AddProcessEnv("HOSTNAME", hostname)
+	}
+
+	return nil
+}
diff --git a/pkg/specgen/generate/namespaces_unsupported.go b/pkg/specgen/generate/namespaces_unsupported.go
index be5805ad6..c4a9c22d8 100644
--- a/pkg/specgen/generate/namespaces_unsupported.go
+++ b/pkg/specgen/generate/namespaces_unsupported.go
@@ -1,5 +1,5 @@
-//go:build !linux
-// +build !linux
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
 
 package generate
 
diff --git a/pkg/specgen/generate/oci_freebsd.go b/pkg/specgen/generate/oci_freebsd.go
new file mode 100644
index 000000000..71c926fd2
--- /dev/null
+++ b/pkg/specgen/generate/oci_freebsd.go
@@ -0,0 +1,96 @@
+//go:build freebsd
+
+package generate
+
+import (
+	"context"
+	"strings"
+
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/config"
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/libpod/define"
+	"github.com/containers/podman/v4/pkg/specgen"
+	spec "github.com/opencontainers/runtime-spec/specs-go"
+	"github.com/opencontainers/runtime-tools/generate"
+)
+
+// SpecGenToOCI returns the base configuration for the container.
+func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runtime, rtc *config.Config, newImage *libimage.Image, mounts []spec.Mount, pod *libpod.Pod, finalCmd []string, compatibleOptions *libpod.InfraInherit) (*spec.Spec, error) {
+	g, err := generate.New("freebsd")
+	if err != nil {
+		return nil, err
+	}
+
+	g.SetProcessCwd(s.WorkDir)
+
+	g.SetProcessArgs(finalCmd)
+
+	g.SetProcessTerminal(s.Terminal)
+
+	for key, val := range s.Annotations {
+		g.AddAnnotation(key, val)
+	}
+
+	g.ClearProcessEnv()
+	for name, val := range s.Env {
+		g.AddProcessEnv(name, val)
+	}
+
+	addRlimits(s, &g)
+
+	// NAMESPACES
+	if err := specConfigureNamespaces(s, &g, rt, pod); err != nil {
+		return nil, err
+	}
+	configSpec := g.Config
+
+	if err := securityConfigureGenerator(s, &g, newImage, rtc); err != nil {
+		return nil, err
+	}
+
+	// BIND MOUNTS
+	configSpec.Mounts = SupersedeUserMounts(mounts, configSpec.Mounts)
+	// Process mounts to ensure correct options
+	if err := InitFSMounts(configSpec.Mounts); err != nil {
+		return nil, err
+	}
+
+	// Add annotations
+	if configSpec.Annotations == nil {
+		configSpec.Annotations = make(map[string]string)
+	}
+
+	if s.Remove {
+		configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
+	} else {
+		configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
+	}
+
+	if len(s.VolumesFrom) > 0 {
+		configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
+	}
+
+	if s.Privileged {
+		configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
+	} else {
+		configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
+	}
+
+	if s.Init {
+		configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
+	} else {
+		configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
+	}
+
+	if s.OOMScoreAdj != nil {
+		g.SetProcessOOMScoreAdj(*s.OOMScoreAdj)
+	}
+
+	return configSpec, nil
+}
+
+func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) {
+	devs := []spec.LinuxWeightDevice{}
+	return devs, nil
+}
diff --git a/pkg/specgen/generate/oci_unsupported.go b/pkg/specgen/generate/oci_unsupported.go
index 3902f9c9f..7e1b8c42c 100644
--- a/pkg/specgen/generate/oci_unsupported.go
+++ b/pkg/specgen/generate/oci_unsupported.go
@@ -1,5 +1,5 @@
-//go:build !linux
-// +build !linux
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
 
 package generate
 
diff --git a/pkg/specgen/generate/security_freebsd.go b/pkg/specgen/generate/security_freebsd.go
new file mode 100644
index 000000000..5fd66c769
--- /dev/null
+++ b/pkg/specgen/generate/security_freebsd.go
@@ -0,0 +1,19 @@
+package generate
+
+import (
+	"github.com/containers/common/libimage"
+	"github.com/containers/common/pkg/config"
+	"github.com/containers/podman/v4/libpod"
+	"github.com/containers/podman/v4/pkg/specgen"
+	"github.com/opencontainers/runtime-tools/generate"
+)
+
+// setLabelOpts sets the label options of the SecurityConfig according to the
+// input.
+func setLabelOpts(s *specgen.SpecGenerator, runtime *libpod.Runtime, pidConfig specgen.Namespace, ipcConfig specgen.Namespace) error {
+	return nil
+}
+
+func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, newImage *libimage.Image, rtc *config.Config) error {
+	return nil
+}
diff --git a/pkg/specgen/generate/security_unsupported.go b/pkg/specgen/generate/security_unsupported.go
index 84a1cdab8..d0f937e44 100644
--- a/pkg/specgen/generate/security_unsupported.go
+++ b/pkg/specgen/generate/security_unsupported.go
@@ -1,5 +1,5 @@
-//go:build !linux
-// +build !linux
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
 
 package generate
 
-- 
cgit v1.2.3-54-g00ecf