14
"github.com/containers/common/libnetwork/types"
15
"github.com/containers/podman/v5/pkg/rootless"
16
spec "github.com/opencontainers/runtime-spec/specs-go"
17
"github.com/opencontainers/runtime-tools/generate"
18
"github.com/sirupsen/logrus"
19
"golang.org/x/sys/unix"
23
bindOptions = []string{}
26
func (c *Container) mountSHM(shmOptions string) error {
30
func (c *Container) unmountSHM(path string) error {
34
// prepare mounts the container and sets up other required resources like net
36
func (c *Container) prepare() error {
40
networkStatus map[string]types.StatusBlock
41
createNetNSErr, mountStorageErr error
43
tmpStateLock sync.Mutex
50
// Set up network namespace if not already set up
51
noNetNS := c.state.NetNS == ""
52
if c.config.CreateNetNS && noNetNS && !c.config.PostConfigureNetNS {
53
ctrNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
54
if createNetNSErr != nil {
59
defer tmpStateLock.Unlock()
61
// Assign NetNS attributes to container
63
c.state.NetworkStatus = networkStatus
66
// Mount storage if not mounted
69
mountPoint, mountStorageErr = c.mountStorage()
71
if mountStorageErr != nil {
76
defer tmpStateLock.Unlock()
78
// Finish up mountStorage
79
c.state.Mounted = true
80
c.state.Mountpoint = mountPoint
82
logrus.Debugf("Created root filesystem for container %s at %s", c.ID(), c.state.Mountpoint)
88
if createNetNSErr != nil {
89
createErr = createNetNSErr
91
if mountStorageErr != nil {
93
logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
95
createErr = mountStorageErr
98
// Only trigger storage cleanup if mountStorage was successful.
99
// Otherwise, we may mess up mount counters.
100
if createErr != nil {
101
if mountStorageErr == nil {
102
if err := c.cleanupStorage(); err != nil {
103
// createErr is guaranteed non-nil, so print
105
logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
106
createErr = fmt.Errorf("unmounting storage for container %s after network create failure: %w", c.ID(), err)
109
// It's OK to unconditionally trigger network cleanup. If the network
110
// isn't ready it will do nothing.
111
if err := c.cleanupNetwork(); err != nil {
112
logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
113
createErr = fmt.Errorf("cleaning up container %s network after setup failure: %w", c.ID(), err)
118
// Save changes to container state
119
if err := c.save(); err != nil {
126
// cleanupNetwork unmounts and cleans up the container's network
127
func (c *Container) cleanupNetwork() error {
128
if c.config.NetNsCtr != "" {
131
netDisabled, err := c.NetworkDisabled()
139
// Stop the container's network namespace (if it has one)
140
if err := c.runtime.teardownNetNS(c); err != nil {
141
logrus.Errorf("Unable to cleanup network for container %s: %q", c.ID(), err)
151
// reloadNetwork reloads the network for the given container, recreating
153
func (c *Container) reloadNetwork() error {
154
result, err := c.runtime.reloadContainerNetwork(c)
159
c.state.NetworkStatus = result
164
// Add an existing container's network jail
165
func (c *Container) addNetworkContainer(g *generate.Generator, ctr string) error {
166
nsCtr, err := c.runtime.state.Container(ctr)
168
return fmt.Errorf("retrieving dependency %s of container %s from state: %w", ctr, c.ID(), err)
170
c.runtime.state.UpdateContainer(nsCtr)
171
if nsCtr.state.NetNS != "" {
172
g.AddAnnotation("org.freebsd.parentJail", nsCtr.state.NetNS)
177
func isRootlessCgroupSet(cgroup string) bool {
181
func (c *Container) expectPodCgroup() (bool, error) {
185
func (c *Container) getOCICgroupPath() (string, error) {
189
func openDirectory(path string) (fd int, err error) {
190
const O_PATH = 0x00400000
191
return unix.Open(path, unix.O_RDONLY|O_PATH|unix.O_CLOEXEC, 0)
194
func (c *Container) addNetworkNamespace(g *generate.Generator) error {
195
if c.config.CreateNetNS {
196
// If PostConfigureNetNS is set (which is true on FreeBSD 13.3
197
// and later), we can manage a container's network settings
198
// without an extra parent jail to own the vnew.
200
// In this case, the OCI runtime creates a new vnet for the
201
// container jail, otherwise it creates the container jail as a
202
// child of the jail owning the vnet.
203
if c.config.PostConfigureNetNS {
204
g.AddAnnotation("org.freebsd.jail.vnet", "new")
206
g.AddAnnotation("org.freebsd.parentJail", c.state.NetNS)
212
func (c *Container) addSystemdMounts(g *generate.Generator) error {
216
func (c *Container) addSharedNamespaces(g *generate.Generator) error {
217
if c.config.NetNsCtr != "" {
218
if err := c.addNetworkContainer(g, c.config.NetNsCtr); err != nil {
223
availableUIDs, availableGIDs, err := rootless.GetAvailableIDMaps()
225
if os.IsNotExist(err) {
226
// The kernel-provided files only exist if user namespaces are supported
227
logrus.Debugf("User or group ID mappings not available: %s", err)
232
g.Config.Linux.UIDMappings = rootless.MaybeSplitMappings(g.Config.Linux.UIDMappings, availableUIDs)
233
g.Config.Linux.GIDMappings = rootless.MaybeSplitMappings(g.Config.Linux.GIDMappings, availableGIDs)
236
// Hostname handling:
237
// If we have a UTS namespace, set Hostname in the OCI spec.
238
// Set the HOSTNAME environment variable unless explicitly overridden by
239
// the user (already present in OCI spec). If we don't have a UTS ns,
240
// set it to the host's hostname instead.
241
hostname := c.Hostname()
244
// TODO: make this optional, needs progress on adding FreeBSD section to the spec
246
g.SetHostname(hostname)
249
tmpHostname, err := os.Hostname()
253
hostname = tmpHostname
256
for _, checkEnv := range g.Config.Process.Env {
257
if strings.HasPrefix(checkEnv, "HOSTNAME=") {
263
g.AddProcessEnv("HOSTNAME", hostname)
268
func (c *Container) addRootPropagation(g *generate.Generator, mounts []spec.Mount) error {
272
func (c *Container) setProcessLabel(g *generate.Generator) {
275
func (c *Container) setMountLabel(g *generate.Generator) {
278
func (c *Container) setCgroupsPath(g *generate.Generator) error {
282
func (c *Container) addSpecialDNS(nameservers []string) []string {
286
func (c *Container) isSlirp4netnsIPv6() bool {
291
func (c *Container) hasNetNone() bool {
292
return c.state.NetNS == ""
295
func setVolumeAtime(mountPoint string, st os.FileInfo) error {
296
stat := st.Sys().(*syscall.Stat_t)
297
atime := time.Unix(int64(stat.Atimespec.Sec), int64(stat.Atimespec.Nsec)) //nolint: unconvert
298
if err := os.Chtimes(mountPoint, atime, st.ModTime()); err != nil {
304
func (c *Container) makePlatformBindMounts() error {
308
func (c *Container) getConmonPidFd() int {
309
// Note: kqueue(2) could be used here but that would require
310
// factoring out the call to unix.PollFd from WaitForExit so
311
// keeping things simple for now.
315
func (c *Container) jailName() (string, error) {
316
// If this container is in a pod, get the vnet name from the
317
// corresponding infra container
319
if c.config.Pod != "" && c.config.Pod != c.ID() {
320
// Get the pod from state
321
pod, err := c.runtime.state.Pod(c.config.Pod)
323
return "", fmt.Errorf("cannot find infra container for pod %s: %w", c.config.Pod, err)
325
ic, err = pod.InfraContainer()
327
return "", fmt.Errorf("getting infra container for pod %s: %w", pod.ID(), err)
329
if ic.ID() != c.ID() {
331
defer ic.lock.Unlock()
332
if err := ic.syncContainer(); err != nil {
340
if ic.state.NetNS != "" {
341
return ic.state.NetNS + "." + c.ID(), nil
347
type safeMountInfo struct {
348
// mountPoint is the mount point.
352
// Close releases the resources allocated with the safe mount info.
353
func (s *safeMountInfo) Close() {
356
// safeMountSubPath securely mounts a subpath inside a volume to a new temporary location.
357
// The function checks that the subpath is a valid subpath within the volume and that it
358
// does not escape the boundaries of the mount point (volume).
360
// The caller is responsible for closing the file descriptor and unmounting the subpath
361
// when it's no longer needed.
362
func (c *Container) safeMountSubPath(mountPoint, subpath string) (s *safeMountInfo, err error) {
363
return &safeMountInfo{mountPoint: filepath.Join(mountPoint, subpath)}, nil
366
func (c *Container) makePlatformMtabLink(etcInTheContainerFd, rootUID, rootGID int) error {
367
// /etc/mtab does not exist on FreeBSD
371
func (c *Container) getPlatformRunPath() (string, error) {
372
// If we have a linux image, use "/run", otherwise use "/var/run" for
373
// consistency with FreeBSD path conventions.
374
runPath := "/var/run"
375
if c.config.RootfsImageID != "" {
376
image, _, err := c.runtime.libimageRuntime.LookupImage(c.config.RootfsImageID, nil)
380
inspectData, err := image.Inspect(nil, nil)
384
if inspectData.Os == "linux" {
391
func (c *Container) addMaskedPaths(g *generate.Generator) {
392
// There are currently no FreeBSD-specific masked paths
395
func (c *Container) hasPrivateUTS() bool {
396
// Currently we always use a private UTS namespace on FreeBSD. This
397
// should be optional but needs a FreeBSD section in the OCI runtime