The test assumes fs.nr_open is close to the default 1048576, but some
systems set it much higher (e.g. 1073741816). This is systemd's doing:
since systemd v240 (2018), PID 1 bumps fs.nr_open and fs.file-max to
their largest possible values on boot, as file descriptors are already
accounted for by memcg [1].

In that case, dup2() to nr_open + 64 requires the kernel to allocate a
file descriptor table with ~1 billion entries, which fails with ENOMEM.

Cap the nr_open value used for the test's own arithmetic to a known
reasonable base value (1048576) and restore the true original value
once the test has completed.

[1] 
https://github.com/systemd/systemd/commit/a8b627aaed409a15260c25988970c795bf963812
    ("main: bump fs.nr_open + fs.max-file to their largest possible values")

Signed-off-by: Konstantin Khorenko <[email protected]>
Signed-off-by: Eva Kurchatova <[email protected]>
---
 tools/testing/selftests/core/unshare_test.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/core/unshare_test.c 
b/tools/testing/selftests/core/unshare_test.c
index ffce75a6c228..d40e963dd520 100644
--- a/tools/testing/selftests/core/unshare_test.c
+++ b/tools/testing/selftests/core/unshare_test.c
@@ -40,6 +40,14 @@ TEST(unshare_EMFILE)
 
        ASSERT_EQ(sscanf(buf, "%d", &nr_open), 1);
 
+       /*
+        * Cap nr_open for the duration of the test to avoid ENOMEM from a
+        * huge fd table allocation; buf/n keep the real original value so
+        * fs.nr_open can be restored to it once the test is done.
+        */
+       if (nr_open > 1024 * 1024)
+               nr_open = 1024 * 1024;
+
        ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlimit));
 
        /* bump fs.nr_open */
@@ -73,10 +81,13 @@ TEST(unshare_EMFILE)
 
        if (pid == 0) {
                int err;
+               char buf3[32];
+               ssize_t n3;
 
-               /* restore fs.nr_open */
+               /* restore fs.nr_open to the (possibly capped) test baseline */
+               n3 = sprintf(buf3, "%d\n", nr_open);
                lseek(fd, 0, SEEK_SET);
-               write(fd, buf, n);
+               write(fd, buf3, n3);
                /* ... and now unshare(CLONE_FILES) must fail with EMFILE */
                err = unshare(CLONE_FILES);
                EXPECT_EQ(err, -1)
@@ -89,6 +100,10 @@ TEST(unshare_EMFILE)
        EXPECT_EQ(waitpid(pid, &status, 0), pid);
        EXPECT_EQ(true, WIFEXITED(status));
        EXPECT_EQ(0, WEXITSTATUS(status));
+
+       /* restore the real fs.nr_open value */
+       lseek(fd, 0, SEEK_SET);
+       write(fd, buf, n);
 }
 
 TEST_HARNESS_MAIN
-- 
2.47.1


Reply via email to