From 18d6bb40d52fe1444181decd57088a6b65357bb5 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Fri, 8 Sep 2023 07:03:49 -0400 Subject: [PATCH] Support passing of Ulimits as -1 to mean max Docker allows the passing of -1 to indicate the maximum limit allowed for the current process. Fixes: https://github.com/containers/podman/issues/19319 Signed-off-by: Daniel J Walsh --- docs/source/markdown/options/ulimit.md | 3 +++ libpod/container_internal_common.go | 3 ++- libpod/oci_conmon_linux.go | 1 - pkg/specgen/generate/oci.go | 1 + pkg/specgen/generate/oci_freebsd.go | 5 ++++ pkg/specgen/generate/oci_linux.go | 36 ++++++++++++++++++++++++++ test/e2e/inspect_test.go | 2 +- test/system/030-run.bats | 17 ++++++++++++ 8 files changed, 65 insertions(+), 3 deletions(-) diff --git a/docs/source/markdown/options/ulimit.md b/docs/source/markdown/options/ulimit.md index b018cf5cb6..be5bdaecb6 100644 --- a/docs/source/markdown/options/ulimit.md +++ b/docs/source/markdown/options/ulimit.md @@ -11,6 +11,9 @@ Ulimit options. Sets the ulimits values inside of the container. $ podman run --ulimit nofile=1024:1024 --rm ubi9 ulimit -n 1024 +Set -1 for the soft or hard limit to set the limit to the maximum limit of the current +process. In rootful mode this is often unlimited. + Use **host** to copy the current configuration from the host. Don't use nproc with the ulimit flag as Linux uses nproc to set the diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 83749ec0f1..d78a583400 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -644,7 +644,8 @@ func (c *Container) generateSpec(ctx context.Context) (s *spec.Spec, cleanupFunc for _, rlimit := range c.config.Spec.Process.Rlimits { if rlimit.Type == "RLIMIT_NOFILE" { nofileSet = true - } else if rlimit.Type == "RLIMIT_NPROC" { + } + if rlimit.Type == "RLIMIT_NPROC" { nprocSet = true } } diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 527dea8370..d68a303331 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -324,6 +324,5 @@ func GetLimits(resource *spec.LinuxResources) (runcconfig.Resources, error) { // Unified state final.Unified = resource.Unified - return *final, nil } diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index fdeebe333e..c5f643308b 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -18,6 +18,7 @@ func addRlimits(s *specgen.SpecGenerator, g *generate.Generator) { for _, u := range s.Rlimits { name := "RLIMIT_" + strings.ToUpper(u.Type) + u = subNegativeOne(u) g.AddProcessRlimits(name, u.Hard, u.Soft) } } diff --git a/pkg/specgen/generate/oci_freebsd.go b/pkg/specgen/generate/oci_freebsd.go index 4546e37d73..bccb461934 100644 --- a/pkg/specgen/generate/oci_freebsd.go +++ b/pkg/specgen/generate/oci_freebsd.go @@ -13,6 +13,7 @@ import ( "github.com/containers/podman/v4/libpod" "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/specgen" + "github.com/opencontainers/runtime-spec/specs-go" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" ) @@ -172,3 +173,7 @@ func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWei devs := []spec.LinuxWeightDevice{} return devs, nil } + +func subNegativeOne(u specs.POSIXRlimit) specs.POSIXRlimit { + return u +} diff --git a/pkg/specgen/generate/oci_linux.go b/pkg/specgen/generate/oci_linux.go index aa8f77e761..7ea22e9f71 100644 --- a/pkg/specgen/generate/oci_linux.go +++ b/pkg/specgen/generate/oci_linux.go @@ -17,8 +17,10 @@ import ( "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/rootless" "github.com/containers/podman/v4/pkg/specgen" + "github.com/docker/go-units" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" + "github.com/sirupsen/logrus" "golang.org/x/sys/unix" ) @@ -357,3 +359,37 @@ func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWei } return devs, nil } + +// subNegativeOne translates Hard or soft limits of -1 to the current +// processes Max limit +func subNegativeOne(u spec.POSIXRlimit) spec.POSIXRlimit { + if !rootless.IsRootless() || + (int64(u.Hard) != -1 && int64(u.Soft) != -1) { + return u + } + + ul, err := units.ParseUlimit(fmt.Sprintf("%s=%d:%d", u.Type, int64(u.Soft), int64(u.Hard))) + if err != nil { + logrus.Warnf("Failed to check %s ulimit %q", u.Type, err) + return u + } + rl, err := ul.GetRlimit() + if err != nil { + logrus.Warnf("Failed to check %s ulimit %q", u.Type, err) + return u + } + + var rlimit unix.Rlimit + + if err := unix.Getrlimit(rl.Type, &rlimit); err != nil { + logrus.Warnf("Failed to return RLIMIT_NOFILE ulimit %q", err) + return u + } + if int64(u.Hard) == -1 { + u.Hard = rlimit.Max + } + if int64(u.Soft) == -1 { + u.Soft = rlimit.Max + } + return u +} diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 20e2265742..1f0e7efb3f 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -465,7 +465,7 @@ var _ = Describe("Podman inspect", func() { Expect(inspect[0].NetworkSettings.Networks).To(HaveLen(1)) }) - It("Container inspect with unlimited uilimits should be -1", func() { + It("Container inspect with unlimited ulimits should be -1", func() { ctrName := "testctr" session := podmanTest.Podman([]string{"run", "-d", "--ulimit", "core=-1:-1", "--name", ctrName, ALPINE, "top"}) session.WaitWithDefaultTimeout() diff --git a/test/system/030-run.bats b/test/system/030-run.bats index e688e8e833..2a1cdcf9ce 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -1149,6 +1149,23 @@ EOF assert "$output" =~ " ${nofile2} * ${nofile2} * files" } +@test "podman run ulimit with -1" { + max=unlimited + if is_rootless; then + run ulimit -c -H + max=$output + fi + + run_podman run --ulimit core=-1:-1 --rm $IMAGE grep core /proc/self/limits + assert "$output" =~ " ${max} * ${max} * bytes" + + run_podman run --ulimit core=1000:-1 --rm $IMAGE grep core /proc/self/limits + assert "$output" =~ " 1000 * ${max} * bytes" + + run_podman 125 run --ulimit core=-1:1000 --rm $IMAGE grep core /proc/self/limits + is "$output" "Error: ulimit option \"core=-1:1000\" requires name=SOFT:HARD, failed to be parsed: ulimit soft limit must be less than or equal to hard limit: soft: -1 (unlimited), hard: 1000" +} + @test "podman run bad --name" { randomname=$(random_string 30) run_podman 125 create --name "$randomname/bad" $IMAGE