secmodel_keylock.c revision 1.1
1/* $NetBSD: secmodel_keylock.c,v 1.1 2009/08/14 21:17:22 mbalmer Exp $ */ 2/*- 3 * Copyright (c) 2009 Marc Balmer <marc@msys.ch> 4 * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30/* 31 * This file contains kauth(9) listeners needed to implement an experimental 32 * keylock based security scheme. 33 * 34 * The position of the keylock is a system-global indication on what 35 * operations are allowed or not. It affects all users, including root. 36 * 37 * Rules: 38 * 39 * - If the number of possible keylock positions is 0, assume there is no 40 * keylock present, do not dissallow any action, i.e. do nothing 41 * 42 * - If the number of possible keylock positions is greater than 0, but the 43 * current lock position is 0, assume tampering with the lock and forbid 44 * all actions. 45 * 46 * - If the lock is in the lowest position, assume the system is locked and 47 * forbid most actions. 48 * 49 * - If the lock is in the highest position, assume the system to be open and 50 * forbid nothing. 51 * 52 * - If the security.models.keylock.order sysctl is set to a value != 0, 53 * reverse this order. 54 */ 55 56#include <sys/cdefs.h> 57__KERNEL_RCSID(0, "$NetBSD: secmodel_keylock.c,v 1.1 2009/08/14 21:17:22 mbalmer Exp $"); 58 59#include <sys/types.h> 60#include <sys/param.h> 61#include <sys/kauth.h> 62 63#include <sys/conf.h> 64#include <sys/keylock.h> 65#include <sys/mount.h> 66#include <sys/sysctl.h> 67#include <sys/vnode.h> 68 69#include <miscfs/specfs/specdev.h> 70 71#include <secmodel/keylock/keylock.h> 72 73static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device; 74 75SYSCTL_SETUP(sysctl_security_keylock_setup, 76 "sysctl security keylock setup") 77{ 78 const struct sysctlnode *rnode; 79 80 sysctl_createv(clog, 0, NULL, &rnode, 81 CTLFLAG_PERMANENT, 82 CTLTYPE_NODE, "security", NULL, 83 NULL, 0, NULL, 0, 84 CTL_SECURITY, CTL_EOL); 85 86 sysctl_createv(clog, 0, &rnode, &rnode, 87 CTLFLAG_PERMANENT, 88 CTLTYPE_NODE, "models", NULL, 89 NULL, 0, NULL, 0, 90 CTL_CREATE, CTL_EOL); 91 92 sysctl_createv(clog, 0, &rnode, &rnode, 93 CTLFLAG_PERMANENT, 94 CTLTYPE_NODE, "keylock", 95 SYSCTL_DESCR("Keylock security model"), 96 NULL, 0, NULL, 0, 97 CTL_CREATE, CTL_EOL); 98 99 sysctl_createv(clog, 0, &rnode, NULL, 100 CTLFLAG_PERMANENT, 101 CTLTYPE_STRING, "name", NULL, 102 NULL, 0, __UNCONST("Keylock"), 0, 103 CTL_CREATE, CTL_EOL); 104} 105 106void 107secmodel_keylock_init(void) 108{ 109} 110 111void 112secmodel_keylock_start(void) 113{ 114 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 115 secmodel_keylock_system_cb, NULL); 116 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 117 secmodel_keylock_process_cb, NULL); 118 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, 119 secmodel_keylock_network_cb, NULL); 120 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, 121 secmodel_keylock_machdep_cb, NULL); 122 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, 123 secmodel_keylock_device_cb, NULL); 124} 125 126void 127secmodel_keylock_stop(void) 128{ 129 kauth_unlisten_scope(l_system); 130 kauth_unlisten_scope(l_process); 131 kauth_unlisten_scope(l_network); 132 kauth_unlisten_scope(l_machdep); 133 kauth_unlisten_scope(l_device); 134} 135 136/* 137 * kauth(9) listener 138 * 139 * Security model: Multi-position keylock 140 * Scope: System 141 * Responsibility: Keylock 142 */ 143int 144secmodel_keylock_system_cb(kauth_cred_t cred, 145 kauth_action_t action, void *cookie, void *arg0, void *arg1, 146 void *arg2, void *arg3) 147{ 148 int result; 149 enum kauth_system_req req; 150 int kstate; 151 152 kstate = keylock_state(); 153 if (kstate == KEYLOCK_ABSENT) 154 return KAUTH_RESULT_DEFER; 155 else if (kstate == KEYLOCK_TAMPER) 156 return KAUTH_RESULT_DENY; 157 158 result = KAUTH_RESULT_DEFER; 159 req = (enum kauth_system_req)arg0; 160 161 switch (action) { 162 case KAUTH_SYSTEM_CHSYSFLAGS: 163 if (kstate == KEYLOCK_CLOSE) 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 (kstate == KEYLOCK_CLOSE) 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 (keylock_position() > 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 default: 194 break; 195 } 196 break; 197 198 case KAUTH_SYSTEM_MODULE: 199 if (kstate == KEYLOCK_CLOSE) 200 result = KAUTH_RESULT_DENY; 201 break; 202 203 case KAUTH_SYSTEM_MOUNT: 204 switch (req) { 205 case KAUTH_REQ_SYSTEM_MOUNT_NEW: 206 if (kstate == KEYLOCK_CLOSE) 207 result = KAUTH_RESULT_DENY; 208 209 break; 210 211 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: 212 if (kstate == KEYLOCK_CLOSE) { 213 struct mount *mp = arg1; 214 u_long flags = (u_long)arg2; 215 216 /* 217 * Can only degrade from read/write to 218 * read-only. 219 */ 220 if (flags != (mp->mnt_flag | MNT_RDONLY | 221 MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) 222 result = KAUTH_RESULT_DENY; 223 } 224 break; 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 (kstate == KEYLOCK_CLOSE) 237 result = KAUTH_RESULT_DENY; 238 break; 239 default: 240 break; 241 } 242 break; 243 244 case KAUTH_SYSTEM_SETIDCORE: 245 if (kstate == KEYLOCK_CLOSE) 246 result = KAUTH_RESULT_DENY; 247 break; 248 249 case KAUTH_SYSTEM_DEBUG: 250 switch (req) { 251 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: 252 if (kstate == KEYLOCK_CLOSE) 253 result = KAUTH_RESULT_DENY; 254 break; 255 default: 256 break; 257 } 258 break; 259 } 260 261 return result; 262} 263 264/* 265 * kauth(9) listener 266 * 267 * Security model: Multi-position keylock 268 * Scope: Process 269 * Responsibility: Keylock 270 */ 271int 272secmodel_keylock_process_cb(kauth_cred_t cred, 273 kauth_action_t action, void *cookie, void *arg0, 274 void *arg1, void *arg2, void *arg3) 275{ 276 struct proc *p; 277 int result, kstate; 278 279 kstate = keylock_state(); 280 if (kstate == KEYLOCK_ABSENT) 281 return KAUTH_RESULT_DEFER; 282 else if (kstate == KEYLOCK_TAMPER) 283 return KAUTH_RESULT_DENY; 284 285 result = KAUTH_RESULT_DEFER; 286 p = arg0; 287 288 switch (action) { 289 case KAUTH_PROCESS_PROCFS: { 290 enum kauth_process_req req; 291 292 req = (enum kauth_process_req)arg2; 293 switch (req) { 294 case KAUTH_REQ_PROCESS_PROCFS_READ: 295 break; 296 297 case KAUTH_REQ_PROCESS_PROCFS_RW: 298 case KAUTH_REQ_PROCESS_PROCFS_WRITE: 299 if ((p == initproc) && (kstate != KEYLOCK_OPEN)) 300 result = KAUTH_RESULT_DENY; 301 302 break; 303 default: 304 break; 305 } 306 307 break; 308 } 309 310 case KAUTH_PROCESS_PTRACE: 311 if ((p == initproc) && (kstate != KEYLOCK_OPEN)) 312 result = KAUTH_RESULT_DENY; 313 314 break; 315 316 case KAUTH_PROCESS_CORENAME: 317 if (kstate == KEYLOCK_CLOSE) 318 result = KAUTH_RESULT_DENY; 319 break; 320 } 321 return result; 322} 323 324/* 325 * kauth(9) listener 326 * 327 * Security model: Multi-position keylock 328 * Scope: Network 329 * Responsibility: Keylock 330 */ 331int 332secmodel_keylock_network_cb(kauth_cred_t cred, 333 kauth_action_t action, void *cookie, void *arg0, 334 void *arg1, void *arg2, void *arg3) 335{ 336 int result, kstate; 337 enum kauth_network_req req; 338 339 kstate = keylock_state(); 340 if (kstate == KEYLOCK_ABSENT) 341 return KAUTH_RESULT_DEFER; 342 else if (kstate == KEYLOCK_TAMPER) 343 return KAUTH_RESULT_DENY; 344 345 result = KAUTH_RESULT_DEFER; 346 req = (enum kauth_network_req)arg0; 347 348 switch (action) { 349 case KAUTH_NETWORK_FIREWALL: 350 switch (req) { 351 case KAUTH_REQ_NETWORK_FIREWALL_FW: 352 case KAUTH_REQ_NETWORK_FIREWALL_NAT: 353 if (kstate == KEYLOCK_CLOSE) 354 result = KAUTH_RESULT_DENY; 355 break; 356 357 default: 358 break; 359 } 360 break; 361 362 case KAUTH_NETWORK_FORWSRCRT: 363 if (kstate != KEYLOCK_OPEN) 364 result = KAUTH_RESULT_DENY; 365 break; 366 } 367 368 return result; 369} 370 371/* 372 * kauth(9) listener 373 * 374 * Security model: Multi-position keylock 375 * Scope: Machdep 376 * Responsibility: Keylock 377 */ 378int 379secmodel_keylock_machdep_cb(kauth_cred_t cred, 380 kauth_action_t action, void *cookie, void *arg0, 381 void *arg1, void *arg2, void *arg3) 382{ 383 int result, kstate; 384 385 kstate = keylock_state(); 386 if (kstate == KEYLOCK_ABSENT) 387 return KAUTH_RESULT_DEFER; 388 else if (kstate == KEYLOCK_TAMPER) 389 return KAUTH_RESULT_DENY; 390 391 result = KAUTH_RESULT_DEFER; 392 393 switch (action) { 394 case KAUTH_MACHDEP_IOPERM_SET: 395 case KAUTH_MACHDEP_IOPL: 396 if (kstate != KEYLOCK_OPEN) 397 result = KAUTH_RESULT_DENY; 398 break; 399 400 case KAUTH_MACHDEP_UNMANAGEDMEM: 401 if (kstate != KEYLOCK_OPEN) 402 result = KAUTH_RESULT_DENY; 403 break; 404 } 405 406 return result; 407} 408 409/* 410 * kauth(9) listener 411 * 412 * Security model: Multi-position keylock 413 * Scope: Device 414 * Responsibility: Keylock 415 */ 416int 417secmodel_keylock_device_cb(kauth_cred_t cred, 418 kauth_action_t action, void *cookie, void *arg0, 419 void *arg1, void *arg2, void *arg3) 420{ 421 int result, kstate; 422 423 kstate = keylock_state(); 424 if (kstate == KEYLOCK_ABSENT) 425 return KAUTH_RESULT_DEFER; 426 else if (kstate == KEYLOCK_TAMPER) 427 return KAUTH_RESULT_DENY; 428 429 result = KAUTH_RESULT_DEFER; 430 431 switch (action) { 432 case KAUTH_DEVICE_RAWIO_SPEC: { 433 struct vnode *vp, *bvp; 434 enum kauth_device_req req; 435 dev_t dev; 436 int d_type; 437 438 req = (enum kauth_device_req)arg0; 439 vp = arg1; 440 441 KASSERT(vp != NULL); 442 443 dev = vp->v_rdev; 444 d_type = D_OTHER; 445 bvp = NULL; 446 447 /* Handle /dev/mem and /dev/kmem. */ 448 if ((vp->v_type == VCHR) && iskmemdev(dev)) { 449 switch (req) { 450 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 451 break; 452 453 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 454 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 455 if (kstate != KEYLOCK_OPEN) 456 result = KAUTH_RESULT_DENY; 457 break; 458 default: 459 break; 460 } 461 break; 462 } 463 464 switch (req) { 465 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 466 break; 467 468 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 469 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 470 switch (vp->v_type) { 471 case VCHR: { 472 const struct cdevsw *cdev; 473 474 cdev = cdevsw_lookup(dev); 475 if (cdev != NULL) { 476 dev_t blkdev; 477 478 blkdev = devsw_chr2blk(dev); 479 if (blkdev != NODEV) { 480 vfinddev(blkdev, VBLK, &bvp); 481 if (bvp != NULL) 482 d_type = (cdev->d_flag 483 & D_TYPEMASK); 484 } 485 } 486 487 break; 488 } 489 case VBLK: { 490 const struct bdevsw *bdev; 491 492 bdev = bdevsw_lookup(dev); 493 if (bdev != NULL) 494 d_type = (bdev->d_flag & D_TYPEMASK); 495 496 bvp = vp; 497 498 break; 499 } 500 default: 501 break; 502 } 503 504 if (d_type != D_DISK) 505 break; 506 507 /* 508 * XXX: This is bogus. We should be failing the request 509 * XXX: not only if this specific slice is mounted, but 510 * XXX: if it's on a disk with any other mounted slice. 511 */ 512 if (vfs_mountedon(bvp) && (kstate != KEYLOCK_OPEN)) 513 break; 514 515 if (kstate == KEYLOCK_CLOSE) 516 result = KAUTH_RESULT_DENY; 517 518 break; 519 default: 520 break; 521 } 522 break; 523 } 524 525 case KAUTH_DEVICE_RAWIO_PASSTHRU: 526 if (kstate != KEYLOCK_OPEN) { 527 u_long bits; 528 529 bits = (u_long)arg0; 530 531 KASSERT(bits != 0); 532 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) 533 == 0); 534 535 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF) 536 result = KAUTH_RESULT_DENY; 537 } 538 break; 539 540 case KAUTH_DEVICE_GPIO_PINSET: 541 if (kstate != KEYLOCK_OPEN) 542 result = KAUTH_RESULT_DENY; 543 break; 544 default: 545 break; 546 } 547 return result; 548} 549