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