gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/rlimits.cc (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <errno.h>
    16  #include <stdlib.h>
    17  #include <sys/resource.h>
    18  #include <sys/time.h>
    19  #include <sys/types.h>
    20  #include <sys/wait.h>
    21  #include <unistd.h>
    22  
    23  #include <algorithm>
    24  #include <climits>
    25  #include <string>
    26  #include <vector>
    27  
    28  #include "absl/algorithm/container.h"
    29  #include "absl/strings/numbers.h"
    30  #include "absl/strings/str_split.h"
    31  #include "test/util/capability_util.h"
    32  #include "test/util/proc_util.h"
    33  #include "test/util/test_util.h"
    34  #include "test/util/thread_util.h"
    35  
    36  namespace gvisor {
    37  namespace testing {
    38  
    39  namespace {
    40  
    41  PosixErrorOr<ProcLimitsEntry> GetProcLimitEntryByType(LimitType limit_type) {
    42    ASSIGN_OR_RETURN_ERRNO(std::string proc_self_limits,
    43                           GetContents("/proc/self/limits"));
    44    ASSIGN_OR_RETURN_ERRNO(auto entries, ParseProcLimits(proc_self_limits));
    45    auto it = absl::c_find_if(entries, [limit_type](const ProcLimitsEntry& v) {
    46      return v.limit_type == limit_type;
    47    });
    48    if (it == entries.end()) {
    49      return PosixError(ENOENT, absl::StrFormat("limit type \"%s\" not found",
    50                                                LimitTypeToString(limit_type)));
    51    }
    52    return *it;
    53  }
    54  
    55  TEST(RlimitTest, SetRlimitHigher) {
    56    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_RESOURCE)));
    57  
    58    struct rlimit rl = {};
    59    EXPECT_THAT(getrlimit(RLIMIT_NOFILE, &rl), SyscallSucceeds());
    60  
    61    // Lower the rlimit first, as it may be equal to /proc/sys/fs/nr_open, in
    62    // which case even users with CAP_SYS_RESOURCE can't raise it.
    63    rl.rlim_cur--;
    64    rl.rlim_max--;
    65    ASSERT_THAT(setrlimit(RLIMIT_NOFILE, &rl), SyscallSucceeds());
    66  
    67    // Now verify we can read the changed values via /proc/self/limits
    68    const ProcLimitsEntry limit_entry = ASSERT_NO_ERRNO_AND_VALUE(
    69        GetProcLimitEntryByType(LimitType::kNumberOfFiles));
    70    EXPECT_EQ(rl.rlim_cur, limit_entry.cur_limit);
    71    EXPECT_EQ(rl.rlim_max, limit_entry.max_limit);
    72  
    73    rl.rlim_max++;
    74    EXPECT_THAT(setrlimit(RLIMIT_NOFILE, &rl), SyscallSucceeds());
    75  }
    76  
    77  TEST(RlimitTest, UnprivilegedSetRlimit) {
    78    // Drop privileges if necessary.
    79    AutoCapability cap(CAP_SYS_RESOURCE, false);
    80  
    81    struct rlimit rl = {};
    82    rl.rlim_cur = 1000;
    83    rl.rlim_max = 20000;
    84    EXPECT_THAT(setrlimit(RLIMIT_NOFILE, &rl), SyscallSucceeds());
    85  
    86    struct rlimit rl2 = {};
    87    EXPECT_THAT(getrlimit(RLIMIT_NOFILE, &rl2), SyscallSucceeds());
    88    EXPECT_EQ(rl.rlim_cur, rl2.rlim_cur);
    89    EXPECT_EQ(rl.rlim_max, rl2.rlim_max);
    90  
    91    rl.rlim_max = 100000;
    92    EXPECT_THAT(setrlimit(RLIMIT_NOFILE, &rl), SyscallFailsWithErrno(EPERM));
    93  }
    94  
    95  TEST(RlimitTest, SetSoftRlimitAboveHard) {
    96    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_RESOURCE)));
    97  
    98    struct rlimit rl = {};
    99    EXPECT_THAT(getrlimit(RLIMIT_NOFILE, &rl), SyscallSucceeds());
   100  
   101    rl.rlim_cur = rl.rlim_max + 1;
   102    EXPECT_THAT(setrlimit(RLIMIT_NOFILE, &rl), SyscallFailsWithErrno(EINVAL));
   103  }
   104  
   105  TEST(RlimitTest, RlimitNProc) {
   106    SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SETUID)));
   107  
   108    // The native test can be run in a user namespace without a mapping for
   109    // kNobody or there can be other processes that are running from the kNobody
   110    // user.
   111    SKIP_IF(!IsRunningOnGvisor());
   112  
   113    // Run the test in a sub-thread to avoid changing UID of the current thread.
   114    ScopedThread([&] {
   115      constexpr int kNobody = 65534;
   116      EXPECT_THAT(syscall(SYS_setuid, kNobody), SyscallSucceeds());
   117  
   118      struct rlimit rl = {};
   119      EXPECT_THAT(getrlimit(RLIMIT_NPROC, &rl), SyscallSucceeds());
   120  
   121      constexpr int kNProc = 10;
   122      rl.rlim_cur = kNProc;
   123      EXPECT_THAT(setrlimit(RLIMIT_NPROC, &rl), SyscallSucceeds());
   124  
   125      constexpr int kIterations = 2;
   126      // Run test actions a few times to check that processes are not leaked.
   127      for (int iter = 0; iter < kIterations; iter++) {
   128        pid_t pids[kNProc];
   129        for (int i = 0; i < kNProc; i++) {
   130          pid_t pid = fork();
   131          if (pid == 0) {
   132            while (1) {
   133              sleep(1);
   134            }
   135            _exit(1);
   136          }
   137          EXPECT_THAT(pid, SyscallSucceeds());
   138          pids[i] = pid;
   139        }
   140        auto cleanup = Cleanup([pids] {
   141          for (int i = 0; i < kNProc; i++) {
   142            if (pids[i] < 0) {
   143              continue;
   144            }
   145            EXPECT_THAT(kill(pids[i], SIGKILL), SyscallSucceeds());
   146            EXPECT_THAT(waitpid(pids[i], nullptr, 0), SyscallSucceeds());
   147          }
   148        });
   149        pid_t pid = fork();
   150        if (pid == 0) {
   151          _exit(1);
   152        }
   153        EXPECT_THAT(pid, SyscallFailsWithErrno(EAGAIN));
   154      }
   155    }).Join();
   156  }
   157  
   158  TEST(RlimitTest, ParseProcPidLimits) {
   159    auto proc_self_limits =
   160        ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/self/limits"));
   161    auto entries = ASSERT_NO_ERRNO_AND_VALUE(ParseProcLimits(proc_self_limits));
   162    EXPECT_EQ(entries.size(), LimitTypes.size());
   163  }
   164  
   165  }  // namespace
   166  
   167  }  // namespace testing
   168  }  // namespace gvisor