diff --git a/define/types.go b/define/types.go index c34bd2152ff..fc9c5a8c8c3 100644 --- a/define/types.go +++ b/define/types.go @@ -54,6 +54,9 @@ const ( SNP TeeType = "snp" ) +// DefaultRlimitValue is the value set by default for nofile and nproc +const RLimitDefaultValue = uint64(1048576) + // TeeType is a supported trusted execution environment type. type TeeType string diff --git a/run_linux.go b/run_linux.go index 4630ac5efcc..c96fc0bffbe 100644 --- a/run_linux.go +++ b/run_linux.go @@ -854,6 +854,9 @@ func addRlimits(ulimit []string, g *generate.Generator, defaultUlimits []string) var ( ul *units.Ulimit err error + // setup rlimits + nofileSet bool + nprocSet bool ) ulimit = append(defaultUlimits, ulimit...) @@ -862,8 +865,39 @@ func addRlimits(ulimit []string, g *generate.Generator, defaultUlimits []string) return fmt.Errorf("ulimit option %q requires name=SOFT:HARD, failed to be parsed: %w", u, err) } + if strings.ToUpper(ul.Name) == "NOFILE" { + nofileSet = true + } + if strings.ToUpper(ul.Name) == "NPROC" { + nprocSet = true + } g.AddProcessRlimits("RLIMIT_"+strings.ToUpper(ul.Name), uint64(ul.Hard), uint64(ul.Soft)) } + if !nofileSet { + max := define.RLimitDefaultValue + var rlimit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit); err == nil { + if max < rlimit.Max || unshare.IsRootless() { + max = rlimit.Max + } + } else { + logrus.Warnf("Failed to return RLIMIT_NOFILE ulimit %q", err) + } + g.AddProcessRlimits("RLIMIT_NOFILE", max, max) + } + if !nprocSet { + max := define.RLimitDefaultValue + var rlimit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NPROC, &rlimit); err == nil { + if max < rlimit.Max || unshare.IsRootless() { + max = rlimit.Max + } + } else { + logrus.Warnf("Failed to return RLIMIT_NPROC ulimit %q", err) + } + g.AddProcessRlimits("RLIMIT_NPROC", max, max) + } + return nil } diff --git a/tests/bud.bats b/tests/bud.bats index 5fbe001d283..097537dbcd2 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -6602,3 +6602,18 @@ _EOF expect_output --substring "localhost/foo/bar" expect_output --substring "localhost/bar" } + +@test "build test default ulimits" { + skip_if_no_runtime + _prefetch alpine + + run podman run --rm alpine sh -c "echo -n Files=; awk '/open files/{print \$4 \"/\" \$5}' /proc/self/limits" + podman_files=$output + + run podman run --rm alpine sh -c "echo -n Processes=; awk '/processes/{print \$3 \"/\" \$4}' /proc/self/limits" + podman_processes=$output + + CONTAINERS_CONF=/dev/null run_buildah build --no-cache --pull=false $WITH_POLICY_JSON -t foo/bar $BUDFILES/bud.limits + expect_output --substring "$podman_files" + expect_output --substring "$podman_processes" +} diff --git a/tests/bud/bud.limits/Containerfile b/tests/bud/bud.limits/Containerfile new file mode 100644 index 00000000000..7d6eedd3586 --- /dev/null +++ b/tests/bud/bud.limits/Containerfile @@ -0,0 +1,4 @@ +# Containerfile +FROM alpine +RUN echo -n "Files="; awk '/open files/{print $4 "/" $5}' /proc/self/limits +RUN echo -n "Processes="; awk '/processes/{print $3 "/" $4}' /proc/self/limits diff --git a/tests/run.bats b/tests/run.bats index 43b84edc045..5e6f917407e 100644 --- a/tests/run.bats +++ b/tests/run.bats @@ -510,7 +510,6 @@ function configure_and_check_user() { } @test "Check if containers run with correct open files/processes limits" { - skip_if_rootless_environment skip_if_no_runtime # we need to not use the list of limits that are set in our default @@ -521,21 +520,25 @@ function configure_and_check_user() { export CONTAINERS_CONF=${TEST_SCRATCH_DIR}/containers.conf _prefetch alpine - maxpids=$(cat /proc/sys/kernel/pid_max) + + run podman run --rm alpine sh -c "awk '/open files/{print \$4 \"/\" \$5}' /proc/self/limits" + podman_files=$output + run_buildah from --quiet --pull=false $WITH_POLICY_JSON alpine cid=$output - run_buildah run $cid awk '/open files/{print $4}' /proc/self/limits - expect_output 1024 "limits: open files (unlimited)" - run_buildah run $cid awk '/processes/{print $3}' /proc/self/limits - expect_output ${maxpids} "limits: processes (unlimited)" + run_buildah run $cid awk '/open files/{print $4 "/" $5}' /proc/self/limits + expect_output "${podman_files}" "limits: podman and buildah should agree on open files" + + run podman run --rm alpine sh -c "awk '/processes/{print \$3 \"/\" \$4}' /proc/self/limits" + podman_processes=$output + run_buildah run $cid awk '/processes/{print $3 "/" $4}' /proc/self/limits + expect_output ${podman_processes} "processes should match podman" run_buildah rm $cid run_buildah from --quiet --ulimit nofile=300:400 --pull=false $WITH_POLICY_JSON alpine cid=$output run_buildah run $cid awk '/open files/{print $4}' /proc/self/limits expect_output "300" "limits: open files (w/file limit)" - run_buildah run $cid awk '/processes/{print $3}' /proc/self/limits - expect_output ${maxpids} "limits: processes (w/file limit)" run_buildah rm $cid run_buildah from --quiet --ulimit nproc=100:200 --ulimit nofile=300:400 --pull=false $WITH_POLICY_JSON alpine