1 /* $NetBSD: secmodel_securelevel.c,v 1.27 2012/03/13 18:41:02 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.27 2012/03/13 18:41:02 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 #include <sys/module.h> 53 #include <sys/timevar.h> 54 55 #include <miscfs/specfs/specdev.h> 56 57 #include <secmodel/secmodel.h> 58 #include <secmodel/securelevel/securelevel.h> 59 60 MODULE(MODULE_CLASS_SECMODEL, securelevel, NULL); 61 62 static int securelevel; 63 64 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device, 65 l_vnode; 66 67 static secmodel_t securelevel_sm; 68 static struct sysctllog *securelevel_sysctl_log; 69 70 /* 71 * Sysctl helper routine for securelevel. Ensures that the value only rises 72 * unless the caller is init. 73 */ 74 int 75 secmodel_securelevel_sysctl(SYSCTLFN_ARGS) 76 { 77 int newsecurelevel, error; 78 struct sysctlnode node; 79 80 newsecurelevel = securelevel; 81 node = *rnode; 82 node.sysctl_data = &newsecurelevel; 83 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 84 if (error || newp == NULL) 85 return (error); 86 87 if ((newsecurelevel < securelevel) && (l->l_proc != initproc)) 88 return (EPERM); 89 90 securelevel = newsecurelevel; 91 92 return (error); 93 } 94 95 void 96 sysctl_security_securelevel_setup(struct sysctllog **clog) 97 { 98 const struct sysctlnode *rnode; 99 100 sysctl_createv(clog, 0, NULL, &rnode, 101 CTLFLAG_PERMANENT, 102 CTLTYPE_NODE, "security", NULL, 103 NULL, 0, NULL, 0, 104 CTL_SECURITY, CTL_EOL); 105 106 sysctl_createv(clog, 0, &rnode, &rnode, 107 CTLFLAG_PERMANENT, 108 CTLTYPE_NODE, "models", NULL, 109 NULL, 0, NULL, 0, 110 CTL_CREATE, CTL_EOL); 111 112 sysctl_createv(clog, 0, &rnode, &rnode, 113 CTLFLAG_PERMANENT, 114 CTLTYPE_NODE, "securelevel", NULL, 115 NULL, 0, NULL, 0, 116 CTL_CREATE, CTL_EOL); 117 118 sysctl_createv(clog, 0, &rnode, NULL, 119 CTLFLAG_PERMANENT, 120 CTLTYPE_STRING, "name", NULL, 121 NULL, 0, __UNCONST(SECMODEL_SECURELEVEL_NAME), 0, 122 CTL_CREATE, CTL_EOL); 123 124 sysctl_createv(clog, 0, &rnode, NULL, 125 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 126 CTLTYPE_INT, "securelevel", 127 SYSCTL_DESCR("System security level"), 128 secmodel_securelevel_sysctl, 0, NULL, 0, 129 CTL_CREATE, CTL_EOL); 130 131 /* Compatibility: kern.securelevel */ 132 sysctl_createv(clog, 0, NULL, NULL, 133 CTLFLAG_PERMANENT, 134 CTLTYPE_NODE, "kern", NULL, 135 NULL, 0, NULL, 0, 136 CTL_KERN, CTL_EOL); 137 138 sysctl_createv(clog, 0, NULL, NULL, 139 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 140 CTLTYPE_INT, "securelevel", 141 SYSCTL_DESCR("System security level"), 142 secmodel_securelevel_sysctl, 0, NULL, 0, 143 CTL_KERN, KERN_SECURELVL, CTL_EOL); 144 } 145 146 void 147 secmodel_securelevel_init(void) 148 { 149 #ifdef INSECURE 150 securelevel = -1; 151 #else 152 securelevel = 0; 153 #endif /* INSECURE */ 154 } 155 156 void 157 secmodel_securelevel_start(void) 158 { 159 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 160 secmodel_securelevel_system_cb, NULL); 161 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 162 secmodel_securelevel_process_cb, NULL); 163 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, 164 secmodel_securelevel_network_cb, NULL); 165 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, 166 secmodel_securelevel_machdep_cb, NULL); 167 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, 168 secmodel_securelevel_device_cb, NULL); 169 l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE, 170 secmodel_securelevel_vnode_cb, NULL); 171 } 172 173 void 174 secmodel_securelevel_stop(void) 175 { 176 kauth_unlisten_scope(l_system); 177 kauth_unlisten_scope(l_process); 178 kauth_unlisten_scope(l_network); 179 kauth_unlisten_scope(l_machdep); 180 kauth_unlisten_scope(l_device); 181 kauth_unlisten_scope(l_vnode); 182 } 183 184 static int 185 securelevel_eval(const char *what, void *arg, void *ret) 186 { 187 int error = 0; 188 189 if (strcasecmp(what, "is-securelevel-above") == 0) { 190 int level = (int)(uintptr_t)arg; 191 bool *bp = ret; 192 193 *bp = (securelevel > level); 194 } else { 195 error = ENOENT; 196 } 197 198 return error; 199 } 200 201 static int 202 securelevel_modcmd(modcmd_t cmd, void *arg) 203 { 204 int error = 0; 205 206 switch (cmd) { 207 case MODULE_CMD_INIT: 208 secmodel_securelevel_init(); 209 error = secmodel_register(&securelevel_sm, 210 SECMODEL_SECURELEVEL_ID, SECMODEL_SECURELEVEL_NAME, 211 NULL, securelevel_eval, NULL); 212 if (error != 0) 213 printf("securelevel_modcmd::init: secmodel_register " 214 "returned %d\n", error); 215 216 secmodel_securelevel_start(); 217 sysctl_security_securelevel_setup(&securelevel_sysctl_log); 218 break; 219 220 case MODULE_CMD_FINI: 221 sysctl_teardown(&securelevel_sysctl_log); 222 secmodel_securelevel_stop(); 223 224 error = secmodel_deregister(securelevel_sm); 225 if (error != 0) 226 printf("securelevel_modcmd::fini: secmodel_deregister " 227 "returned %d\n", error); 228 229 break; 230 231 case MODULE_CMD_AUTOUNLOAD: 232 error = EPERM; 233 break; 234 235 default: 236 error = ENOTTY; 237 break; 238 } 239 240 return (error); 241 } 242 243 /* 244 * kauth(9) listener 245 * 246 * Security model: Traditional NetBSD 247 * Scope: System 248 * Responsibility: Securelevel 249 */ 250 int 251 secmodel_securelevel_system_cb(kauth_cred_t cred, kauth_action_t action, 252 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 253 { 254 int result; 255 enum kauth_system_req req; 256 257 result = KAUTH_RESULT_DEFER; 258 req = (enum kauth_system_req)arg0; 259 260 switch (action) { 261 case KAUTH_SYSTEM_CHSYSFLAGS: 262 /* Deprecated. */ 263 if (securelevel > 0) 264 result = KAUTH_RESULT_DENY; 265 break; 266 267 case KAUTH_SYSTEM_TIME: 268 switch (req) { 269 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET: 270 if (securelevel > 0) 271 result = KAUTH_RESULT_DENY; 272 break; 273 274 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: { 275 struct timespec *ts = arg1; 276 struct timespec *delta = arg2; 277 278 if (securelevel > 1 && time_wraps(ts, delta)) 279 result = KAUTH_RESULT_DENY; 280 281 break; 282 } 283 284 default: 285 break; 286 } 287 break; 288 289 case KAUTH_SYSTEM_MAP_VA_ZERO: 290 if (securelevel > 0) 291 result = KAUTH_RESULT_DENY; 292 break; 293 294 case KAUTH_SYSTEM_MODULE: 295 if (securelevel > 0) 296 result = KAUTH_RESULT_DENY; 297 break; 298 299 case KAUTH_SYSTEM_MOUNT: 300 switch (req) { 301 case KAUTH_REQ_SYSTEM_MOUNT_NEW: 302 if (securelevel > 1) 303 result = KAUTH_RESULT_DENY; 304 305 break; 306 307 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: 308 if (securelevel > 1) { 309 struct mount *mp = arg1; 310 u_long flags = (u_long)arg2; 311 312 /* Can only degrade from read/write to read-only. */ 313 if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD | 314 MNT_FORCE | MNT_UPDATE)) 315 result = KAUTH_RESULT_DENY; 316 } 317 318 break; 319 320 default: 321 break; 322 } 323 324 break; 325 326 case KAUTH_SYSTEM_SYSCTL: 327 switch (req) { 328 case KAUTH_REQ_SYSTEM_SYSCTL_ADD: 329 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE: 330 case KAUTH_REQ_SYSTEM_SYSCTL_DESC: 331 if (securelevel > 0) 332 result = KAUTH_RESULT_DENY; 333 break; 334 335 default: 336 break; 337 } 338 break; 339 340 case KAUTH_SYSTEM_SETIDCORE: 341 if (securelevel > 0) 342 result = KAUTH_RESULT_DENY; 343 break; 344 345 case KAUTH_SYSTEM_DEBUG: 346 switch (req) { 347 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: 348 if (securelevel > 0) 349 result = KAUTH_RESULT_DENY; 350 break; 351 352 default: 353 break; 354 } 355 break; 356 357 default: 358 break; 359 } 360 361 return (result); 362 } 363 364 /* 365 * kauth(9) listener 366 * 367 * Security model: Traditional NetBSD 368 * Scope: Process 369 * Responsibility: Securelevel 370 */ 371 int 372 secmodel_securelevel_process_cb(kauth_cred_t cred, kauth_action_t action, 373 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 374 { 375 struct proc *p; 376 int result; 377 378 result = KAUTH_RESULT_DEFER; 379 p = arg0; 380 381 switch (action) { 382 case KAUTH_PROCESS_PROCFS: { 383 enum kauth_process_req req; 384 385 req = (enum kauth_process_req)arg2; 386 switch (req) { 387 case KAUTH_REQ_PROCESS_PROCFS_READ: 388 break; 389 390 case KAUTH_REQ_PROCESS_PROCFS_RW: 391 case KAUTH_REQ_PROCESS_PROCFS_WRITE: 392 if ((p == initproc) && (securelevel > -1)) 393 result = KAUTH_RESULT_DENY; 394 395 break; 396 397 default: 398 break; 399 } 400 401 break; 402 } 403 404 case KAUTH_PROCESS_PTRACE: 405 if ((p == initproc) && (securelevel > -1)) 406 result = KAUTH_RESULT_DENY; 407 408 break; 409 410 case KAUTH_PROCESS_CORENAME: 411 if (securelevel > 1) 412 result = KAUTH_RESULT_DENY; 413 break; 414 415 default: 416 break; 417 } 418 419 return (result); 420 } 421 422 /* 423 * kauth(9) listener 424 * 425 * Security model: Traditional NetBSD 426 * Scope: Network 427 * Responsibility: Securelevel 428 */ 429 int 430 secmodel_securelevel_network_cb(kauth_cred_t cred, kauth_action_t action, 431 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 432 { 433 int result; 434 enum kauth_network_req req; 435 436 result = KAUTH_RESULT_DEFER; 437 req = (enum kauth_network_req)arg0; 438 439 switch (action) { 440 case KAUTH_NETWORK_FIREWALL: 441 switch (req) { 442 case KAUTH_REQ_NETWORK_FIREWALL_FW: 443 case KAUTH_REQ_NETWORK_FIREWALL_NAT: 444 if (securelevel > 1) 445 result = KAUTH_RESULT_DENY; 446 break; 447 448 default: 449 break; 450 } 451 break; 452 453 case KAUTH_NETWORK_FORWSRCRT: 454 if (securelevel > 0) 455 result = KAUTH_RESULT_DENY; 456 break; 457 458 default: 459 break; 460 } 461 462 return (result); 463 } 464 465 /* 466 * kauth(9) listener 467 * 468 * Security model: Traditional NetBSD 469 * Scope: Machdep 470 * Responsibility: Securelevel 471 */ 472 int 473 secmodel_securelevel_machdep_cb(kauth_cred_t cred, kauth_action_t action, 474 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 475 { 476 int result; 477 478 result = KAUTH_RESULT_DEFER; 479 480 switch (action) { 481 case KAUTH_MACHDEP_IOPERM_SET: 482 case KAUTH_MACHDEP_IOPL: 483 if (securelevel > 0) 484 result = KAUTH_RESULT_DENY; 485 break; 486 487 case KAUTH_MACHDEP_UNMANAGEDMEM: 488 if (securelevel > 0) 489 result = KAUTH_RESULT_DENY; 490 break; 491 492 case KAUTH_MACHDEP_CPU_UCODE_APPLY: 493 if (securelevel > 1) 494 result = KAUTH_RESULT_DENY; 495 break; 496 497 default: 498 break; 499 } 500 501 return (result); 502 } 503 504 /* 505 * kauth(9) listener 506 * 507 * Security model: Traditional NetBSD 508 * Scope: Device 509 * Responsibility: Securelevel 510 */ 511 int 512 secmodel_securelevel_device_cb(kauth_cred_t cred, kauth_action_t action, 513 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 514 { 515 int result; 516 517 result = KAUTH_RESULT_DEFER; 518 519 switch (action) { 520 case KAUTH_DEVICE_RAWIO_SPEC: { 521 struct vnode *vp; 522 enum kauth_device_req req; 523 524 req = (enum kauth_device_req)arg0; 525 vp = arg1; 526 527 KASSERT(vp != NULL); 528 529 /* Handle /dev/mem and /dev/kmem. */ 530 if (iskmemvp(vp)) { 531 switch (req) { 532 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 533 break; 534 535 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 536 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 537 if (securelevel > 0) 538 result = KAUTH_RESULT_DENY; 539 540 break; 541 542 default: 543 break; 544 } 545 546 break; 547 } 548 549 switch (req) { 550 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 551 break; 552 553 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 554 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: { 555 int error; 556 557 error = rawdev_mounted(vp, NULL); 558 559 /* Not a disk. */ 560 if (error == EINVAL) 561 break; 562 563 if (error && securelevel > 0) 564 result = KAUTH_RESULT_DENY; 565 566 if (securelevel > 1) 567 result = KAUTH_RESULT_DENY; 568 569 break; 570 } 571 572 default: 573 break; 574 } 575 576 break; 577 } 578 579 case KAUTH_DEVICE_RAWIO_PASSTHRU: 580 if (securelevel > 0) { 581 u_long bits; 582 583 bits = (u_long)arg0; 584 585 KASSERT(bits != 0); 586 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0); 587 588 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF) 589 result = KAUTH_RESULT_DENY; 590 } 591 592 break; 593 594 case KAUTH_DEVICE_GPIO_PINSET: 595 if (securelevel > 0) 596 result = KAUTH_RESULT_DENY; 597 break; 598 599 case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE: 600 if (securelevel > 0) 601 result = KAUTH_RESULT_DENY; 602 break; 603 604 default: 605 break; 606 } 607 608 return (result); 609 } 610 611 int 612 secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action, 613 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) 614 { 615 int result; 616 617 result = KAUTH_RESULT_DEFER; 618 619 if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) && 620 (action & KAUTH_VNODE_HAS_SYSFLAGS)) { 621 if (securelevel > 0) 622 result = KAUTH_RESULT_DENY; 623 } 624 625 return (result); 626 } 627 628