diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 9920f6b20b..a285d7d12c 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -308,10 +308,6 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra if c.Flag("cgroups").Changed && vals.CgroupsMode == "split" && registry.IsRemote() { return vals, fmt.Errorf("the option --cgroups=%q is not supported in remote mode", vals.CgroupsMode) } - - if c.Flag("pod").Changed && !strings.HasPrefix(c.Flag("pod").Value.String(), "new:") && c.Flag("userns").Changed { - return vals, errors.New("--userns and --pod cannot be set together") - } } if c.Flag("shm-size").Changed { vals.ShmSize = c.Flag("shm-size").Value.String() diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index a7295334cd..01d716ebe9 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -21,6 +21,23 @@ import ( const host = "host" +// userNSConflictsWithPod returns an error if the user namespace mode +// conflicts with pod namespace sharing requirements. +// Containers in a pod must use the same user namespace to avoid ownership and +// capability issues with shared resources. +func userNSConflictsWithPod(pod *libpod.Pod, mode specgen.NamespaceMode) error { + if pod != nil && pod.HasInfraContainer() { + // Allow modes that don't create a new user namespace + switch mode { + case specgen.FromPod, specgen.Default, specgen.Host, specgen.FromContainer: + return nil + default: + return fmt.Errorf("cannot set user namespace mode when joining pod with infra container: %w", define.ErrInvalidArg) + } + } + return nil +} + // Get the default namespace mode for any given namespace type. func GetDefaultNamespaceMode(nsType string, cfg *config.Config, pod *libpod.Pod) (specgen.Namespace, error) { // The default for most is private @@ -211,7 +228,11 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod. } } - // User + // Validate that user namespace mode is compatible with pod. + if err := userNSConflictsWithPod(pod, s.UserNS.NSMode); err != nil { + return nil, err + } + switch s.UserNS.NSMode { case specgen.KeepID: opts, err := namespaces.UsernsMode(s.UserNS.String()).GetKeepIDOptions() @@ -247,6 +268,10 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod. return nil, fmt.Errorf("looking up container to share user namespace with: %w", err) } toReturn = append(toReturn, libpod.WithUserNSFrom(userCtr)) + case specgen.Private: + case specgen.Auto: + case specgen.NoMap: + case specgen.Path: } // This wipes the UserNS settings that get set from the infra container @@ -255,8 +280,6 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod. if s.IDMappings != nil { if pod == nil { toReturn = append(toReturn, libpod.WithIDMappings(*s.IDMappings)) - } else if pod.HasInfraContainer() && (len(s.IDMappings.UIDMap) > 0 || len(s.IDMappings.GIDMap) > 0) { - return nil, fmt.Errorf("cannot specify a new uid/gid map when entering a pod with an infra container: %w", define.ErrInvalidArg) } } if s.User != "" { diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 32de6cdccb..1a4205a86a 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -678,12 +678,14 @@ var _ = Describe("Podman create", func() { create := podmanTest.Podman([]string{"create", "--uidmap", "0:1000:1000", "--pod", "new:testing123", ALPINE}) create.WaitWithDefaultTimeout() Expect(create).ShouldNot(ExitCleanly()) - Expect(create.ErrorToString()).To(ContainSubstring("cannot specify a new uid/gid map when entering a pod with an infra container")) + Expect(create.ErrorToString()).To(ContainSubstring("cannot set user namespace mode when joining pod with infra container")) + + podmanTest.PodmanExitCleanly("pod", "rm", "-f", "testing123") create = podmanTest.Podman([]string{"create", "--gidmap", "0:1000:1000", "--pod", "new:testing1234", ALPINE}) create.WaitWithDefaultTimeout() Expect(create).ShouldNot(ExitCleanly()) - Expect(create.ErrorToString()).To(ContainSubstring("cannot specify a new uid/gid map when entering a pod with an infra container")) + Expect(create.ErrorToString()).To(ContainSubstring("cannot set user namespace mode when joining pod with infra container")) }) It("podman create --chrootdirs inspection test", func() { diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 9eab96fafb..a8225df259 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -803,7 +803,7 @@ ENTRYPOINT ["sleep","99999"] // fail if --pod and --userns set together session = podmanTest.Podman([]string{"run", "--pod", podName, "--userns", "keep-id", ALPINE, "id", "-u"}) session.WaitWithDefaultTimeout() - Expect(session).Should(ExitWithError(125, "--userns and --pod cannot be set together")) + Expect(session).Should(ExitWithError(125, "cannot set user namespace mode when joining pod with infra container")) }) It("podman pod create with --userns=keep-id can add users", func() { diff --git a/test/system/620-option-conflicts.bats b/test/system/620-option-conflicts.bats index f3889b3655..8851fbdf40 100644 --- a/test/system/620-option-conflicts.bats +++ b/test/system/620-option-conflicts.bats @@ -14,7 +14,6 @@ load helpers create,run | --cpu-period=1 | --cpus=2 | $IMAGE create,run | --cpu-quota=1 | --cpus=2 | $IMAGE create,run | --no-hosts | --add-host=foo:1.1.1.1 | $IMAGE -create,run | --userns=bar | --pod=foo | $IMAGE container cleanup | --all | --exec=foo container cleanup | --exec=foo | --rmi | foo " @@ -48,6 +47,14 @@ container cleanup | --exec=foo | --rmi | foo "podman $cmd --platform + --$opt" done done + + # --userns and --pod have a different error message format + podname=p-$(safename) + run_podman pod create --name $podname + run_podman 125 run --uidmap=0:1000:1000 --pod=$podname $IMAGE true + is "$output" "Error: cannot set user namespace mode when joining pod with infra container: invalid argument" \ + "podman run --uidmap + --pod" + run_podman pod rm -f $podname }