spiegel_podman/pkg/specgen/generate/config_linux_seccomp.go
r-vdp 4ce2583ad7
compat API: accept inline seccomp profiles
Docker clients send the seccomp profile JSON itself in
HostConfig.SecurityOpt (the docker CLI reads the profile file
client-side and inlines it). The compat API treated the value as a path
to a profile file, so container create failed with "file name too
long". This breaks docker-compat tooling that passes seccomp profiles
through the socket, like Nextcloud AIO and forgejo-runner.

Add a SeccompProfile field to specgen for inline profile content,
next to the existing SeccompProfilePath, as requested in review of the
earlier PR that tried to fix this (#28985). The compat create handler
extracts inline profiles (values starting with "{") from SecurityOpt
and sets the new field. Path-based values and "unconfined" keep their
current meaning, and duplicate seccomp options resolve last-one-wins,
like docker.

Fixes: #27710

Signed-off-by: r-vdp <ramses@well-founded.dev>
2026-09-24 10:31:00 +02:00

73 lines
2.2 KiB
Go

//go:build linux && !remote
package generate
import (
"context"
"errors"
"fmt"
"os"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"
"go.podman.io/common/libimage"
goSeccomp "go.podman.io/common/pkg/seccomp"
"go.podman.io/podman/v6/pkg/seccomp"
"go.podman.io/podman/v6/pkg/specgen"
)
func getSeccompConfig(s *specgen.SpecGenerator, configSpec *spec.Spec, img *libimage.Image) (*spec.LinuxSeccomp, error) {
var seccompConfig *spec.LinuxSeccomp
var err error
scp, err := seccomp.LookupPolicy(s.SeccompPolicy)
if err != nil {
return nil, err
}
if scp == seccomp.PolicyImage {
if img == nil {
return nil, errors.New("cannot read seccomp profile without a valid image")
}
labels, err := img.Labels(context.Background())
if err != nil {
return nil, err
}
imagePolicy := labels[seccomp.ContainerImageLabel]
if len(imagePolicy) < 1 {
return nil, errors.New("no seccomp policy defined by image")
}
logrus.Debug("Loading seccomp profile from the security config")
seccompConfig, err = goSeccomp.LoadProfile(imagePolicy, configSpec)
if err != nil {
return nil, fmt.Errorf("loading seccomp profile failed: %w", err)
}
return seccompConfig, nil
}
switch {
case s.SeccompProfile != "":
logrus.Debug("Loading inline seccomp profile")
seccompConfig, err = goSeccomp.LoadProfile(s.SeccompProfile, configSpec)
if err != nil {
return nil, fmt.Errorf("loading inline seccomp profile failed: %w", err)
}
case s.SeccompProfilePath != "":
logrus.Debugf("Loading seccomp profile from %q", s.SeccompProfilePath)
seccompProfile, err := os.ReadFile(s.SeccompProfilePath)
if err != nil {
return nil, fmt.Errorf("opening seccomp profile failed: %w", err)
}
seccompConfig, err = goSeccomp.LoadProfile(string(seccompProfile), configSpec)
if err != nil {
return nil, fmt.Errorf("loading seccomp profile (%s) failed: %w", s.SeccompProfilePath, err)
}
default:
logrus.Debug("Loading default seccomp profile")
seccompConfig, err = goSeccomp.GetDefaultProfile(configSpec)
if err != nil {
return nil, fmt.Errorf("loading seccomp profile (%s) failed: %w", s.SeccompProfilePath, err)
}
}
return seccompConfig, nil
}