github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/uidgid.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 <grp.h> 17 #include <sys/resource.h> 18 #include <sys/types.h> 19 #include <unistd.h> 20 21 #include "gtest/gtest.h" 22 #include "absl/flags/flag.h" 23 #include "absl/strings/str_cat.h" 24 #include "absl/strings/str_join.h" 25 #include "test/util/capability_util.h" 26 #include "test/util/cleanup.h" 27 #include "test/util/multiprocess_util.h" 28 #include "test/util/posix_error.h" 29 #include "test/util/test_util.h" 30 #include "test/util/thread_util.h" 31 #include "test/util/uid_util.h" 32 33 ABSL_FLAG(int32_t, scratch_uid1, 65534, "first scratch UID"); 34 ABSL_FLAG(int32_t, scratch_uid2, 65533, "second scratch UID"); 35 ABSL_FLAG(int32_t, scratch_gid1, 65534, "first scratch GID"); 36 ABSL_FLAG(int32_t, scratch_gid2, 65533, "second scratch GID"); 37 38 // Force use of syscall instead of glibc set*id() wrappers because we want to 39 // apply to the current task only. libc sets all threads in a process because 40 // "POSIX requires that all threads in a process share the same credentials." 41 #define setuid USE_SYSCALL_INSTEAD 42 #define setgid USE_SYSCALL_INSTEAD 43 #define setreuid USE_SYSCALL_INSTEAD 44 #define setregid USE_SYSCALL_INSTEAD 45 #define setresuid USE_SYSCALL_INSTEAD 46 #define setresgid USE_SYSCALL_INSTEAD 47 48 using ::testing::UnorderedElementsAreArray; 49 50 namespace gvisor { 51 namespace testing { 52 53 namespace { 54 55 TEST(UidGidTest, Getuid) { 56 uid_t ruid, euid, suid; 57 EXPECT_THAT(getresuid(&ruid, &euid, &suid), SyscallSucceeds()); 58 EXPECT_THAT(getuid(), SyscallSucceedsWithValue(ruid)); 59 EXPECT_THAT(geteuid(), SyscallSucceedsWithValue(euid)); 60 } 61 62 TEST(UidGidTest, Getgid) { 63 gid_t rgid, egid, sgid; 64 EXPECT_THAT(getresgid(&rgid, &egid, &sgid), SyscallSucceeds()); 65 EXPECT_THAT(getgid(), SyscallSucceedsWithValue(rgid)); 66 EXPECT_THAT(getegid(), SyscallSucceedsWithValue(egid)); 67 } 68 69 TEST(UidGidTest, Getgroups) { 70 // "If size is zero, list is not modified, but the total number of 71 // supplementary group IDs for the process is returned." - getgroups(2) 72 int nr_groups; 73 ASSERT_THAT(nr_groups = getgroups(0, nullptr), SyscallSucceeds()); 74 std::vector<gid_t> list(nr_groups); 75 EXPECT_THAT(getgroups(list.size(), list.data()), SyscallSucceeds()); 76 77 // "EINVAL: size is less than the number of supplementary group IDs, but is 78 // not zero." 79 EXPECT_THAT(getgroups(-1, nullptr), SyscallFailsWithErrno(EINVAL)); 80 81 // Testing for EFAULT requires actually having groups, which isn't guaranteed 82 // here; see the setgroups test below. 83 } 84 85 // Checks that the calling process' real/effective/saved user IDs are 86 // ruid/euid/suid respectively. 87 PosixError CheckUIDs(uid_t ruid, uid_t euid, uid_t suid) { 88 uid_t actual_ruid, actual_euid, actual_suid; 89 int rc = getresuid(&actual_ruid, &actual_euid, &actual_suid); 90 MaybeSave(); 91 if (rc < 0) { 92 return PosixError(errno, "getresuid"); 93 } 94 if (ruid != actual_ruid || euid != actual_euid || suid != actual_suid) { 95 return PosixError( 96 EPERM, absl::StrCat( 97 "incorrect user IDs: got (", 98 absl::StrJoin({actual_ruid, actual_euid, actual_suid}, ", "), 99 ", wanted (", absl::StrJoin({ruid, euid, suid}, ", "), ")")); 100 } 101 return NoError(); 102 } 103 104 PosixError CheckGIDs(gid_t rgid, gid_t egid, gid_t sgid) { 105 gid_t actual_rgid, actual_egid, actual_sgid; 106 int rc = getresgid(&actual_rgid, &actual_egid, &actual_sgid); 107 MaybeSave(); 108 if (rc < 0) { 109 return PosixError(errno, "getresgid"); 110 } 111 if (rgid != actual_rgid || egid != actual_egid || sgid != actual_sgid) { 112 return PosixError( 113 EPERM, absl::StrCat( 114 "incorrect group IDs: got (", 115 absl::StrJoin({actual_rgid, actual_egid, actual_sgid}, ", "), 116 ", wanted (", absl::StrJoin({rgid, egid, sgid}, ", "), ")")); 117 } 118 return NoError(); 119 } 120 121 // N.B. These tests may break horribly unless run via a gVisor test runner, 122 // because changing UID in one test may forfeit permissions required by other 123 // tests. (The test runner runs each test in a separate process.) 124 125 TEST(UidGidRootTest, Setuid) { 126 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 127 128 // Do setuid in a separate thread so that after finishing this test, the 129 // process can still open files the test harness created before starting this 130 // test. Otherwise, the files are created by root (UID before the test), but 131 // cannot be opened by the `uid` set below after the test. After calling 132 // setuid(non-zero-UID), there is no way to get root privileges back. 133 ScopedThread([&] { 134 // Use syscall instead of glibc setuid wrapper because we want this setuid 135 // call to only apply to this task. POSIX threads, however, require that all 136 // threads have the same UIDs, so using the setuid wrapper sets all threads' 137 // real UID. 138 EXPECT_THAT(syscall(SYS_setuid, -1), SyscallFailsWithErrno(EINVAL)); 139 140 const uid_t uid = absl::GetFlag(FLAGS_scratch_uid1); 141 EXPECT_THAT(syscall(SYS_setuid, uid), SyscallSucceeds()); 142 // "If the effective UID of the caller is root (more precisely: if the 143 // caller has the CAP_SETUID capability), the real UID and saved set-user-ID 144 // are also set." - setuid(2) 145 EXPECT_NO_ERRNO(CheckUIDs(uid, uid, uid)); 146 }); 147 } 148 149 TEST(UidGidRootTest, Setgid) { 150 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 151 152 EXPECT_THAT(syscall(SYS_setgid, -1), SyscallFailsWithErrno(EINVAL)); 153 154 ScopedThread([&] { 155 const gid_t gid = absl::GetFlag(FLAGS_scratch_gid1); 156 EXPECT_THAT(syscall(SYS_setgid, gid), SyscallSucceeds()); 157 EXPECT_NO_ERRNO(CheckGIDs(gid, gid, gid)); 158 }); 159 } 160 161 TEST(UidGidRootTest, SetgidNotFromThreadGroupLeader) { 162 #pragma push_macro("allow_setgid") 163 #undef setgid 164 165 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 166 167 int old_gid = getgid(); 168 auto clean = Cleanup([old_gid] { setgid(old_gid); }); 169 170 const gid_t gid = absl::GetFlag(FLAGS_scratch_gid1); 171 // NOTE(b/64676707): Do setgid in a separate thread so that we can test if 172 // info.si_pid is set correctly. 173 ScopedThread thread = 174 ScopedThread([gid] { ASSERT_THAT(setgid(gid), SyscallSucceeds()); }); 175 thread.Join(); 176 EXPECT_NO_ERRNO(CheckGIDs(gid, gid, gid)); 177 178 #pragma pop_macro("allow_setgid") 179 } 180 181 TEST(UidGidRootTest, Setreuid) { 182 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 183 184 // "Supplying a value of -1 for either the real or effective user ID forces 185 // the system to leave that ID unchanged." - setreuid(2) 186 EXPECT_THAT(syscall(SYS_setreuid, -1, -1), SyscallSucceeds()); 187 188 EXPECT_NO_ERRNO(CheckUIDs(0, 0, 0)); 189 190 // Do setuid in a separate thread so that after finishing this test, the 191 // process can still open files the test harness created before starting 192 // this test. Otherwise, the files are created by root (UID before the 193 // test), but cannot be opened by the `uid` set below after the test. After 194 // calling setuid(non-zero-UID), there is no way to get root privileges 195 // back. 196 ScopedThread([&] { 197 const uid_t ruid = absl::GetFlag(FLAGS_scratch_uid1); 198 const uid_t euid = absl::GetFlag(FLAGS_scratch_uid2); 199 200 EXPECT_THAT(syscall(SYS_setreuid, ruid, euid), SyscallSucceeds()); 201 202 // "If the real user ID is set or the effective user ID is set to a value 203 // not equal to the previous real user ID, the saved set-user-ID will be 204 // set to the new effective user ID." - setreuid(2) 205 EXPECT_NO_ERRNO(CheckUIDs(ruid, euid, euid)); 206 }); 207 } 208 209 TEST(UidGidRootTest, Setregid) { 210 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 211 212 EXPECT_THAT(syscall(SYS_setregid, -1, -1), SyscallSucceeds()); 213 EXPECT_NO_ERRNO(CheckGIDs(0, 0, 0)); 214 215 ScopedThread([&] { 216 const gid_t rgid = absl::GetFlag(FLAGS_scratch_gid1); 217 const gid_t egid = absl::GetFlag(FLAGS_scratch_gid2); 218 ASSERT_THAT(syscall(SYS_setregid, rgid, egid), SyscallSucceeds()); 219 EXPECT_NO_ERRNO(CheckGIDs(rgid, egid, egid)); 220 }); 221 } 222 223 TEST(UidGidRootTest, Setresuid) { 224 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 225 226 // "If one of the arguments equals -1, the corresponding value is not 227 // changed." - setresuid(2) 228 EXPECT_THAT(syscall(SYS_setresuid, -1, -1, -1), SyscallSucceeds()); 229 EXPECT_NO_ERRNO(CheckUIDs(0, 0, 0)); 230 231 // Do setuid in a separate thread so that after finishing this test, the 232 // process can still open files the test harness created before starting 233 // this test. Otherwise, the files are created by root (UID before the 234 // test), but cannot be opened by the `uid` set below after the test. After 235 // calling setuid(non-zero-UID), there is no way to get root privileges 236 // back. 237 ScopedThread([&] { 238 const uid_t ruid = 12345; 239 const uid_t euid = 23456; 240 const uid_t suid = 34567; 241 242 // Use syscall instead of glibc setuid wrapper because we want this setuid 243 // call to only apply to this task. posix threads, however, require that 244 // all threads have the same UIDs, so using the setuid wrapper sets all 245 // threads' real UID. 246 EXPECT_THAT(syscall(SYS_setresuid, ruid, euid, suid), SyscallSucceeds()); 247 EXPECT_NO_ERRNO(CheckUIDs(ruid, euid, suid)); 248 }); 249 } 250 251 TEST(UidGidRootTest, Setresgid) { 252 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 253 254 EXPECT_THAT(syscall(SYS_setresgid, -1, -1, -1), SyscallSucceeds()); 255 EXPECT_NO_ERRNO(CheckGIDs(0, 0, 0)); 256 257 ScopedThread([&] { 258 const gid_t rgid = 12345; 259 const gid_t egid = 23456; 260 const gid_t sgid = 34567; 261 ASSERT_THAT(syscall(SYS_setresgid, rgid, egid, sgid), SyscallSucceeds()); 262 EXPECT_NO_ERRNO(CheckGIDs(rgid, egid, sgid)); 263 }); 264 } 265 266 TEST(UidGidRootTest, Setgroups) { 267 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 268 269 std::vector<gid_t> list = {123, 500}; 270 ASSERT_THAT(setgroups(list.size(), list.data()), SyscallSucceeds()); 271 std::vector<gid_t> list2(list.size()); 272 ASSERT_THAT(getgroups(list2.size(), list2.data()), SyscallSucceeds()); 273 EXPECT_THAT(list, UnorderedElementsAreArray(list2)); 274 275 // "EFAULT: list has an invalid address." 276 EXPECT_THAT(getgroups(100, reinterpret_cast<gid_t*>(-1)), 277 SyscallFailsWithErrno(EFAULT)); 278 } 279 280 TEST(UidGidRootTest, Setuid_prlimit) { 281 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(IsRoot())); 282 283 // Do seteuid in a separate thread so that after finishing this test, the 284 // process can still open files the test harness created before starting 285 // this test. Otherwise, the files are created by root (UID before the 286 // test), but cannot be opened by the `uid` set below after the test. 287 ScopedThread([&] { 288 // Use syscall instead of glibc setuid wrapper because we want this 289 // seteuid call to only apply to this task. POSIX threads, however, 290 // require that all threads have the same UIDs, so using the seteuid 291 // wrapper sets all threads' UID. 292 EXPECT_THAT(syscall(SYS_setreuid, -1, 65534), SyscallSucceeds()); 293 294 // Despite the UID change, we should be able to get our own limits. 295 struct rlimit rl = {}; 296 EXPECT_THAT(prlimit(0, RLIMIT_NOFILE, NULL, &rl), SyscallSucceeds()); 297 }); 298 } 299 300 } // namespace 301 302 } // namespace testing 303 } // namespace gvisor