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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/param.h> 30 #include <sys/types.h> 31 #include <sys/sysmacros.h> 32 #include <sys/systm.h> 33 #include <sys/cred_impl.h> 34 #include <sys/errno.h> 35 #include <sys/proc.h> 36 #include <sys/debug.h> 37 #include <sys/priv_impl.h> 38 #include <sys/policy.h> 39 #include <sys/ddi.h> 40 #include <sys/thread.h> 41 #include <c2/audit.h> 42 43 /* 44 * System call support for manipulating privileges. 45 * 46 * 47 * setppriv(2) - set process privilege set 48 * getppriv(2) - get process privilege set 49 * getprivimplinfo(2) - get process privilege implementation information 50 * setpflags(2) - set process (privilege) flags 51 * getpflags(2) - get process (privilege) flags 52 */ 53 54 /* 55 * setppriv (priv_op_t, priv_ptype_t, priv_set_t) 56 */ 57 static int 58 setppriv(priv_op_t op, priv_ptype_t type, priv_set_t *in_pset) 59 { 60 priv_set_t pset, *target; 61 cred_t *cr, *pcr; 62 proc_t *p; 63 boolean_t donocd; 64 65 if (!PRIV_VALIDSET(type) || !PRIV_VALIDOP(op)) 66 return (set_errno(EINVAL)); 67 68 if (copyin(in_pset, &pset, sizeof (priv_set_t))) 69 return (set_errno(EFAULT)); 70 71 p = ttoproc(curthread); 72 cr = cralloc(); 73 mutex_enter(&p->p_crlock); 74 75 pcr = p->p_cred; 76 77 #ifdef C2_AUDIT 78 if (audit_active) 79 audit_setppriv(op, type, &pset, pcr); 80 #endif 81 82 /* 83 * Filter out unallowed request (bad op and bad type) 84 */ 85 switch (op) { 86 case PRIV_ON: 87 case PRIV_SET: 88 /* 89 * Turning on privileges; the limit set cannot grow, 90 * other sets can but only as long as they remain subsets 91 * of P. Only immediately after exec holds that P <= L. 92 */ 93 if (((type == PRIV_LIMIT && 94 !priv_issubset(&pset, &CR_LPRIV(pcr))) || 95 !priv_issubset(&pset, &CR_OPPRIV(pcr))) && 96 !priv_issubset(&pset, priv_getset(pcr, type))) { 97 mutex_exit(&p->p_crlock); 98 crfree(cr); 99 return (set_errno(EPERM)); 100 } 101 break; 102 103 case PRIV_OFF: 104 /* PRIV_OFF is always allowed */ 105 break; 106 } 107 108 /* 109 * OK! everything is cool. 110 * Do cred COW. 111 */ 112 crcopy_to(pcr, cr); 113 114 /* 115 * If we change the effective, permitted or limit set, we attain 116 * "privilege awareness". 117 */ 118 if (type != PRIV_INHERITABLE) 119 priv_set_PA(cr); 120 121 target = &(CR_PRIVS(cr)->crprivs[type]); 122 123 switch (op) { 124 case PRIV_ON: 125 priv_union(&pset, target); 126 break; 127 case PRIV_OFF: 128 priv_inverse(&pset); 129 priv_intersect(target, &pset); 130 131 /* 132 * Fall-thru to set target and change other process 133 * privilege sets. 134 */ 135 /*FALLTHRU*/ 136 137 case PRIV_SET: 138 *target = pset; 139 140 /* 141 * Take privileges no longer permitted out 142 * of other effective sets as well. 143 * Limit set is enforced at exec() time. 144 */ 145 if (type == PRIV_PERMITTED) 146 priv_intersect(&pset, &CR_EPRIV(cr)); 147 break; 148 } 149 150 /* 151 * When we give up privileges not in the inheritable set, 152 * set SNOCD if not already set; first we compute the 153 * privileges removed from P using Diff = (~P') & P 154 * and then we check whether the removed privileges are 155 * a subset of I. If we retain uid 0, all privileges 156 * are required anyway so don't set SNOCD. 157 */ 158 if (type == PRIV_PERMITTED && (p->p_flag & SNOCD) == 0 && 159 cr->cr_uid != 0 && cr->cr_ruid != 0 && cr->cr_suid != 0) { 160 priv_set_t diff = CR_OPPRIV(cr); 161 priv_inverse(&diff); 162 priv_intersect(&CR_OPPRIV(pcr), &diff); 163 donocd = !priv_issubset(&diff, &CR_IPRIV(cr)); 164 } else { 165 donocd = B_FALSE; 166 } 167 168 p->p_cred = cr; 169 mutex_exit(&p->p_crlock); 170 171 if (donocd) { 172 mutex_enter(&p->p_lock); 173 p->p_flag |= SNOCD; 174 mutex_exit(&p->p_lock); 175 } 176 177 crset(p, cr); /* broadcast to process threads */ 178 179 return (0); 180 } 181 182 /* 183 * getppriv (priv_ptype_t, priv_set_t *) 184 */ 185 static int 186 getppriv(priv_ptype_t type, priv_set_t *pset) 187 { 188 if (!PRIV_VALIDSET(type)) 189 return (set_errno(EINVAL)); 190 191 if (copyout(priv_getset(CRED(), type), pset, sizeof (priv_set_t)) != 0) 192 return (set_errno(EFAULT)); 193 194 return (0); 195 } 196 197 static int 198 getprivimplinfo(void *buf, size_t bufsize) 199 { 200 int err; 201 202 err = copyout(priv_hold_implinfo(), buf, min(bufsize, privinfosize)); 203 204 priv_release_implinfo(); 205 206 if (err) 207 return (set_errno(EFAULT)); 208 209 return (0); 210 } 211 212 /* 213 * Set privilege flags 214 * 215 * For now we cheat: the flags are actually bit masks so we can simplify 216 * some; we do make sure that the arguments are valid, though. 217 */ 218 219 static int 220 setpflags(uint_t flag, uint_t val) 221 { 222 cred_t *cr, *pcr; 223 proc_t *p = curproc; 224 uint_t newflags; 225 226 if (val > 1 || (flag != PRIV_DEBUG && flag != PRIV_AWARE && 227 flag != __PROC_PROTECT)) { 228 return (set_errno(EINVAL)); 229 } 230 231 if (flag == __PROC_PROTECT) { 232 mutex_enter(&p->p_lock); 233 if (val == 0) 234 p->p_flag &= ~SNOCD; 235 else 236 p->p_flag |= SNOCD; 237 mutex_exit(&p->p_lock); 238 return (0); 239 } 240 241 cr = cralloc(); 242 243 mutex_enter(&p->p_crlock); 244 245 pcr = p->p_cred; 246 247 newflags = CR_FLAGS(pcr); 248 249 if (val != 0) 250 newflags |= flag; 251 else 252 newflags &= ~flag; 253 254 /* No change */ 255 if (CR_FLAGS(pcr) == newflags) { 256 mutex_exit(&p->p_crlock); 257 crfree(cr); 258 return (0); 259 } 260 261 /* Trying to unset PA; if we can't, return an error */ 262 if (flag == PRIV_AWARE && val == 0 && !priv_can_clear_PA(pcr)) { 263 mutex_exit(&p->p_crlock); 264 crfree(cr); 265 return (set_errno(EPERM)); 266 } 267 268 /* Committed to changing the flag */ 269 crcopy_to(pcr, cr); 270 if (flag == PRIV_AWARE) { 271 if (val != 0) 272 priv_set_PA(cr); 273 else 274 priv_adjust_PA(cr); 275 } else { 276 CR_FLAGS(cr) = newflags; 277 } 278 279 p->p_cred = cr; 280 281 mutex_exit(&p->p_crlock); 282 283 crset(p, cr); 284 285 return (0); 286 } 287 288 /* 289 * Getpflags. Currently only implements single bit flags. 290 */ 291 static uint_t 292 getpflags(uint_t flag) 293 { 294 if (flag != PRIV_DEBUG && flag != PRIV_AWARE) 295 return (set_errno(EINVAL)); 296 297 return ((CR_FLAGS(CRED()) & flag) != 0); 298 } 299 300 /* 301 * Privilege system call entry point 302 */ 303 int 304 privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize) 305 { 306 switch (code) { 307 case PRIVSYS_SETPPRIV: 308 if (bufsize < sizeof (priv_set_t)) 309 return (set_errno(ENOMEM)); 310 return (setppriv(op, type, buf)); 311 case PRIVSYS_GETPPRIV: 312 if (bufsize < sizeof (priv_set_t)) 313 return (set_errno(ENOMEM)); 314 return (getppriv(type, buf)); 315 case PRIVSYS_GETIMPLINFO: 316 return (getprivimplinfo(buf, bufsize)); 317 case PRIVSYS_SETPFLAGS: 318 return (setpflags((uint_t)op, (uint_t)type)); 319 case PRIVSYS_GETPFLAGS: 320 return ((int)getpflags((uint_t)op)); 321 322 } 323 return (set_errno(EINVAL)); 324 } 325 326 #ifdef _SYSCALL32_IMPL 327 int 328 privsys32(int code, priv_op_t op, priv_ptype_t type, caddr32_t *buf, 329 size32_t bufsize) 330 { 331 return (privsys(code, op, type, (void *)buf, (size_t)bufsize)); 332 } 333 #endif 334