Files
podman/pkg/specgen/generate/container_create_test.go
Giuseppe Scrivano 458fcaa1ba specgen: fix pod mount options leaking between mounts
Replace the JSON marshal/unmarshal round-trip in Inherit() with
copier.Copy. json.Unmarshal reuses existing slice backing arrays
and does not zero struct fields absent from the JSON (omitempty),
so mount options like "ro" from one mount would leak into another
mount at the same backing-array position.

Fixes the case where running:
  podman run --pod mypod \
    --mount type=bind,src=/a,target=/mylog \
    --mount type=bind,src=/b,target=/mytmp,ro=true \
    alpine touch /mylog/a

incorrectly fails with "Read-only file system" because /mylog
inherits "ro" from /mytmp.

Fixes: https://issues.redhat.com/browse/RHEL-154348

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
2026-03-10 09:14:38 +01:00

61 lines
1.8 KiB
Go

//go:build !remote && (linux || freebsd)
package generate
import (
"testing"
"github.com/containers/podman/v6/libpod"
"github.com/containers/podman/v6/pkg/specgen"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestApplyInfraInheritMountOptionsDoNotLeak verifies that mount options from
// one mount do not leak into another when calling applyInfraInherit.
func TestApplyInfraInheritMountOptionsDoNotLeak(t *testing.T) {
compatibleOptions := &libpod.InfraInherit{
Mounts: []spec.Mount{
{Destination: "/mylog", Source: "/a", Type: "bind"},
{Destination: "/mytmp", Source: "/b", Type: "bind", Options: []string{"ro"}},
},
}
s := &specgen.SpecGenerator{}
s.Mounts = []spec.Mount{
{Destination: "/mytmp", Source: "/b", Type: "bind", Options: []string{"ro"}},
{Destination: "/mylog", Source: "/a", Type: "bind"},
}
err := applyInfraInherit(compatibleOptions, s)
require.NoError(t, err)
for _, m := range s.Mounts {
if m.Destination == "/mylog" {
assert.Empty(t, m.Options,
"/mylog should have no options; ro from /mytmp leaked")
}
if m.Destination == "/mytmp" {
assert.Equal(t, []string{"ro"}, m.Options,
"/mytmp should keep its ro option")
}
}
}
// TestApplyInfraInheritDoesNotOverwriteSeccomp verifies that applyInfraInherit
// does not overwrite a pre-set SeccompProfilePath when the infra container has
// no seccomp profile (empty string).
func TestApplyInfraInheritDoesNotOverwriteSeccomp(t *testing.T) {
compatibleOptions := &libpod.InfraInherit{}
s := &specgen.SpecGenerator{}
s.SeccompProfilePath = "localhost/seccomp.json"
err := applyInfraInherit(compatibleOptions, s)
require.NoError(t, err)
assert.Equal(t, "localhost/seccomp.json", s.SeccompProfilePath,
"SeccompProfilePath should not be overwritten by empty infra value")
}