1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T 27 */ 28 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/sysmacros.h> 32 #include <sys/systm.h> 33 #include <sys/tuneable.h> 34 #include <sys/cred_impl.h> 35 #include <sys/errno.h> 36 #include <sys/proc.h> 37 #include <sys/signal.h> 38 #include <sys/debug.h> 39 #include <sys/policy.h> 40 #include <sys/zone.h> 41 #include <sys/sid.h> 42 43 int 44 setuid(uid_t uid) 45 { 46 proc_t *p; 47 int error; 48 int do_nocd = 0; 49 int uidchge = 0; 50 cred_t *cr, *newcr; 51 uid_t oldruid = uid; 52 zoneid_t zoneid = getzoneid(); 53 ksid_t ksid, *ksp; 54 zone_t *zone = crgetzone(CRED()); 55 56 if (!VALID_UID(uid, zone)) 57 return (set_errno(EINVAL)); 58 59 if (uid > MAXUID) { 60 if (ksid_lookupbyuid(zone, uid, &ksid) != 0) 61 return (set_errno(EINVAL)); 62 ksp = &ksid; 63 } else { 64 ksp = NULL; 65 } 66 /* 67 * Need to pre-allocate the new cred structure before grabbing 68 * the p_crlock mutex. We can't hold on to the p_crlock for most 69 * if this though, now that we allow kernel upcalls from the 70 * policy routines. 71 */ 72 newcr = cralloc_ksid(); 73 74 p = ttoproc(curthread); 75 76 retry: 77 mutex_enter(&p->p_crlock); 78 retry_locked: 79 cr = p->p_cred; 80 crhold(cr); 81 mutex_exit(&p->p_crlock); 82 83 if ((uid == cr->cr_ruid || uid == cr->cr_suid) && 84 secpolicy_allow_setid(cr, uid, B_TRUE) != 0) { 85 mutex_enter(&p->p_crlock); 86 crfree(cr); 87 if (cr != p->p_cred) 88 goto retry_locked; 89 error = 0; 90 crcopy_to(cr, newcr); 91 p->p_cred = newcr; 92 newcr->cr_uid = uid; 93 crsetsid(newcr, ksp, KSID_USER); 94 mutex_exit(&p->p_crlock); 95 } else if ((error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { 96 mutex_enter(&p->p_crlock); 97 crfree(cr); 98 if (cr != p->p_cred) 99 goto retry_locked; 100 if (!uidchge && uid != cr->cr_ruid) { 101 /* 102 * The ruid of the process is going to change. In order 103 * to avoid a race condition involving the 104 * process-count associated with the newly given ruid, 105 * we increment the count before assigning the 106 * credential to the process. 107 * To do that, we'll have to take pidlock, so we first 108 * release p_crlock. 109 */ 110 mutex_exit(&p->p_crlock); 111 uidchge = 1; 112 mutex_enter(&pidlock); 113 upcount_inc(uid, zoneid); 114 mutex_exit(&pidlock); 115 /* 116 * As we released p_crlock we can't rely on the cr 117 * we read. So retry the whole thing. 118 */ 119 goto retry; 120 } 121 /* 122 * A privileged process that gives up its privilege 123 * must be marked to produce no core dump. 124 */ 125 if (cr->cr_uid != uid || 126 cr->cr_ruid != uid || 127 cr->cr_suid != uid) 128 do_nocd = 1; 129 oldruid = cr->cr_ruid; 130 crcopy_to(cr, newcr); 131 p->p_cred = newcr; 132 newcr->cr_ruid = uid; 133 newcr->cr_suid = uid; 134 newcr->cr_uid = uid; 135 136 /* Remove the PRIV_PFEXEC, we changed the real uid. */ 137 if (uidchge) 138 CR_FLAGS(newcr) &= ~PRIV_PFEXEC; 139 140 crsetsid(newcr, ksp, KSID_USER); 141 142 priv_reset_PA(newcr, B_TRUE); 143 144 ASSERT(uid != oldruid ? uidchge : 1); 145 mutex_exit(&p->p_crlock); 146 } else { 147 crfree(newcr); 148 crfree(cr); 149 if (ksp != NULL) 150 ksid_rele(ksp); 151 } 152 153 /* 154 * We decrement the number of processes associated with the oldruid 155 * to match the increment above, even if the ruid of the process 156 * did not change or an error occurred (oldruid == uid). 157 */ 158 if (uidchge) { 159 mutex_enter(&pidlock); 160 upcount_dec(oldruid, zoneid); 161 mutex_exit(&pidlock); 162 } 163 164 if (error == 0) { 165 if (do_nocd) { 166 mutex_enter(&p->p_lock); 167 p->p_flag |= SNOCD; 168 mutex_exit(&p->p_lock); 169 } 170 crset(p, newcr); /* broadcast to process threads */ 171 return (0); 172 } 173 return (set_errno(error)); 174 } 175 176 int64_t 177 getuid(void) 178 { 179 rval_t r; 180 cred_t *cr; 181 182 cr = curthread->t_cred; 183 r.r_val1 = cr->cr_ruid; 184 r.r_val2 = cr->cr_uid; 185 return (r.r_vals); 186 } 187 188 int 189 seteuid(uid_t uid) 190 { 191 proc_t *p; 192 int error = EPERM; 193 int do_nocd = 0; 194 cred_t *cr, *newcr; 195 ksid_t ksid, *ksp; 196 zone_t *zone = crgetzone(CRED()); 197 198 if (!VALID_UID(uid, zone)) 199 return (set_errno(EINVAL)); 200 201 if (uid > MAXUID) { 202 if (ksid_lookupbyuid(zone, uid, &ksid) != 0) 203 return (set_errno(EINVAL)); 204 ksp = &ksid; 205 } else { 206 ksp = NULL; 207 } 208 209 /* 210 * Need to pre-allocate the new cred structure before grabbing 211 * the p_crlock mutex. 212 */ 213 newcr = cralloc_ksid(); 214 p = ttoproc(curthread); 215 mutex_enter(&p->p_crlock); 216 retry: 217 crhold(cr = p->p_cred); 218 mutex_exit(&p->p_crlock); 219 220 if (uid == cr->cr_ruid || uid == cr->cr_uid || uid == cr->cr_suid || 221 (error = secpolicy_allow_setid(cr, uid, B_FALSE)) == 0) { 222 /* 223 * A privileged process that makes itself look like a 224 * set-uid process must be marked to produce no core dump, 225 * if the effective uid did changed. 226 */ 227 mutex_enter(&p->p_crlock); 228 crfree(cr); 229 if (cr != p->p_cred) 230 goto retry; 231 if (cr->cr_uid != uid && error == 0) 232 do_nocd = 1; 233 error = 0; 234 crcopy_to(cr, newcr); 235 p->p_cred = newcr; 236 newcr->cr_uid = uid; 237 crsetsid(newcr, ksp, KSID_USER); 238 priv_reset_PA(newcr, B_FALSE); 239 mutex_exit(&p->p_crlock); 240 if (do_nocd) { 241 mutex_enter(&p->p_lock); 242 p->p_flag |= SNOCD; 243 mutex_exit(&p->p_lock); 244 } 245 crset(p, newcr); /* broadcast to process threads */ 246 return (0); 247 } 248 249 crfree(newcr); 250 crfree(cr); 251 if (ksp != NULL) 252 ksid_rele(ksp); 253 return (set_errno(error)); 254 } 255 256 /* 257 * Buy-back from SunOS 4.x 258 * 259 * Like setuid() and seteuid() combined -except- that non-root users 260 * can change cr_ruid to cr_uid, and the semantics of cr_suid are 261 * subtly different. 262 */ 263 int 264 setreuid(uid_t ruid, uid_t euid) 265 { 266 proc_t *p; 267 int error = 0; 268 int do_nocd = 0; 269 int uidchge = 0; 270 uid_t oldruid = ruid; 271 cred_t *cr, *newcr; 272 zoneid_t zoneid = getzoneid(); 273 ksid_t ksid, *ksp; 274 zone_t *zone = crgetzone(CRED()); 275 276 if ((ruid != -1 && !VALID_UID(ruid, zone)) || 277 (euid != -1 && !VALID_UID(euid, zone))) 278 return (set_errno(EINVAL)); 279 280 if (euid != -1 && euid > MAXUID) { 281 if (ksid_lookupbyuid(zone, euid, &ksid) != 0) 282 return (set_errno(EINVAL)); 283 ksp = &ksid; 284 } else { 285 ksp = NULL; 286 } 287 288 /* 289 * Need to pre-allocate the new cred structure before grabbing 290 * the p_crlock mutex. 291 */ 292 newcr = cralloc_ksid(); 293 294 p = ttoproc(curthread); 295 296 retry: 297 mutex_enter(&p->p_crlock); 298 retry_locked: 299 crhold(cr = p->p_cred); 300 mutex_exit(&p->p_crlock); 301 302 if (ruid != -1 && ruid != cr->cr_ruid && ruid != cr->cr_uid && 303 secpolicy_allow_setid(cr, ruid, B_FALSE) != 0) { 304 mutex_enter(&p->p_crlock); 305 crfree(cr); 306 if (cr != p->p_cred) 307 goto retry_locked; 308 error = EPERM; 309 } else if (euid != -1 && 310 euid != cr->cr_ruid && euid != cr->cr_uid && 311 euid != cr->cr_suid && secpolicy_allow_setid(cr, euid, B_FALSE)) { 312 mutex_enter(&p->p_crlock); 313 crfree(cr); 314 if (cr != p->p_cred) 315 goto retry_locked; 316 error = EPERM; 317 } else { 318 mutex_enter(&p->p_crlock); 319 crfree(cr); 320 if (cr != p->p_cred) 321 goto retry_locked; 322 if (!uidchge && ruid != -1 && cr->cr_ruid != ruid) { 323 /* 324 * The ruid of the process is going to change. In order 325 * to avoid a race condition involving the 326 * process-count associated with the newly given ruid, 327 * we increment the count before assigning the 328 * credential to the process. 329 * To do that, we'll have to take pidlock, so we first 330 * release p_crlock. 331 */ 332 mutex_exit(&p->p_crlock); 333 uidchge = 1; 334 mutex_enter(&pidlock); 335 upcount_inc(ruid, zoneid); 336 mutex_exit(&pidlock); 337 /* 338 * As we released p_crlock we can't rely on the cr 339 * we read. So retry the whole thing. 340 */ 341 goto retry; 342 } 343 crhold(cr); 344 crcopy_to(cr, newcr); 345 p->p_cred = newcr; 346 347 if (euid != -1) { 348 newcr->cr_uid = euid; 349 crsetsid(newcr, ksp, KSID_USER); 350 } 351 if (ruid != -1) { 352 /* Remove the PRIV_PFEXEC, we changed the real uid. */ 353 if (uidchge) 354 CR_FLAGS(newcr) &= ~PRIV_PFEXEC; 355 356 oldruid = newcr->cr_ruid; 357 newcr->cr_ruid = ruid; 358 ASSERT(ruid != oldruid ? uidchge : 1); 359 } 360 /* 361 * "If the real uid is being changed, or the effective uid is 362 * being changed to a value not equal to the real uid, the 363 * saved uid is set to the new effective uid." 364 */ 365 if (ruid != -1 || 366 (euid != -1 && newcr->cr_uid != newcr->cr_ruid)) 367 newcr->cr_suid = newcr->cr_uid; 368 /* 369 * A process that gives up its privilege 370 * must be marked to produce no core dump. 371 */ 372 if ((cr->cr_uid != newcr->cr_uid || 373 cr->cr_ruid != newcr->cr_ruid || 374 cr->cr_suid != newcr->cr_suid)) 375 do_nocd = 1; 376 377 priv_reset_PA(newcr, ruid != -1 && euid != -1 && ruid == euid); 378 crfree(cr); 379 } 380 mutex_exit(&p->p_crlock); 381 382 /* 383 * We decrement the number of processes associated with the oldruid 384 * to match the increment above, even if the ruid of the process 385 * did not change or an error occurred (oldruid == uid). 386 */ 387 if (uidchge) { 388 ASSERT(oldruid != -1 && ruid != -1); 389 mutex_enter(&pidlock); 390 upcount_dec(oldruid, zoneid); 391 mutex_exit(&pidlock); 392 } 393 394 if (error == 0) { 395 if (do_nocd) { 396 mutex_enter(&p->p_lock); 397 p->p_flag |= SNOCD; 398 mutex_exit(&p->p_lock); 399 } 400 crset(p, newcr); /* broadcast to process threads */ 401 return (0); 402 } 403 crfree(newcr); 404 if (ksp != NULL) 405 ksid_rele(ksp); 406 return (set_errno(error)); 407 } 408