1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2006 nCircle Network Security, Inc. 5 * Copyright (c) 2009 Robert N. M. Watson 6 * Copyright (c) 2020 Mariusz Zaborski <oshogbo@FreeBSD.org> 7 * All rights reserved. 8 * 9 * This software was developed by Robert N. M. Watson for the TrustedBSD 10 * Project under contract to nCircle Network Security, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, 25 * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/jail.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/mutex.h> 42 #include <sys/sx.h> 43 #include <sys/priv.h> 44 #include <sys/proc.h> 45 #include <sys/sdt.h> 46 #include <sys/sysctl.h> 47 #include <sys/systm.h> 48 49 #include <security/mac/mac_framework.h> 50 51 /* 52 * `suser_enabled' (which can be set by the security.bsd.suser_enabled 53 * sysctl) determines whether the system 'super-user' policy is in effect. If 54 * it is nonzero, an effective uid of 0 connotes special privilege, 55 * overriding many mandatory and discretionary protections. If it is zero, 56 * uid 0 is offered no special privilege in the kernel security policy. 57 * Setting it to zero may seriously impact the functionality of many existing 58 * userland programs, and should not be done without careful consideration of 59 * the consequences. 60 */ 61 62 static bool 63 suser_enabled(struct ucred *cred) 64 { 65 66 return (prison_allow(cred, PR_ALLOW_SUSER)); 67 } 68 69 static int 70 sysctl_kern_suser_enabled(SYSCTL_HANDLER_ARGS) 71 { 72 struct ucred *cred; 73 int error, enabled; 74 75 cred = req->td->td_ucred; 76 enabled = suser_enabled(cred); 77 error = sysctl_handle_int(oidp, &enabled, 0, req); 78 if (error || !req->newptr) 79 return (error); 80 prison_set_allow(cred, PR_ALLOW_SUSER, enabled); 81 return (0); 82 } 83 84 SYSCTL_PROC(_security_bsd, OID_AUTO, suser_enabled, CTLTYPE_INT | 85 CTLFLAG_RWTUN | CTLFLAG_PRISON | CTLFLAG_MPSAFE, 0, 0, 86 &sysctl_kern_suser_enabled, "I", "Processes with uid 0 have privilege"); 87 88 static int unprivileged_mlock = 1; 89 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_mlock, CTLFLAG_RWTUN, 90 &unprivileged_mlock, 0, "Allow non-root users to call mlock(2)"); 91 92 static int unprivileged_read_msgbuf = 1; 93 SYSCTL_INT(_security_bsd, OID_AUTO, unprivileged_read_msgbuf, 94 CTLFLAG_RW, &unprivileged_read_msgbuf, 0, 95 "Unprivileged processes may read the kernel message buffer"); 96 97 SDT_PROVIDER_DEFINE(priv); 98 SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__ok, "int"); 99 SDT_PROBE_DEFINE1(priv, kernel, priv_check, priv__err, "int"); 100 101 static __always_inline int 102 priv_check_cred_pre(struct ucred *cred, int priv) 103 { 104 int error; 105 106 #ifdef MAC 107 error = mac_priv_check(cred, priv); 108 #else 109 error = 0; 110 #endif 111 return (error); 112 } 113 114 static __always_inline int 115 priv_check_cred_post(struct ucred *cred, int priv, int error, bool handled) 116 { 117 118 if (__predict_true(handled)) 119 goto out; 120 /* 121 * Now check with MAC, if enabled, to see if a policy module grants 122 * privilege. 123 */ 124 #ifdef MAC 125 if (mac_priv_grant(cred, priv) == 0) { 126 error = 0; 127 goto out; 128 } 129 #endif 130 131 /* 132 * The default is deny, so if no policies have granted it, reject 133 * with a privilege error here. 134 */ 135 error = EPERM; 136 out: 137 if (SDT_PROBES_ENABLED()) { 138 if (error) 139 SDT_PROBE1(priv, kernel, priv_check, priv__err, priv); 140 else 141 SDT_PROBE1(priv, kernel, priv_check, priv__ok, priv); 142 } 143 return (error); 144 } 145 146 /* 147 * Check a credential for privilege. Lots of good reasons to deny privilege; 148 * only a few to grant it. 149 */ 150 int 151 priv_check_cred(struct ucred *cred, int priv) 152 { 153 int error; 154 155 KASSERT(PRIV_VALID(priv), ("priv_check_cred: invalid privilege %d", 156 priv)); 157 158 switch (priv) { 159 case PRIV_VFS_LOOKUP: 160 return (priv_check_cred_vfs_lookup(cred)); 161 case PRIV_VFS_GENERATION: 162 return (priv_check_cred_vfs_generation(cred)); 163 } 164 165 /* 166 * We first evaluate policies that may deny the granting of 167 * privilege unilaterally. 168 */ 169 error = priv_check_cred_pre(cred, priv); 170 if (error) 171 goto out; 172 173 /* 174 * Jail policy will restrict certain privileges that may otherwise be 175 * be granted. 176 */ 177 error = prison_priv_check(cred, priv); 178 if (error) 179 goto out; 180 181 if (unprivileged_mlock) { 182 /* 183 * Allow unprivileged users to call mlock(2)/munlock(2) and 184 * mlockall(2)/munlockall(2). 185 */ 186 switch (priv) { 187 case PRIV_VM_MLOCK: 188 case PRIV_VM_MUNLOCK: 189 error = 0; 190 goto out; 191 } 192 } 193 194 if (unprivileged_read_msgbuf) { 195 /* 196 * Allow an unprivileged user to read the kernel message 197 * buffer. 198 */ 199 if (priv == PRIV_MSGBUF) { 200 error = 0; 201 goto out; 202 } 203 } 204 205 /* 206 * Having determined if privilege is restricted by various policies, 207 * now determine if privilege is granted. At this point, any policy 208 * may grant privilege. For now, we allow short-circuit boolean 209 * evaluation, so may not call all policies. Perhaps we should. 210 * 211 * Superuser policy grants privilege based on the effective (or in 212 * the case of specific privileges, real) uid being 0. We allow the 213 * superuser policy to be globally disabled, although this is 214 * currenty of limited utility. 215 */ 216 if (suser_enabled(cred)) { 217 switch (priv) { 218 case PRIV_MAXFILES: 219 case PRIV_MAXPROC: 220 case PRIV_PROC_LIMIT: 221 if (cred->cr_ruid == 0) { 222 error = 0; 223 goto out; 224 } 225 break; 226 case PRIV_VFS_READ_DIR: 227 /* 228 * Allow PRIV_VFS_READ_DIR for root if we're not in a 229 * jail, otherwise deny unless a MAC policy grants it. 230 */ 231 if (jailed(cred)) 232 break; 233 /* FALLTHROUGH */ 234 default: 235 if (cred->cr_uid == 0) { 236 error = 0; 237 goto out; 238 } 239 break; 240 } 241 } 242 243 /* 244 * Writes to kernel/physical memory are a typical root-only operation, 245 * but non-root users are expected to be able to read it (provided they 246 * have permission to access /dev/[k]mem). 247 */ 248 if (priv == PRIV_KMEM_READ) { 249 error = 0; 250 goto out; 251 } 252 253 /* 254 * Allow unprivileged process debugging on a per-jail basis. 255 * Do this here instead of prison_priv_check(), so it can also 256 * apply to prison0. 257 */ 258 if (priv == PRIV_DEBUG_UNPRIV) { 259 if (prison_allow(cred, PR_ALLOW_UNPRIV_DEBUG)) { 260 error = 0; 261 goto out; 262 } 263 } 264 265 return (priv_check_cred_post(cred, priv, error, false)); 266 out: 267 return (priv_check_cred_post(cred, priv, error, true)); 268 } 269 270 int 271 priv_check(struct thread *td, int priv) 272 { 273 274 KASSERT(td == curthread, ("priv_check: td != curthread")); 275 276 return (priv_check_cred(td->td_ucred, priv)); 277 } 278 279 static int __noinline 280 priv_check_cred_vfs_lookup_slow(struct ucred *cred) 281 { 282 int error; 283 284 error = priv_check_cred_pre(cred, PRIV_VFS_LOOKUP); 285 if (error) 286 goto out; 287 288 if (cred->cr_uid == 0 && suser_enabled(cred)) { 289 error = 0; 290 goto out; 291 } 292 293 return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, false)); 294 out: 295 return (priv_check_cred_post(cred, PRIV_VFS_LOOKUP, error, true)); 296 297 } 298 299 int 300 priv_check_cred_vfs_lookup(struct ucred *cred) 301 { 302 int error; 303 304 if (__predict_false(mac_priv_check_fp_flag || 305 mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) 306 return (priv_check_cred_vfs_lookup_slow(cred)); 307 308 error = EPERM; 309 if (cred->cr_uid == 0 && suser_enabled(cred)) 310 error = 0; 311 return (error); 312 } 313 314 int 315 priv_check_cred_vfs_lookup_nomac(struct ucred *cred) 316 { 317 int error; 318 319 if (__predict_false(mac_priv_check_fp_flag || 320 mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) 321 return (EAGAIN); 322 323 error = EPERM; 324 if (cred->cr_uid == 0 && suser_enabled(cred)) 325 error = 0; 326 return (error); 327 } 328 329 static int __noinline 330 priv_check_cred_vfs_generation_slow(struct ucred *cred) 331 { 332 int error; 333 334 error = priv_check_cred_pre(cred, PRIV_VFS_GENERATION); 335 if (error) 336 goto out; 337 338 if (jailed(cred)) { 339 error = EPERM; 340 goto out; 341 } 342 343 if (cred->cr_uid == 0 && suser_enabled(cred)) { 344 error = 0; 345 goto out; 346 } 347 348 return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, false)); 349 out: 350 return (priv_check_cred_post(cred, PRIV_VFS_GENERATION, error, true)); 351 352 } 353 354 int 355 priv_check_cred_vfs_generation(struct ucred *cred) 356 { 357 int error; 358 359 if (__predict_false(mac_priv_check_fp_flag || 360 mac_priv_grant_fp_flag || SDT_PROBES_ENABLED())) 361 return (priv_check_cred_vfs_generation_slow(cred)); 362 363 error = EPERM; 364 if (!jailed(cred) && cred->cr_uid == 0 && suser_enabled(cred)) 365 error = 0; 366 return (error); 367 } 368