1 /* $NetBSD: secmodel_securelevel.c,v 1.13 2009/09/03 04:45:28 elad 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.13 2009/09/03 04:45:28 elad 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 l_vnode; 61 62 /* 63 * sysctl helper routine for securelevel. ensures that the value 64 * only rises unless the caller has pid 1 (assumed to be init). 65 */ 66 int 67 secmodel_securelevel_sysctl(SYSCTLFN_ARGS) 68 { 69 int newsecurelevel, error; 70 struct sysctlnode node; 71 72 newsecurelevel = securelevel; 73 node = *rnode; 74 node.sysctl_data = &newsecurelevel; 75 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 76 if (error || newp == NULL) 77 return (error); 78 79 if (newsecurelevel < securelevel && l && l->l_proc->p_pid != 1) 80 return (EPERM); 81 82 securelevel = newsecurelevel; 83 84 return (error); 85 } 86 87 void 88 secmodel_securelevel_init(void) 89 { 90 #ifdef INSECURE 91 securelevel = -1; 92 #else 93 securelevel = 0; 94 #endif /* INSECURE */ 95 } 96 97 SYSCTL_SETUP(sysctl_security_securelevel_setup, 98 "sysctl security securelevel setup") 99 { 100 /* 101 * For compatibility, we create a kern.securelevel variable. 102 */ 103 sysctl_createv(clog, 0, NULL, NULL, 104 CTLFLAG_PERMANENT, 105 CTLTYPE_NODE, "kern", NULL, 106 NULL, 0, NULL, 0, 107 CTL_KERN, CTL_EOL); 108 109 sysctl_createv(clog, 0, NULL, NULL, 110 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 111 CTLTYPE_INT, "securelevel", 112 SYSCTL_DESCR("System security level"), 113 secmodel_securelevel_sysctl, 0, NULL, 0, 114 CTL_KERN, KERN_SECURELVL, CTL_EOL); 115 } 116 117 void 118 secmodel_securelevel_start(void) 119 { 120 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 121 secmodel_securelevel_system_cb, NULL); 122 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 123 secmodel_securelevel_process_cb, NULL); 124 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, 125 secmodel_securelevel_network_cb, NULL); 126 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, 127 secmodel_securelevel_machdep_cb, NULL); 128 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, 129 secmodel_securelevel_device_cb, NULL); 130 l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE, 131 secmodel_securelevel_vnode_cb, NULL); 132 } 133 134 #if defined(_LKM) 135 void 136 secmodel_securelevel_stop(void) 137 { 138 kauth_unlisten_scope(l_system); 139 kauth_unlisten_scope(l_process); 140 kauth_unlisten_scope(l_network); 141 kauth_unlisten_scope(l_machdep); 142 kauth_unlisten_scope(l_device); 143 kauth_unlisten_scope(l_vnode); 144 } 145 #endif /* _LKM */ 146 147 /* 148 * kauth(9) listener 149 * 150 * Security model: Traditional NetBSD 151 * Scope: System 152 * Responsibility: Securelevel 153 */ 154 int 155 secmodel_securelevel_system_cb(kauth_cred_t cred, 156 kauth_action_t action, void *cookie, void *arg0, void *arg1, 157 void *arg2, void *arg3) 158 { 159 int result; 160 enum kauth_system_req req; 161 162 result = KAUTH_RESULT_DEFER; 163 req = (enum kauth_system_req)arg0; 164 165 switch (action) { 166 case KAUTH_SYSTEM_CHSYSFLAGS: 167 if (securelevel > 0) 168 result = KAUTH_RESULT_DENY; 169 break; 170 171 case KAUTH_SYSTEM_TIME: 172 switch (req) { 173 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET: 174 if (securelevel > 0) 175 result = KAUTH_RESULT_DENY; 176 break; 177 178 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: { 179 struct timespec *ts = arg1; 180 struct timespec *delta = arg2; 181 182 /* 183 * Don't allow the time to be set forward so far it 184 * will wrap and become negative, thus allowing an 185 * attacker to bypass the next check below. The 186 * cutoff is 1 year before rollover occurs, so even 187 * if the attacker uses adjtime(2) to move the time 188 * past the cutoff, it will take a very long time 189 * to get to the wrap point. 190 */ 191 if (securelevel > 1 && 192 ((ts->tv_sec > LLONG_MAX - 365*24*60*60) || 193 (delta->tv_sec < 0 || delta->tv_nsec < 0))) 194 result = KAUTH_RESULT_DENY; 195 break; 196 } 197 198 default: 199 break; 200 } 201 break; 202 203 case KAUTH_SYSTEM_MODULE: 204 if (securelevel > 0) 205 result = KAUTH_RESULT_DENY; 206 break; 207 208 case KAUTH_SYSTEM_MOUNT: 209 switch (req) { 210 case KAUTH_REQ_SYSTEM_MOUNT_NEW: 211 if (securelevel > 1) 212 result = KAUTH_RESULT_DENY; 213 214 break; 215 216 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: 217 if (securelevel > 1) { 218 struct mount *mp = arg1; 219 u_long flags = (u_long)arg2; 220 221 /* Can only degrade from read/write to read-only. */ 222 if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD | 223 MNT_FORCE | MNT_UPDATE)) 224 result = KAUTH_RESULT_DENY; 225 } 226 227 break; 228 229 default: 230 break; 231 } 232 233 break; 234 235 case KAUTH_SYSTEM_SYSCTL: 236 switch (req) { 237 case KAUTH_REQ_SYSTEM_SYSCTL_ADD: 238 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE: 239 case KAUTH_REQ_SYSTEM_SYSCTL_DESC: 240 if (securelevel > 0) 241 result = KAUTH_RESULT_DENY; 242 break; 243 244 default: 245 break; 246 } 247 break; 248 249 case KAUTH_SYSTEM_SETIDCORE: 250 if (securelevel > 0) 251 result = KAUTH_RESULT_DENY; 252 break; 253 254 case KAUTH_SYSTEM_DEBUG: 255 switch (req) { 256 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: 257 if (securelevel > 0) 258 result = KAUTH_RESULT_DENY; 259 break; 260 261 default: 262 break; 263 } 264 break; 265 266 default: 267 break; 268 } 269 270 return (result); 271 } 272 273 /* 274 * kauth(9) listener 275 * 276 * Security model: Traditional NetBSD 277 * Scope: Process 278 * Responsibility: Securelevel 279 */ 280 int 281 secmodel_securelevel_process_cb(kauth_cred_t cred, 282 kauth_action_t action, void *cookie, void *arg0, 283 void *arg1, void *arg2, void *arg3) 284 { 285 struct proc *p; 286 int result; 287 288 result = KAUTH_RESULT_DEFER; 289 p = arg0; 290 291 switch (action) { 292 case KAUTH_PROCESS_PROCFS: { 293 enum kauth_process_req req; 294 295 req = (enum kauth_process_req)arg2; 296 switch (req) { 297 case KAUTH_REQ_PROCESS_PROCFS_READ: 298 break; 299 300 case KAUTH_REQ_PROCESS_PROCFS_RW: 301 case KAUTH_REQ_PROCESS_PROCFS_WRITE: 302 if ((p == initproc) && (securelevel > -1)) 303 result = KAUTH_RESULT_DENY; 304 305 break; 306 307 default: 308 break; 309 } 310 311 break; 312 } 313 314 case KAUTH_PROCESS_PTRACE: 315 if ((p == initproc) && (securelevel >= 0)) 316 result = KAUTH_RESULT_DENY; 317 318 break; 319 320 case KAUTH_PROCESS_CORENAME: 321 if (securelevel > 1) 322 result = KAUTH_RESULT_DENY; 323 break; 324 325 default: 326 break; 327 } 328 329 return (result); 330 } 331 332 /* 333 * kauth(9) listener 334 * 335 * Security model: Traditional NetBSD 336 * Scope: Network 337 * Responsibility: Securelevel 338 */ 339 int 340 secmodel_securelevel_network_cb(kauth_cred_t cred, 341 kauth_action_t action, void *cookie, void *arg0, 342 void *arg1, void *arg2, void *arg3) 343 { 344 int result; 345 enum kauth_network_req req; 346 347 result = KAUTH_RESULT_DEFER; 348 req = (enum kauth_network_req)arg0; 349 350 switch (action) { 351 case KAUTH_NETWORK_FIREWALL: 352 switch (req) { 353 case KAUTH_REQ_NETWORK_FIREWALL_FW: 354 case KAUTH_REQ_NETWORK_FIREWALL_NAT: 355 if (securelevel > 1) 356 result = KAUTH_RESULT_DENY; 357 break; 358 359 default: 360 break; 361 } 362 break; 363 364 case KAUTH_NETWORK_FORWSRCRT: 365 if (securelevel > 0) 366 result = KAUTH_RESULT_DENY; 367 break; 368 369 default: 370 break; 371 } 372 373 return (result); 374 } 375 376 /* 377 * kauth(9) listener 378 * 379 * Security model: Traditional NetBSD 380 * Scope: Machdep 381 * Responsibility: Securelevel 382 */ 383 int 384 secmodel_securelevel_machdep_cb(kauth_cred_t cred, 385 kauth_action_t action, void *cookie, void *arg0, 386 void *arg1, void *arg2, void *arg3) 387 { 388 int result; 389 390 result = KAUTH_RESULT_DEFER; 391 392 switch (action) { 393 case KAUTH_MACHDEP_IOPERM_SET: 394 case KAUTH_MACHDEP_IOPL: 395 if (securelevel > 0) 396 result = KAUTH_RESULT_DENY; 397 break; 398 399 case KAUTH_MACHDEP_UNMANAGEDMEM: 400 if (securelevel > 0) 401 result = KAUTH_RESULT_DENY; 402 break; 403 404 default: 405 break; 406 } 407 408 return (result); 409 } 410 411 /* 412 * kauth(9) listener 413 * 414 * Security model: Traditional NetBSD 415 * Scope: Device 416 * Responsibility: Securelevel 417 */ 418 int 419 secmodel_securelevel_device_cb(kauth_cred_t cred, 420 kauth_action_t action, void *cookie, void *arg0, 421 void *arg1, void *arg2, void *arg3) 422 { 423 int result; 424 425 result = KAUTH_RESULT_DEFER; 426 427 switch (action) { 428 case KAUTH_DEVICE_RAWIO_SPEC: { 429 struct vnode *vp, *bvp; 430 enum kauth_device_req req; 431 dev_t dev; 432 int d_type; 433 434 req = (enum kauth_device_req)arg0; 435 vp = arg1; 436 437 KASSERT(vp != NULL); 438 439 dev = vp->v_rdev; 440 d_type = D_OTHER; 441 bvp = NULL; 442 443 /* Handle /dev/mem and /dev/kmem. */ 444 if ((vp->v_type == VCHR) && iskmemdev(dev)) { 445 switch (req) { 446 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 447 break; 448 449 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 450 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 451 if (securelevel > 0) 452 result = KAUTH_RESULT_DENY; 453 break; 454 455 default: 456 break; 457 } 458 459 break; 460 } 461 462 switch (req) { 463 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 464 break; 465 466 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 467 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 468 switch (vp->v_type) { 469 case VCHR: { 470 const struct cdevsw *cdev; 471 472 cdev = cdevsw_lookup(dev); 473 if (cdev != NULL) { 474 dev_t blkdev; 475 476 blkdev = devsw_chr2blk(dev); 477 if (blkdev != NODEV) { 478 vfinddev(blkdev, VBLK, &bvp); 479 if (bvp != NULL) 480 d_type = (cdev->d_flag 481 & D_TYPEMASK); 482 } 483 } 484 485 break; 486 } 487 case VBLK: { 488 const struct bdevsw *bdev; 489 490 bdev = bdevsw_lookup(dev); 491 if (bdev != NULL) 492 d_type = (bdev->d_flag & D_TYPEMASK); 493 494 bvp = vp; 495 496 break; 497 } 498 499 default: 500 break; 501 } 502 503 if (d_type != D_DISK) 504 break; 505 506 /* 507 * XXX: This is bogus. We should be failing the request 508 * XXX: not only if this specific slice is mounted, but 509 * XXX: if it's on a disk with any other mounted slice. 510 */ 511 if (vfs_mountedon(bvp) && (securelevel > 0)) 512 break; 513 514 if (securelevel > 1) 515 result = KAUTH_RESULT_DENY; 516 517 break; 518 519 default: 520 break; 521 } 522 523 break; 524 } 525 526 case KAUTH_DEVICE_RAWIO_PASSTHRU: 527 if (securelevel > 0) { 528 u_long bits; 529 530 bits = (u_long)arg0; 531 532 KASSERT(bits != 0); 533 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0); 534 535 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF) 536 result = KAUTH_RESULT_DENY; 537 } 538 539 break; 540 541 case KAUTH_DEVICE_GPIO_PINSET: 542 if (securelevel > 0) 543 result = KAUTH_RESULT_DENY; 544 break; 545 546 default: 547 break; 548 } 549 550 return (result); 551 } 552 553 int 554 secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action, 555 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 556 { 557 int result; 558 559 result = KAUTH_RESULT_DEFER; 560 561 if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) && 562 (action & KAUTH_VNODE_HAS_SYSFLAGS)) { 563 if (securelevel > 0) 564 result = KAUTH_RESULT_DENY; 565 } 566 567 return (result); 568 } 569 570