From 76ae0c907591b60374febdd8bd41f90cbc5444b6 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 11 Aug 2020 11:29:49 +0200 Subject: Enable systemd mode for /usr/local/sbin/init Podman 1.6.2 changed systemd mode auto-detection from commands ending in ``init`` to hard-coded paths ``/sbin/init`` and ``/usr/sbin/init``. This broke FreeIPA container. ``podman run`` and ``podman create`` now activate systemd mode when the command is ``/usr/local/sbin/init``. Fixes: https://github.com/containers/podman/issues/7287 Signed-off-by: Christian Heimes --- pkg/specgen/generate/container_create.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'pkg/specgen') diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index be1e3b48e..630e59854 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -153,13 +153,14 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. } if len(command) > 0 { - if command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || (filepath.Base(command[0]) == "systemd") { + if command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || command[0] == "/usr/local/sbin/init" || (filepath.Base(command[0]) == "systemd") { useSystemd = true } } default: return nil, errors.Wrapf(err, "invalid value %q systemd option requires 'true, false, always'", s.Systemd) } + logrus.Debugf("using systemd mode: %t", useSystemd) if useSystemd { // is StopSignal was not set by the user then set it to systemd // expected StopSigal -- cgit v1.2.3-54-g00ecf From 7fb53bc240cea153fb054bcd307d3b1a8945a435 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 11 Aug 2020 13:29:17 +0200 Subject: Use set for systemd commands Signed-off-by: Christian Heimes --- pkg/specgen/generate/container_create.go | 7 ++++++- pkg/varlinkapi/create.go | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'pkg/specgen') diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 630e59854..b31bc91e0 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -153,7 +153,12 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. } if len(command) > 0 { - if command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || command[0] == "/usr/local/sbin/init" || (filepath.Base(command[0]) == "systemd") { + useSystemdCommands := map[string]bool{ + "/sbin/init": true, + "/usr/sbin/init": true, + "/usr/local/sbin/init": true, + } + if useSystemdCommands[command[0]] || (filepath.Base(command[0]) == "systemd") { useSystemd = true } } diff --git a/pkg/varlinkapi/create.go b/pkg/varlinkapi/create.go index 249505486..7661173b8 100644 --- a/pkg/varlinkapi/create.go +++ b/pkg/varlinkapi/create.go @@ -704,7 +704,12 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. if err != nil { return nil, errors.Wrapf(err, "cannot parse bool %s", c.String("systemd")) } - if x && (command[0] == "/usr/sbin/init" || command[0] == "/sbin/init" || command[0] == "/usr/local/sbin/init" || (filepath.Base(command[0]) == "systemd")) { + useSystemdCommands := map[string]bool{ + "/sbin/init": true, + "/usr/sbin/init": true, + "/usr/local/sbin/init": true, + } + if x && (useSystemdCommands[command[0]] || (filepath.Base(command[0]) == "systemd")) { systemd = true } } -- cgit v1.2.3-54-g00ecf From 66fcafa4d45a26b59ad3662419cd3c778e23c39c Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Mon, 10 Aug 2020 10:16:28 +0200 Subject: Allow specifying seccomp profiles for privileged containers To sync the behavior between AppArmor and seccomp it is now possible to also specify seccomp profiles for privileged containers. Signed-off-by: Sascha Grunert --- pkg/specgen/generate/security.go | 5 +++-- test/e2e/run_test.go | 30 +++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'pkg/specgen') diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go index fcd1622f9..840dcb72d 100644 --- a/pkg/specgen/generate/security.go +++ b/pkg/specgen/generate/security.go @@ -158,8 +158,9 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, configSpec.Linux.Seccomp = seccompConfig } - // Clear default Seccomp profile from Generator for privileged containers - if s.SeccompProfilePath == "unconfined" || s.Privileged { + // 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 == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) { configSpec.Linux.Seccomp = nil } diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 95eecd042..13f0db550 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -183,22 +183,46 @@ var _ = Describe("Podman run", func() { Expect(conData[0].Config.Annotations["io.podman.annotations.init"]).To(Equal("FALSE")) }) - It("podman run seccomp test", func() { - + forbidGetCWDSeccompProfile := func() string { in := []byte(`{"defaultAction":"SCMP_ACT_ALLOW","syscalls":[{"name":"getcwd","action":"SCMP_ACT_ERRNO"}]}`) jsonFile, err := podmanTest.CreateSeccompJson(in) if err != nil { fmt.Println(err) Skip("Failed to prepare seccomp.json for test.") } + return jsonFile + } + + It("podman run seccomp test", func() { + session := podmanTest.Podman([]string{"run", "-it", "--security-opt", strings.Join([]string{"seccomp=", forbidGetCWDSeccompProfile()}, ""), ALPINE, "pwd"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + match, _ := session.GrepString("Operation not permitted") + Expect(match).Should(BeTrue()) + }) - session := podmanTest.Podman([]string{"run", "-it", "--security-opt", strings.Join([]string{"seccomp=", jsonFile}, ""), ALPINE, "pwd"}) + It("podman run seccomp test --privileged", func() { + session := podmanTest.Podman([]string{"run", "-it", "--privileged", "--security-opt", strings.Join([]string{"seccomp=", forbidGetCWDSeccompProfile()}, ""), ALPINE, "pwd"}) session.WaitWithDefaultTimeout() Expect(session).To(ExitWithError()) match, _ := session.GrepString("Operation not permitted") Expect(match).Should(BeTrue()) }) + It("podman run seccomp test --privileged no profile should be unconfined", func() { + session := podmanTest.Podman([]string{"run", "-it", "--privileged", ALPINE, "grep", "Seccomp", "/proc/self/status"}) + session.WaitWithDefaultTimeout() + Expect(session.OutputToString()).To(ContainSubstring("0")) + Expect(session.ExitCode()).To(Equal(0)) + }) + + It("podman run seccomp test no profile should be default", func() { + session := podmanTest.Podman([]string{"run", "-it", ALPINE, "grep", "Seccomp", "/proc/self/status"}) + session.WaitWithDefaultTimeout() + Expect(session.OutputToString()).To(ContainSubstring("2")) + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman run capabilities test", func() { session := podmanTest.Podman([]string{"run", "--rm", "--cap-add", "all", ALPINE, "cat", "/proc/self/status"}) session.WaitWithDefaultTimeout() -- cgit v1.2.3-54-g00ecf From d4c3365454d903077ece3c1a31367f639ee24900 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Fri, 31 Jul 2020 17:08:06 -0400 Subject: Ensure WORKDIR from images is created A recent crun change stopped the creation of the container's working directory if it does not exist. This is arguably correct for user-specified directories, to protect against typos; it is definitely not correct for image WORKDIR, where the image author definitely intended for the directory to be used. This makes Podman create the working directory and chown it to container root, if it does not already exist, and only if it was specified by an image, not the user. Signed-off-by: Matthew Heon --- libpod/container.go | 4 ++++ libpod/container_internal_linux.go | 27 ++++++++++++++++++++++++++- libpod/options.go | 13 +++++++++++++ pkg/specgen/generate/container_create.go | 11 +++++++++++ test/e2e/run_test.go | 10 ++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) (limited to 'pkg/specgen') diff --git a/libpod/container.go b/libpod/container.go index 9ad938a5c..644647bc9 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -261,6 +261,10 @@ type ContainerConfig struct { Mounts []string `json:"mounts,omitempty"` // NamedVolumes lists the named volumes to mount into the container. NamedVolumes []*ContainerNamedVolume `json:"namedVolumes,omitempty"` + // CreateWorkingDir indicates that Libpod should create the container's + // working directory if it does not exist. Some OCI runtimes do this by + // default, but others do not. + CreateWorkingDir bool `json:"createWorkingDir,omitempty"` // Security Config diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index b9e4f9a93..0d9a1c824 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -157,7 +157,32 @@ func (c *Container) prepare() error { } // Save changes to container state - return c.save() + if err := c.save(); err != nil { + return err + } + + // Ensure container entrypoint is created (if required) + if c.config.CreateWorkingDir { + workdir, err := securejoin.SecureJoin(c.state.Mountpoint, c.WorkingDir()) + if err != nil { + return errors.Wrapf(err, "error creating path to container %s working dir", c.ID()) + } + rootUID := c.RootUID() + rootGID := c.RootGID() + + if err := os.MkdirAll(workdir, 0755); err != nil { + if os.IsExist(err) { + return nil + } + return errors.Wrapf(err, "error creating container %s working dir", c.ID()) + } + + if err := os.Chown(workdir, rootUID, rootGID); err != nil { + return errors.Wrapf(err, "error chowning container %s working directory to container root", c.ID()) + } + } + + return nil } // cleanupNetwork unmounts and cleans up the container's network diff --git a/libpod/options.go b/libpod/options.go index 560b406e2..a4e4b99e9 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1395,6 +1395,19 @@ func WithCreateCommand(cmd []string) CtrCreateOption { } } +// WithCreateWorkingDir tells Podman to create the container's working directory +// if it does not exist. +func WithCreateWorkingDir() CtrCreateOption { + return func(ctr *Container) error { + if ctr.valid { + return define.ErrCtrFinalized + } + + ctr.config.CreateWorkingDir = true + return nil + } +} + // Volume Creation Options // WithVolumeName sets the name of the volume. diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index b31bc91e0..42be5e812 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -215,6 +215,17 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. if s.Entrypoint != nil { options = append(options, libpod.WithEntrypoint(s.Entrypoint)) } + // If the user did not set an workdir but the image did, ensure it is + // created. + if s.WorkDir == "" && img != nil { + newWD, err := img.WorkingDir(ctx) + if err != nil { + return nil, err + } + if newWD != "" { + options = append(options, libpod.WithCreateWorkingDir()) + } + } if s.StopSignal != nil { options = append(options, libpod.WithStopSignal(*s.StopSignal)) } diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 13f0db550..ef275b32e 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1060,4 +1060,14 @@ USER mail` Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring(limit)) }) + + It("podman run makes entrypoint from image", func() { + dockerfile := `FROM busybox +WORKDIR /madethis` + podmanTest.BuildImage(dockerfile, "test", "false") + session := podmanTest.Podman([]string{"run", "--rm", "test", "pwd"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring("/madethis")) + }) }) -- cgit v1.2.3-54-g00ecf From 32f0c8f624e0400a6decf219d6fe889f12272729 Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Fri, 7 Aug 2020 13:57:02 -0400 Subject: Do not use image CMD if user gave ENTRYPOINT This matches Docker behavior, and seems to make sense - the CMD may have been specific to the original entrypoint and probably does not make sense if it was changed. While we're in here, greatly simplify the logic for populating the SpecGen's Command. We create the full command when making the OCI spec, so the client should not be doing any more than setting it to the Command the user passed in, and completely ignoring ENTRYPOINT. Fixes #7115 Signed-off-by: Matthew Heon --- cmd/podman/common/specgen.go | 18 +----------------- pkg/specgen/generate/oci.go | 4 +++- test/e2e/run_test.go | 11 +++++------ 3 files changed, 9 insertions(+), 24 deletions(-) (limited to 'pkg/specgen') diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 2333f2f7e..48a2069ff 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -387,8 +387,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string s.Annotations = annotations s.WorkDir = c.Workdir - userCommand := []string{} - var command []string if c.Entrypoint != nil { entrypoint := []string{} if ep := *c.Entrypoint; len(ep) > 0 { @@ -398,27 +396,13 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string } } s.Entrypoint = entrypoint - // Build the command - // If we have an entry point, it goes first - command = entrypoint } // Include the command used to create the container. s.ContainerCreateCommand = os.Args if len(inputCommand) > 0 { - // User command overrides data CMD - command = append(command, inputCommand...) - userCommand = append(userCommand, inputCommand...) - } - - switch { - case len(inputCommand) > 0: - s.Command = userCommand - case c.Entrypoint != nil: - s.Command = []string{} - default: - s.Command = command + s.Command = inputCommand } // SHM Size diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index f279aac1c..f1c9f2a1a 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -96,8 +96,10 @@ func makeCommand(ctx context.Context, s *specgen.SpecGenerator, img *image.Image finalCommand = append(finalCommand, entrypoint...) + // Only use image command if the user did not manually set an + // entrypoint. command := s.Command - if command == nil && img != nil { + if command == nil && img != nil && s.Entrypoint == nil { newCmd, err := img.Cmd(ctx) if err != nil { return nil, err diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index ef275b32e..681498ea1 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1061,13 +1061,12 @@ USER mail` Expect(session.OutputToString()).To(ContainSubstring(limit)) }) - It("podman run makes entrypoint from image", func() { - dockerfile := `FROM busybox -WORKDIR /madethis` - podmanTest.BuildImage(dockerfile, "test", "false") - session := podmanTest.Podman([]string{"run", "--rm", "test", "pwd"}) + It("podman run --entrypoint does not use image command", func() { + session := podmanTest.Podman([]string{"run", "--entrypoint", "/bin/echo", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(ContainSubstring("/madethis")) + // We can't guarantee the output is completely empty, some + // nonprintables seem to work their way in. + Expect(session.OutputToString()).To(Not(ContainSubstring("/bin/sh"))) }) }) -- cgit v1.2.3-54-g00ecf From fc24c0cc102de911387ed6b768173604fecb1eee Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Wed, 5 Aug 2020 16:28:47 -0400 Subject: Fix handling of working dir Buildah and podman build can create images without a working dir. FROM fedora WORKDIR /test If you build this image with caching twice, the second time the image will not have a working dir. Similarly if you execute podman run --workdir /foobar fedora It blows up since the workingdir is not created automatically. Finally there was duplicated code for getting the workingdir out of an image, that this PR removes. Signed-off-by: Daniel J Walsh --- pkg/specgen/container_validate.go | 5 --- pkg/specgen/generate/container.go | 15 ++++--- pkg/specgen/generate/container_create.go | 8 +--- test/e2e/run_working_dir.go | 69 ++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 test/e2e/run_working_dir.go (limited to 'pkg/specgen') diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go index 57dd2aba7..a979a7f4a 100644 --- a/pkg/specgen/container_validate.go +++ b/pkg/specgen/container_validate.go @@ -135,11 +135,6 @@ func (s *SpecGenerator) Validate() error { return err } - // The following are defaults as needed by container creation - if len(s.WorkDir) < 1 { - s.WorkDir = "/" - } - // Set defaults if network info is not provided if s.NetNS.NSMode == "" { s.NetNS.NSMode = Bridge diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index f0d52d0c3..59fee80f1 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -135,15 +135,18 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat s.Annotations = annotations // workdir - if newImage != nil { - workingDir, err := newImage.WorkingDir(ctx) - if err != nil { - return nil, err - } - if len(s.WorkDir) < 1 && len(workingDir) > 1 { + if s.WorkDir == "" { + if newImage != nil { + workingDir, err := newImage.WorkingDir(ctx) + if err != nil { + return nil, err + } s.WorkDir = workingDir } } + if s.WorkDir == "" { + s.WorkDir = "/" + } if len(s.SeccompProfilePath) < 1 { p, err := libpod.DefaultSeccompPath() diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 42be5e812..6c0a702d6 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -218,13 +218,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen. // If the user did not set an workdir but the image did, ensure it is // created. if s.WorkDir == "" && img != nil { - newWD, err := img.WorkingDir(ctx) - if err != nil { - return nil, err - } - if newWD != "" { - options = append(options, libpod.WithCreateWorkingDir()) - } + options = append(options, libpod.WithCreateWorkingDir()) } if s.StopSignal != nil { options = append(options, libpod.WithStopSignal(*s.StopSignal)) diff --git a/test/e2e/run_working_dir.go b/test/e2e/run_working_dir.go new file mode 100644 index 000000000..93330deba --- /dev/null +++ b/test/e2e/run_working_dir.go @@ -0,0 +1,69 @@ +package integration + +import ( + "os" + "strings" + + . "github.com/containers/podman/v2/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman run", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("podman run a container without workdir", func() { + session := podmanTest.Podman([]string{"run", ALPINE, "pwd"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("/")) + }) + + It("podman run a container using non existing --workdir", func() { + if !strings.Contains(podmanTest.OCIRuntime, "crun") { + Skip("Test only works on crun") + } + session := podmanTest.Podman([]string{"run", "--workdir", "/home/foobar", ALPINE, "pwd"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(127)) + }) + + It("podman run a container on an image with a workdir", func() { + SkipIfRemote() + dockerfile := `FROM alpine +RUN mkdir -p /home/foobar +WORKDIR /etc/foobar` + podmanTest.BuildImage(dockerfile, "test", "false") + + session := podmanTest.Podman([]string{"run", "test", "pwd"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("/etc/foobar")) + + session = podmanTest.Podman([]string{"run", "--workdir", "/home/foobar", "test", "pwd"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(Equal("/home/foobar")) + }) +}) -- cgit v1.2.3-54-g00ecf From 23348e7f313a570c513772a88db7f2741c8242ba Mon Sep 17 00:00:00 2001 From: Matthew Heon Date: Fri, 31 Jul 2020 13:52:14 -0400 Subject: Ensure DefaultEnvVariables is used in Specgen When we rewrote Podman's pkg/spec, one of the things that was lost was our use of a set of default environment variables, that ensure all containers have at least $PATH and $TERM set. While we're in the process of re-adding it, change it from a variable to a function, so we can ensure the Join function does not overwrite it and corrupt the defaults. Signed-off-by: Matthew Heon --- cmd/podman/common/specgen.go | 5 ++--- pkg/env/env.go | 14 ++++++++------ pkg/spec/spec.go | 4 ++-- pkg/specgen/generate/container.go | 9 +++++++++ pkg/specgen/generate/oci.go | 1 - 5 files changed, 21 insertions(+), 12 deletions(-) (limited to 'pkg/specgen') diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go index 48a2069ff..2074ed4fa 100644 --- a/cmd/podman/common/specgen.go +++ b/cmd/podman/common/specgen.go @@ -308,9 +308,8 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string // // Precedence order (higher index wins): // 1) env-host, 2) image data, 3) env-file, 4) env - env := map[string]string{ - "container": "podman", - } + env := make(map[string]string) + env["container"] = "podman" // First transform the os env into a map. We need it for the labels later in // any case. diff --git a/pkg/env/env.go b/pkg/env/env.go index a16007a50..0d55e5560 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -12,14 +12,16 @@ import ( "github.com/pkg/errors" ) -// DefaultEnvVariables sets $PATH and $TERM. -var DefaultEnvVariables = map[string]string{ - "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "TERM": "xterm", -} - const whiteSpaces = " \t" +// DefaultEnvVariables returns a default environment, with $PATH and $TERM set. +func DefaultEnvVariables() map[string]string { + return map[string]string{ + "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM": "xterm", + } +} + // Slice transforms the specified map of environment variables into a // slice. If a value is non-empty, the key and value are joined with '='. func Slice(m map[string]string) []string { diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index b974772d5..0dbdc76bb 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -321,13 +321,13 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM // config. var defaultEnv map[string]string if runtimeConfig == nil { - defaultEnv = env.DefaultEnvVariables + defaultEnv = env.DefaultEnvVariables() } else { defaultEnv, err = env.ParseSlice(runtimeConfig.Containers.Env) if err != nil { return nil, errors.Wrap(err, "Env fields in containers.conf failed ot parse") } - defaultEnv = env.Join(env.DefaultEnvVariables, defaultEnv) + defaultEnv = env.Join(env.DefaultEnvVariables(), defaultEnv) } if err := addRlimits(config, &g); err != nil { diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 59fee80f1..06ffa3df6 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -86,6 +86,15 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat s.Env = envLib.Join(envLib.Join(defaultEnvs, envs), s.Env) + // Ensure that default environment variables are populated. + // Container must have PATH and TERM set, even if nothing else set them. + baseEnv := envLib.DefaultEnvVariables() + for k, v := range baseEnv { + if _, ok := s.Env[k]; !ok { + s.Env[k] = v + } + } + // Labels and Annotations annotations := make(map[string]string) if newImage != nil { diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index f1c9f2a1a..aefc7204c 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -260,7 +260,6 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt for key, val := range s.Annotations { g.AddAnnotation(key, val) } - g.AddProcessEnv("container", "podman") g.Config.Linux.Resources = s.ResourceLimits -- cgit v1.2.3-54-g00ecf From 0ef668878572986951df57fb38596683e5750d07 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Tue, 18 Aug 2020 12:19:28 +0200 Subject: fix podman create/run UTS NS docs Add better error message when using `--pod` and `--hostname`. Improve the docs to better explain the uts hostname relation. Add more valid options for the `--uts` flag. Signed-off-by: Paul Holzinger --- docs/source/markdown/podman-create.1.md | 14 ++++++++------ docs/source/markdown/podman-run.1.md | 9 ++++----- pkg/specgen/container_validate.go | 3 +++ 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'pkg/specgen') diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index ffce338b4..00f16d0a3 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -336,7 +336,7 @@ value can be expressed in a time format such as `1m22s`. The default value is ` Container host name -Sets the container host name that is available inside the container. +Sets the container host name that is available inside the container. Can only be used with a private UTS namespace `--uts=private` (default). If `--pod` is specified and the pod shares the UTS namespace (default) the pods hostname will be used. **--help** @@ -862,12 +862,14 @@ Set the user namespace mode for the container. It defaults to the **PODMAN_USER This option is incompatible with --gidmap, --uidmap, --subuid and --subgid -**--uts**=*host* +**--uts**=*mode* -Set the UTS mode for the container - **host**: use the host's UTS namespace inside the container. - **ns**: specify the user namespace to use. - Note: the host mode gives the container access to changing the host's hostname and is therefore considered insecure. +Set the UTS namespace mode for the container. The following values are supported: + +- **host**: use the host's UTS namespace inside the container. +- **private**: create a new namespace for the container (default). +- **ns:[path]**: run the container in the given existing UTS namespace. +- **container:[container]**: join the UTS namespace of the specified container. **--volume**, **-v**[=*[[SOURCE-VOLUME|HOST-DIR:]CONTAINER-DIR[:OPTIONS]]*] diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 25bb44c06..5febf1c66 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -356,7 +356,7 @@ Print usage statement Container host name -Sets the container host name that is available inside the container. +Sets the container host name that is available inside the container. Can only be used with a private UTS namespace `--uts=private` (default). If `--pod` is specified and the pod shares the UTS namespace (default) the pods hostname will be used. **--http-proxy**=**true**|**false** @@ -900,10 +900,9 @@ This option is incompatible with **--gidmap**, **--uidmap**, **--subuid** and ** Set the UTS namespace mode for the container. The following values are supported: - **host**: use the host's UTS namespace inside the container. -- **private**: create a new namespace for the container (default) -- **ns**: use own UTS namespace. - -**NOTE**: the host mode gives the container access to changing the host's hostname and is therefore considered insecure. +- **private**: create a new namespace for the container (default). +- **ns:[path]**: run the container in the given existing UTS namespace. +- **container:[container]**: join the UTS namespace of the specified container. **--volume**, **-v**[=[[_source-volume_|_host-dir_:]_container-dir_[:_options_]]] diff --git a/pkg/specgen/container_validate.go b/pkg/specgen/container_validate.go index a979a7f4a..4dd2ab0b3 100644 --- a/pkg/specgen/container_validate.go +++ b/pkg/specgen/container_validate.go @@ -43,6 +43,9 @@ func (s *SpecGenerator) Validate() error { } // Cannot set hostname and utsns if len(s.ContainerBasicConfig.Hostname) > 0 && !s.ContainerBasicConfig.UtsNS.IsPrivate() { + if s.ContainerBasicConfig.UtsNS.IsPod() { + return errors.Wrap(ErrInvalidSpecConfig, "cannot set hostname when joining the pod UTS namespace") + } return errors.Wrap(ErrInvalidSpecConfig, "cannot set hostname when running in the host UTS namespace") } // systemd values must be true, false, or always -- cgit v1.2.3-54-g00ecf