1 /* $NetBSD: secmodel_securelevel.c,v 1.10 2009/01/11 02:45:55 christos Exp $ */ 2 /*- 3 * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * This file contains kauth(9) listeners needed to implement the traditional 31 * NetBSD securelevel. 32 * 33 * The securelevel is a system-global indication on what operations are 34 * allowed or not. It affects all users, including root. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.10 2009/01/11 02:45:55 christos Exp $"); 39 40 #ifdef _KERNEL_OPT 41 #include "opt_insecure.h" 42 #endif /* _KERNEL_OPT */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/kauth.h> 47 48 #include <sys/conf.h> 49 #include <sys/mount.h> 50 #include <sys/sysctl.h> 51 #include <sys/vnode.h> 52 53 #include <miscfs/specfs/specdev.h> 54 55 #include <secmodel/securelevel/securelevel.h> 56 57 static int securelevel; 58 59 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device; 60 61 /* 62 * sysctl helper routine for securelevel. ensures that the value 63 * only rises unless the caller has pid 1 (assumed to be init). 64 */ 65 int 66 secmodel_securelevel_sysctl(SYSCTLFN_ARGS) 67 { 68 int newsecurelevel, error; 69 struct sysctlnode node; 70 71 newsecurelevel = securelevel; 72 node = *rnode; 73 node.sysctl_data = &newsecurelevel; 74 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 75 if (error || newp == NULL) 76 return (error); 77 78 if (newsecurelevel < securelevel && l && l->l_proc->p_pid != 1) 79 return (EPERM); 80 81 securelevel = newsecurelevel; 82 83 return (error); 84 } 85 86 void 87 secmodel_securelevel_init(void) 88 { 89 #ifdef INSECURE 90 securelevel = -1; 91 #else 92 securelevel = 0; 93 #endif /* INSECURE */ 94 } 95 96 SYSCTL_SETUP(sysctl_security_securelevel_setup, 97 "sysctl security securelevel setup") 98 { 99 /* 100 * For compatibility, we create a kern.securelevel variable. 101 */ 102 sysctl_createv(clog, 0, NULL, NULL, 103 CTLFLAG_PERMANENT, 104 CTLTYPE_NODE, "kern", NULL, 105 NULL, 0, NULL, 0, 106 CTL_KERN, CTL_EOL); 107 108 sysctl_createv(clog, 0, NULL, NULL, 109 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 110 CTLTYPE_INT, "securelevel", 111 SYSCTL_DESCR("System security level"), 112 secmodel_securelevel_sysctl, 0, NULL, 0, 113 CTL_KERN, KERN_SECURELVL, CTL_EOL); 114 } 115 116 void 117 secmodel_securelevel_start(void) 118 { 119 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 120 secmodel_securelevel_system_cb, NULL); 121 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 122 secmodel_securelevel_process_cb, NULL); 123 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, 124 secmodel_securelevel_network_cb, NULL); 125 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, 126 secmodel_securelevel_machdep_cb, NULL); 127 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, 128 secmodel_securelevel_device_cb, NULL); 129 } 130 131 #if defined(_LKM) 132 void 133 secmodel_securelevel_stop(void) 134 { 135 kauth_unlisten_scope(l_system); 136 kauth_unlisten_scope(l_process); 137 kauth_unlisten_scope(l_network); 138 kauth_unlisten_scope(l_machdep); 139 kauth_unlisten_scope(l_device); 140 } 141 #endif /* _LKM */ 142 143 /* 144 * kauth(9) listener 145 * 146 * Security model: Traditional NetBSD 147 * Scope: System 148 * Responsibility: Securelevel 149 */ 150 int 151 secmodel_securelevel_system_cb(kauth_cred_t cred, 152 kauth_action_t action, void *cookie, void *arg0, void *arg1, 153 void *arg2, void *arg3) 154 { 155 int result; 156 enum kauth_system_req req; 157 158 result = KAUTH_RESULT_DEFER; 159 req = (enum kauth_system_req)arg0; 160 161 switch (action) { 162 case KAUTH_SYSTEM_CHSYSFLAGS: 163 if (securelevel > 0) 164 result = KAUTH_RESULT_DENY; 165 break; 166 167 case KAUTH_SYSTEM_TIME: 168 switch (req) { 169 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET: 170 if (securelevel > 0) 171 result = KAUTH_RESULT_DENY; 172 break; 173 174 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: { 175 struct timespec *ts = arg1; 176 struct timespec *delta = arg2; 177 178 /* 179 * Don't allow the time to be set forward so far it 180 * will wrap and become negative, thus allowing an 181 * attacker to bypass the next check below. The 182 * cutoff is 1 year before rollover occurs, so even 183 * if the attacker uses adjtime(2) to move the time 184 * past the cutoff, it will take a very long time 185 * to get to the wrap point. 186 */ 187 if (securelevel > 1 && 188 ((ts->tv_sec > LLONG_MAX - 365*24*60*60) || 189 (delta->tv_sec < 0 || delta->tv_nsec < 0))) 190 result = KAUTH_RESULT_DENY; 191 break; 192 } 193 194 default: 195 break; 196 } 197 break; 198 199 case KAUTH_SYSTEM_MODULE: 200 if (securelevel > 0) 201 result = KAUTH_RESULT_DENY; 202 break; 203 204 case KAUTH_SYSTEM_MOUNT: 205 switch (req) { 206 case KAUTH_REQ_SYSTEM_MOUNT_NEW: 207 if (securelevel > 1) 208 result = KAUTH_RESULT_DENY; 209 210 break; 211 212 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: 213 if (securelevel > 1) { 214 struct mount *mp = arg1; 215 u_long flags = (u_long)arg2; 216 217 /* Can only degrade from read/write to read-only. */ 218 if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD | 219 MNT_FORCE | MNT_UPDATE)) 220 result = KAUTH_RESULT_DENY; 221 } 222 223 break; 224 225 default: 226 break; 227 } 228 229 break; 230 231 case KAUTH_SYSTEM_SYSCTL: 232 switch (req) { 233 case KAUTH_REQ_SYSTEM_SYSCTL_ADD: 234 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE: 235 case KAUTH_REQ_SYSTEM_SYSCTL_DESC: 236 if (securelevel > 0) 237 result = KAUTH_RESULT_DENY; 238 break; 239 240 default: 241 break; 242 } 243 break; 244 245 case KAUTH_SYSTEM_SETIDCORE: 246 if (securelevel > 0) 247 result = KAUTH_RESULT_DENY; 248 break; 249 250 case KAUTH_SYSTEM_DEBUG: 251 switch (req) { 252 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: 253 if (securelevel > 0) 254 result = KAUTH_RESULT_DENY; 255 break; 256 257 default: 258 break; 259 } 260 break; 261 } 262 263 return (result); 264 } 265 266 /* 267 * kauth(9) listener 268 * 269 * Security model: Traditional NetBSD 270 * Scope: Process 271 * Responsibility: Securelevel 272 */ 273 int 274 secmodel_securelevel_process_cb(kauth_cred_t cred, 275 kauth_action_t action, void *cookie, void *arg0, 276 void *arg1, void *arg2, void *arg3) 277 { 278 struct proc *p; 279 int result; 280 281 result = KAUTH_RESULT_DEFER; 282 p = arg0; 283 284 switch (action) { 285 case KAUTH_PROCESS_PROCFS: { 286 enum kauth_process_req req; 287 288 req = (enum kauth_process_req)arg2; 289 switch (req) { 290 case KAUTH_REQ_PROCESS_PROCFS_READ: 291 break; 292 293 case KAUTH_REQ_PROCESS_PROCFS_RW: 294 case KAUTH_REQ_PROCESS_PROCFS_WRITE: 295 if ((p == initproc) && (securelevel > -1)) 296 result = KAUTH_RESULT_DENY; 297 298 break; 299 300 default: 301 break; 302 } 303 304 break; 305 } 306 307 case KAUTH_PROCESS_PTRACE: 308 if ((p == initproc) && (securelevel >= 0)) 309 result = KAUTH_RESULT_DENY; 310 311 break; 312 313 case KAUTH_PROCESS_CORENAME: 314 if (securelevel > 1) 315 result = KAUTH_RESULT_DENY; 316 break; 317 } 318 319 return (result); 320 } 321 322 /* 323 * kauth(9) listener 324 * 325 * Security model: Traditional NetBSD 326 * Scope: Network 327 * Responsibility: Securelevel 328 */ 329 int 330 secmodel_securelevel_network_cb(kauth_cred_t cred, 331 kauth_action_t action, void *cookie, void *arg0, 332 void *arg1, void *arg2, void *arg3) 333 { 334 int result; 335 enum kauth_network_req req; 336 337 result = KAUTH_RESULT_DEFER; 338 req = (enum kauth_network_req)arg0; 339 340 switch (action) { 341 case KAUTH_NETWORK_FIREWALL: 342 switch (req) { 343 case KAUTH_REQ_NETWORK_FIREWALL_FW: 344 case KAUTH_REQ_NETWORK_FIREWALL_NAT: 345 if (securelevel > 1) 346 result = KAUTH_RESULT_DENY; 347 break; 348 349 default: 350 break; 351 } 352 break; 353 354 case KAUTH_NETWORK_FORWSRCRT: 355 if (securelevel > 0) 356 result = KAUTH_RESULT_DENY; 357 break; 358 } 359 360 return (result); 361 } 362 363 /* 364 * kauth(9) listener 365 * 366 * Security model: Traditional NetBSD 367 * Scope: Machdep 368 * Responsibility: Securelevel 369 */ 370 int 371 secmodel_securelevel_machdep_cb(kauth_cred_t cred, 372 kauth_action_t action, void *cookie, void *arg0, 373 void *arg1, void *arg2, void *arg3) 374 { 375 int result; 376 377 result = KAUTH_RESULT_DEFER; 378 379 switch (action) { 380 case KAUTH_MACHDEP_IOPERM_SET: 381 case KAUTH_MACHDEP_IOPL: 382 if (securelevel > 0) 383 result = KAUTH_RESULT_DENY; 384 break; 385 386 case KAUTH_MACHDEP_UNMANAGEDMEM: 387 if (securelevel > 0) 388 result = KAUTH_RESULT_DENY; 389 break; 390 } 391 392 return (result); 393 } 394 395 /* 396 * kauth(9) listener 397 * 398 * Security model: Traditional NetBSD 399 * Scope: Device 400 * Responsibility: Securelevel 401 */ 402 int 403 secmodel_securelevel_device_cb(kauth_cred_t cred, 404 kauth_action_t action, void *cookie, void *arg0, 405 void *arg1, void *arg2, void *arg3) 406 { 407 int result; 408 409 result = KAUTH_RESULT_DEFER; 410 411 switch (action) { 412 case KAUTH_DEVICE_RAWIO_SPEC: { 413 struct vnode *vp, *bvp; 414 enum kauth_device_req req; 415 dev_t dev; 416 int d_type; 417 418 req = (enum kauth_device_req)arg0; 419 vp = arg1; 420 421 KASSERT(vp != NULL); 422 423 dev = vp->v_rdev; 424 d_type = D_OTHER; 425 bvp = NULL; 426 427 /* Handle /dev/mem and /dev/kmem. */ 428 if ((vp->v_type == VCHR) && iskmemdev(dev)) { 429 switch (req) { 430 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 431 break; 432 433 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 434 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 435 if (securelevel > 0) 436 result = KAUTH_RESULT_DENY; 437 break; 438 } 439 440 break; 441 } 442 443 switch (req) { 444 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 445 break; 446 447 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 448 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 449 switch (vp->v_type) { 450 case VCHR: { 451 const struct cdevsw *cdev; 452 453 cdev = cdevsw_lookup(dev); 454 if (cdev != NULL) { 455 dev_t blkdev; 456 457 blkdev = devsw_chr2blk(dev); 458 if (blkdev != NODEV) { 459 vfinddev(blkdev, VBLK, &bvp); 460 if (bvp != NULL) 461 d_type = (cdev->d_flag 462 & D_TYPEMASK); 463 } 464 } 465 466 break; 467 } 468 case VBLK: { 469 const struct bdevsw *bdev; 470 471 bdev = bdevsw_lookup(dev); 472 if (bdev != NULL) 473 d_type = (bdev->d_flag & D_TYPEMASK); 474 475 bvp = vp; 476 477 break; 478 } 479 480 default: 481 break; 482 } 483 484 if (d_type != D_DISK) 485 break; 486 487 /* 488 * XXX: This is bogus. We should be failing the request 489 * XXX: not only if this specific slice is mounted, but 490 * XXX: if it's on a disk with any other mounted slice. 491 */ 492 if (vfs_mountedon(bvp) && (securelevel > 0)) 493 break; 494 495 if (securelevel > 1) 496 result = KAUTH_RESULT_DENY; 497 498 break; 499 } 500 501 break; 502 } 503 504 case KAUTH_DEVICE_RAWIO_PASSTHRU: 505 if (securelevel > 0) { 506 u_long bits; 507 508 bits = (u_long)arg0; 509 510 KASSERT(bits != 0); 511 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0); 512 513 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF) 514 result = KAUTH_RESULT_DENY; 515 } 516 517 break; 518 } 519 520 return (result); 521 } 522