Serenity Operating System
at master 352 lines 11 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/API/POSIX/sys/limits.h> 8#include <Kernel/Process.h> 9 10namespace Kernel { 11 12ErrorOr<FlatPtr> Process::sys$seteuid(UserID new_euid) 13{ 14 VERIFY_NO_PROCESS_BIG_LOCK(this); 15 TRY(require_promise(Pledge::id)); 16 17 if (new_euid == (uid_t)-1) 18 return EINVAL; 19 20 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 21 auto credentials = this->credentials(); 22 23 if (new_euid != credentials->uid() && new_euid != credentials->suid() && !credentials->is_superuser()) 24 return EPERM; 25 26 auto new_credentials = TRY(Credentials::create( 27 credentials->uid(), 28 credentials->gid(), 29 new_euid, 30 credentials->egid(), 31 credentials->suid(), 32 credentials->sgid(), 33 credentials->extra_gids(), 34 credentials->sid(), 35 credentials->pgid())); 36 37 if (credentials->euid() != new_euid) 38 protected_data.dumpable = false; 39 40 protected_data.credentials = move(new_credentials); 41 return 0; 42 }); 43} 44 45ErrorOr<FlatPtr> Process::sys$setegid(GroupID new_egid) 46{ 47 VERIFY_NO_PROCESS_BIG_LOCK(this); 48 TRY(require_promise(Pledge::id)); 49 50 if (new_egid == (uid_t)-1) 51 return EINVAL; 52 53 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 54 auto credentials = this->credentials(); 55 56 if (new_egid != credentials->gid() && new_egid != credentials->sgid() && !credentials->is_superuser()) 57 return EPERM; 58 59 auto new_credentials = TRY(Credentials::create( 60 credentials->uid(), 61 credentials->gid(), 62 credentials->euid(), 63 new_egid, 64 credentials->suid(), 65 credentials->sgid(), 66 credentials->extra_gids(), 67 credentials->sid(), 68 credentials->pgid())); 69 70 if (credentials->egid() != new_egid) 71 protected_data.dumpable = false; 72 73 protected_data.credentials = move(new_credentials); 74 return 0; 75 }); 76} 77 78ErrorOr<FlatPtr> Process::sys$setuid(UserID new_uid) 79{ 80 VERIFY_NO_PROCESS_BIG_LOCK(this); 81 TRY(require_promise(Pledge::id)); 82 83 if (new_uid == (uid_t)-1) 84 return EINVAL; 85 86 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 87 auto credentials = this->credentials(); 88 89 if (new_uid != credentials->uid() && new_uid != credentials->euid() && !credentials->is_superuser()) 90 return EPERM; 91 92 auto new_credentials = TRY(Credentials::create( 93 new_uid, 94 credentials->gid(), 95 new_uid, 96 credentials->egid(), 97 new_uid, 98 credentials->sgid(), 99 credentials->extra_gids(), 100 credentials->sid(), 101 credentials->pgid())); 102 103 if (credentials->euid() != new_uid) 104 protected_data.dumpable = false; 105 106 protected_data.credentials = move(new_credentials); 107 return 0; 108 }); 109} 110 111ErrorOr<FlatPtr> Process::sys$setgid(GroupID new_gid) 112{ 113 VERIFY_NO_PROCESS_BIG_LOCK(this); 114 TRY(require_promise(Pledge::id)); 115 116 if (new_gid == (uid_t)-1) 117 return EINVAL; 118 119 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 120 auto credentials = this->credentials(); 121 122 if (new_gid != credentials->gid() && new_gid != credentials->egid() && !credentials->is_superuser()) 123 return EPERM; 124 125 auto new_credentials = TRY(Credentials::create( 126 credentials->uid(), 127 new_gid, 128 credentials->euid(), 129 new_gid, 130 credentials->suid(), 131 new_gid, 132 credentials->extra_gids(), 133 credentials->sid(), 134 credentials->pgid())); 135 136 if (credentials->egid() != new_gid) 137 protected_data.dumpable = false; 138 139 protected_data.credentials = move(new_credentials); 140 return 0; 141 }); 142} 143 144ErrorOr<FlatPtr> Process::sys$setreuid(UserID new_ruid, UserID new_euid) 145{ 146 VERIFY_NO_PROCESS_BIG_LOCK(this); 147 TRY(require_promise(Pledge::id)); 148 149 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 150 auto credentials = this->credentials(); 151 152 if (new_ruid == (uid_t)-1) 153 new_ruid = credentials->uid(); 154 if (new_euid == (uid_t)-1) 155 new_euid = credentials->euid(); 156 157 auto ok = [&credentials](UserID id) { return id == credentials->uid() || id == credentials->euid() || id == credentials->suid(); }; 158 if (!ok(new_ruid) || !ok(new_euid)) 159 return EPERM; 160 161 if (new_ruid < (uid_t)-1 || new_euid < (uid_t)-1) 162 return EINVAL; 163 164 auto new_credentials = TRY(Credentials::create( 165 new_ruid, 166 credentials->gid(), 167 new_euid, 168 credentials->egid(), 169 credentials->suid(), 170 credentials->sgid(), 171 credentials->extra_gids(), 172 credentials->sid(), 173 credentials->pgid())); 174 175 if (credentials->euid() != new_euid) 176 protected_data.dumpable = false; 177 178 protected_data.credentials = move(new_credentials); 179 return 0; 180 }); 181} 182 183ErrorOr<FlatPtr> Process::sys$setresuid(UserID new_ruid, UserID new_euid, UserID new_suid) 184{ 185 VERIFY_NO_PROCESS_BIG_LOCK(this); 186 TRY(require_promise(Pledge::id)); 187 188 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 189 auto credentials = this->credentials(); 190 191 if (new_ruid == (uid_t)-1) 192 new_ruid = credentials->uid(); 193 if (new_euid == (uid_t)-1) 194 new_euid = credentials->euid(); 195 if (new_suid == (uid_t)-1) 196 new_suid = credentials->suid(); 197 198 auto ok = [&credentials](UserID id) { return id == credentials->uid() || id == credentials->euid() || id == credentials->suid(); }; 199 if ((!ok(new_ruid) || !ok(new_euid) || !ok(new_suid)) && !credentials->is_superuser()) 200 return EPERM; 201 202 auto new_credentials = TRY(Credentials::create( 203 new_ruid, 204 credentials->gid(), 205 new_euid, 206 credentials->egid(), 207 new_suid, 208 credentials->sgid(), 209 credentials->extra_gids(), 210 credentials->sid(), 211 credentials->pgid())); 212 213 if (credentials->euid() != new_euid) 214 protected_data.dumpable = false; 215 216 protected_data.credentials = move(new_credentials); 217 return 0; 218 }); 219} 220 221ErrorOr<FlatPtr> Process::sys$setregid(GroupID new_rgid, GroupID new_egid) 222{ 223 VERIFY_NO_PROCESS_BIG_LOCK(this); 224 TRY(require_promise(Pledge::id)); 225 226 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 227 auto credentials = this->credentials(); 228 229 if (new_rgid == (gid_t)-1) 230 new_rgid = credentials->gid(); 231 if (new_egid == (gid_t)-1) 232 new_egid = credentials->egid(); 233 234 auto ok = [&credentials](GroupID id) { return id == credentials->gid() || id == credentials->egid() || id == credentials->sgid(); }; 235 if (!ok(new_rgid) || !ok(new_egid)) 236 return EPERM; 237 238 auto new_credentials = TRY(Credentials::create( 239 credentials->uid(), 240 new_rgid, 241 credentials->euid(), 242 new_egid, 243 credentials->suid(), 244 credentials->sgid(), 245 credentials->extra_gids(), 246 credentials->sid(), 247 credentials->pgid())); 248 249 if (credentials->egid() != new_egid) 250 protected_data.dumpable = false; 251 252 protected_data.credentials = move(new_credentials); 253 return 0; 254 }); 255} 256 257ErrorOr<FlatPtr> Process::sys$setresgid(GroupID new_rgid, GroupID new_egid, GroupID new_sgid) 258{ 259 VERIFY_NO_PROCESS_BIG_LOCK(this); 260 TRY(require_promise(Pledge::id)); 261 262 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 263 auto credentials = this->credentials(); 264 265 if (new_rgid == (gid_t)-1) 266 new_rgid = credentials->gid(); 267 if (new_egid == (gid_t)-1) 268 new_egid = credentials->egid(); 269 if (new_sgid == (gid_t)-1) 270 new_sgid = credentials->sgid(); 271 272 auto ok = [&credentials](GroupID id) { return id == credentials->gid() || id == credentials->egid() || id == credentials->sgid(); }; 273 if ((!ok(new_rgid) || !ok(new_egid) || !ok(new_sgid)) && !credentials->is_superuser()) 274 return EPERM; 275 276 auto new_credentials = TRY(Credentials::create( 277 credentials->uid(), 278 new_rgid, 279 credentials->euid(), 280 new_egid, 281 credentials->suid(), 282 new_sgid, 283 credentials->extra_gids(), 284 credentials->sid(), 285 credentials->pgid())); 286 287 if (credentials->egid() != new_egid) 288 protected_data.dumpable = false; 289 290 protected_data.credentials = move(new_credentials); 291 return 0; 292 }); 293} 294 295ErrorOr<FlatPtr> Process::sys$setgroups(size_t count, Userspace<GroupID const*> user_gids) 296{ 297 VERIFY_NO_PROCESS_BIG_LOCK(this); 298 TRY(require_promise(Pledge::id)); 299 300 if (count > NGROUPS_MAX) 301 return EINVAL; 302 303 return with_mutable_protected_data([&](auto& protected_data) -> ErrorOr<FlatPtr> { 304 auto credentials = this->credentials(); 305 306 if (!credentials->is_superuser()) 307 return EPERM; 308 309 if (!count) { 310 protected_data.credentials = TRY(Credentials::create( 311 credentials->uid(), 312 credentials->gid(), 313 credentials->euid(), 314 credentials->egid(), 315 credentials->suid(), 316 credentials->sgid(), 317 {}, 318 credentials->sid(), 319 credentials->pgid())); 320 return 0; 321 } 322 323 Vector<GroupID> new_extra_gids; 324 TRY(new_extra_gids.try_resize(count)); 325 TRY(copy_n_from_user(new_extra_gids.data(), user_gids, count)); 326 327 HashTable<GroupID> unique_extra_gids; 328 for (auto& extra_gid : new_extra_gids) { 329 if (extra_gid != credentials->gid()) 330 TRY(unique_extra_gids.try_set(extra_gid)); 331 } 332 333 new_extra_gids.clear_with_capacity(); 334 for (auto extra_gid : unique_extra_gids) { 335 TRY(new_extra_gids.try_append(extra_gid)); 336 } 337 338 protected_data.credentials = TRY(Credentials::create( 339 credentials->uid(), 340 credentials->gid(), 341 credentials->euid(), 342 credentials->egid(), 343 credentials->suid(), 344 credentials->sgid(), 345 new_extra_gids.span(), 346 credentials->sid(), 347 credentials->pgid())); 348 return 0; 349 }); 350} 351 352}