secmodel_keylock.c revision 1.3
1/* $NetBSD: secmodel_keylock.c,v 1.3 2009/10/03 20:48:42 elad 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.3 2009/10/03 20:48:42 elad 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/mount.h> 65#include <sys/sysctl.h> 66#include <sys/vnode.h> 67#include <sys/timevar.h> 68 69#include <dev/keylock.h> 70 71#include <miscfs/specfs/specdev.h> 72 73#include <secmodel/keylock/keylock.h> 74 75static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device; 76 77SYSCTL_SETUP(sysctl_security_keylock_setup, 78 "sysctl security keylock setup") 79{ 80 const struct sysctlnode *rnode; 81 82 sysctl_createv(clog, 0, NULL, &rnode, 83 CTLFLAG_PERMANENT, 84 CTLTYPE_NODE, "security", NULL, 85 NULL, 0, NULL, 0, 86 CTL_SECURITY, CTL_EOL); 87 88 sysctl_createv(clog, 0, &rnode, &rnode, 89 CTLFLAG_PERMANENT, 90 CTLTYPE_NODE, "models", NULL, 91 NULL, 0, NULL, 0, 92 CTL_CREATE, CTL_EOL); 93 94 sysctl_createv(clog, 0, &rnode, &rnode, 95 CTLFLAG_PERMANENT, 96 CTLTYPE_NODE, "keylock", 97 SYSCTL_DESCR("Keylock security model"), 98 NULL, 0, NULL, 0, 99 CTL_CREATE, CTL_EOL); 100 101 sysctl_createv(clog, 0, &rnode, NULL, 102 CTLFLAG_PERMANENT, 103 CTLTYPE_STRING, "name", NULL, 104 NULL, 0, __UNCONST("Keylock"), 0, 105 CTL_CREATE, CTL_EOL); 106} 107 108void 109secmodel_keylock_init(void) 110{ 111} 112 113void 114secmodel_keylock_start(void) 115{ 116 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 117 secmodel_keylock_system_cb, NULL); 118 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 119 secmodel_keylock_process_cb, NULL); 120 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, 121 secmodel_keylock_network_cb, NULL); 122 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, 123 secmodel_keylock_machdep_cb, NULL); 124 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, 125 secmodel_keylock_device_cb, NULL); 126} 127 128void 129secmodel_keylock_stop(void) 130{ 131 kauth_unlisten_scope(l_system); 132 kauth_unlisten_scope(l_process); 133 kauth_unlisten_scope(l_network); 134 kauth_unlisten_scope(l_machdep); 135 kauth_unlisten_scope(l_device); 136} 137 138/* 139 * kauth(9) listener 140 * 141 * Security model: Multi-position keylock 142 * Scope: System 143 * Responsibility: Keylock 144 */ 145int 146secmodel_keylock_system_cb(kauth_cred_t cred, 147 kauth_action_t action, void *cookie, void *arg0, void *arg1, 148 void *arg2, void *arg3) 149{ 150 int result; 151 enum kauth_system_req req; 152 int kstate; 153 154 kstate = keylock_state(); 155 if (kstate == KEYLOCK_ABSENT) 156 return KAUTH_RESULT_DEFER; 157 else if (kstate == KEYLOCK_TAMPER) 158 return KAUTH_RESULT_DENY; 159 160 result = KAUTH_RESULT_DEFER; 161 req = (enum kauth_system_req)arg0; 162 163 switch (action) { 164 case KAUTH_SYSTEM_CHSYSFLAGS: 165 if (kstate == KEYLOCK_CLOSE) 166 result = KAUTH_RESULT_DENY; 167 break; 168 169 case KAUTH_SYSTEM_TIME: 170 switch (req) { 171 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET: 172 if (kstate == KEYLOCK_CLOSE) 173 result = KAUTH_RESULT_DENY; 174 break; 175 176 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: { 177 struct timespec *ts = arg1; 178 struct timespec *delta = arg2; 179 180 if (keylock_position() > 1 && time_wraps(ts, delta)) 181 result = KAUTH_RESULT_DENY; 182 break; 183 } 184 default: 185 break; 186 } 187 break; 188 189 case KAUTH_SYSTEM_MODULE: 190 if (kstate == KEYLOCK_CLOSE) 191 result = KAUTH_RESULT_DENY; 192 break; 193 194 case KAUTH_SYSTEM_MOUNT: 195 switch (req) { 196 case KAUTH_REQ_SYSTEM_MOUNT_NEW: 197 if (kstate == KEYLOCK_CLOSE) 198 result = KAUTH_RESULT_DENY; 199 200 break; 201 202 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: 203 if (kstate == KEYLOCK_CLOSE) { 204 struct mount *mp = arg1; 205 u_long flags = (u_long)arg2; 206 207 /* 208 * Can only degrade from read/write to 209 * read-only. 210 */ 211 if (flags != (mp->mnt_flag | MNT_RDONLY | 212 MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) 213 result = KAUTH_RESULT_DENY; 214 } 215 break; 216 default: 217 break; 218 } 219 220 break; 221 222 case KAUTH_SYSTEM_SYSCTL: 223 switch (req) { 224 case KAUTH_REQ_SYSTEM_SYSCTL_ADD: 225 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE: 226 case KAUTH_REQ_SYSTEM_SYSCTL_DESC: 227 if (kstate == KEYLOCK_CLOSE) 228 result = KAUTH_RESULT_DENY; 229 break; 230 default: 231 break; 232 } 233 break; 234 235 case KAUTH_SYSTEM_SETIDCORE: 236 if (kstate == KEYLOCK_CLOSE) 237 result = KAUTH_RESULT_DENY; 238 break; 239 240 case KAUTH_SYSTEM_DEBUG: 241 switch (req) { 242 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: 243 if (kstate == KEYLOCK_CLOSE) 244 result = KAUTH_RESULT_DENY; 245 break; 246 default: 247 break; 248 } 249 break; 250 } 251 252 return result; 253} 254 255/* 256 * kauth(9) listener 257 * 258 * Security model: Multi-position keylock 259 * Scope: Process 260 * Responsibility: Keylock 261 */ 262int 263secmodel_keylock_process_cb(kauth_cred_t cred, 264 kauth_action_t action, void *cookie, void *arg0, 265 void *arg1, void *arg2, void *arg3) 266{ 267 struct proc *p; 268 int result, kstate; 269 270 kstate = keylock_state(); 271 if (kstate == KEYLOCK_ABSENT) 272 return KAUTH_RESULT_DEFER; 273 else if (kstate == KEYLOCK_TAMPER) 274 return KAUTH_RESULT_DENY; 275 276 result = KAUTH_RESULT_DEFER; 277 p = arg0; 278 279 switch (action) { 280 case KAUTH_PROCESS_PROCFS: { 281 enum kauth_process_req req; 282 283 req = (enum kauth_process_req)arg2; 284 switch (req) { 285 case KAUTH_REQ_PROCESS_PROCFS_READ: 286 break; 287 288 case KAUTH_REQ_PROCESS_PROCFS_RW: 289 case KAUTH_REQ_PROCESS_PROCFS_WRITE: 290 if ((p == initproc) && (kstate != KEYLOCK_OPEN)) 291 result = KAUTH_RESULT_DENY; 292 293 break; 294 default: 295 break; 296 } 297 298 break; 299 } 300 301 case KAUTH_PROCESS_PTRACE: 302 if ((p == initproc) && (kstate != KEYLOCK_OPEN)) 303 result = KAUTH_RESULT_DENY; 304 305 break; 306 307 case KAUTH_PROCESS_CORENAME: 308 if (kstate == KEYLOCK_CLOSE) 309 result = KAUTH_RESULT_DENY; 310 break; 311 } 312 return result; 313} 314 315/* 316 * kauth(9) listener 317 * 318 * Security model: Multi-position keylock 319 * Scope: Network 320 * Responsibility: Keylock 321 */ 322int 323secmodel_keylock_network_cb(kauth_cred_t cred, 324 kauth_action_t action, void *cookie, void *arg0, 325 void *arg1, void *arg2, void *arg3) 326{ 327 int result, kstate; 328 enum kauth_network_req req; 329 330 kstate = keylock_state(); 331 if (kstate == KEYLOCK_ABSENT) 332 return KAUTH_RESULT_DEFER; 333 else if (kstate == KEYLOCK_TAMPER) 334 return KAUTH_RESULT_DENY; 335 336 result = KAUTH_RESULT_DEFER; 337 req = (enum kauth_network_req)arg0; 338 339 switch (action) { 340 case KAUTH_NETWORK_FIREWALL: 341 switch (req) { 342 case KAUTH_REQ_NETWORK_FIREWALL_FW: 343 case KAUTH_REQ_NETWORK_FIREWALL_NAT: 344 if (kstate == KEYLOCK_CLOSE) 345 result = KAUTH_RESULT_DENY; 346 break; 347 348 default: 349 break; 350 } 351 break; 352 353 case KAUTH_NETWORK_FORWSRCRT: 354 if (kstate != KEYLOCK_OPEN) 355 result = KAUTH_RESULT_DENY; 356 break; 357 } 358 359 return result; 360} 361 362/* 363 * kauth(9) listener 364 * 365 * Security model: Multi-position keylock 366 * Scope: Machdep 367 * Responsibility: Keylock 368 */ 369int 370secmodel_keylock_machdep_cb(kauth_cred_t cred, 371 kauth_action_t action, void *cookie, void *arg0, 372 void *arg1, void *arg2, void *arg3) 373{ 374 int result, kstate; 375 376 kstate = keylock_state(); 377 if (kstate == KEYLOCK_ABSENT) 378 return KAUTH_RESULT_DEFER; 379 else if (kstate == KEYLOCK_TAMPER) 380 return KAUTH_RESULT_DENY; 381 382 result = KAUTH_RESULT_DEFER; 383 384 switch (action) { 385 case KAUTH_MACHDEP_IOPERM_SET: 386 case KAUTH_MACHDEP_IOPL: 387 if (kstate != KEYLOCK_OPEN) 388 result = KAUTH_RESULT_DENY; 389 break; 390 391 case KAUTH_MACHDEP_UNMANAGEDMEM: 392 if (kstate != KEYLOCK_OPEN) 393 result = KAUTH_RESULT_DENY; 394 break; 395 } 396 397 return result; 398} 399 400/* 401 * kauth(9) listener 402 * 403 * Security model: Multi-position keylock 404 * Scope: Device 405 * Responsibility: Keylock 406 */ 407int 408secmodel_keylock_device_cb(kauth_cred_t cred, 409 kauth_action_t action, void *cookie, void *arg0, 410 void *arg1, void *arg2, void *arg3) 411{ 412 int result, kstate; 413 414 kstate = keylock_state(); 415 if (kstate == KEYLOCK_ABSENT) 416 return KAUTH_RESULT_DEFER; 417 else if (kstate == KEYLOCK_TAMPER) 418 return KAUTH_RESULT_DENY; 419 420 result = KAUTH_RESULT_DEFER; 421 422 switch (action) { 423 case KAUTH_DEVICE_RAWIO_SPEC: { 424 struct vnode *vp, *bvp; 425 enum kauth_device_req req; 426 dev_t dev; 427 int d_type; 428 429 req = (enum kauth_device_req)arg0; 430 vp = arg1; 431 432 KASSERT(vp != NULL); 433 434 dev = vp->v_rdev; 435 d_type = D_OTHER; 436 bvp = NULL; 437 438 /* Handle /dev/mem and /dev/kmem. */ 439 if ((vp->v_type == VCHR) && iskmemdev(dev)) { 440 switch (req) { 441 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 442 break; 443 444 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 445 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 446 if (kstate != KEYLOCK_OPEN) 447 result = KAUTH_RESULT_DENY; 448 break; 449 default: 450 break; 451 } 452 break; 453 } 454 455 switch (req) { 456 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 457 break; 458 459 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 460 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 461 switch (vp->v_type) { 462 case VCHR: { 463 const struct cdevsw *cdev; 464 465 cdev = cdevsw_lookup(dev); 466 if (cdev != NULL) { 467 dev_t blkdev; 468 469 blkdev = devsw_chr2blk(dev); 470 if (blkdev != NODEV) { 471 vfinddev(blkdev, VBLK, &bvp); 472 if (bvp != NULL) 473 d_type = (cdev->d_flag 474 & D_TYPEMASK); 475 } 476 } 477 478 break; 479 } 480 case VBLK: { 481 const struct bdevsw *bdev; 482 483 bdev = bdevsw_lookup(dev); 484 if (bdev != NULL) 485 d_type = (bdev->d_flag & D_TYPEMASK); 486 487 bvp = vp; 488 489 break; 490 } 491 default: 492 break; 493 } 494 495 if (d_type != D_DISK) 496 break; 497 498 /* 499 * XXX: This is bogus. We should be failing the request 500 * XXX: not only if this specific slice is mounted, but 501 * XXX: if it's on a disk with any other mounted slice. 502 */ 503 if (vfs_mountedon(bvp) && (kstate != KEYLOCK_OPEN)) 504 break; 505 506 if (kstate == KEYLOCK_CLOSE) 507 result = KAUTH_RESULT_DENY; 508 509 break; 510 default: 511 break; 512 } 513 break; 514 } 515 516 case KAUTH_DEVICE_RAWIO_PASSTHRU: 517 if (kstate != KEYLOCK_OPEN) { 518 u_long bits; 519 520 bits = (u_long)arg0; 521 522 KASSERT(bits != 0); 523 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) 524 == 0); 525 526 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF) 527 result = KAUTH_RESULT_DENY; 528 } 529 break; 530 531 case KAUTH_DEVICE_GPIO_PINSET: 532 if (kstate != KEYLOCK_OPEN) 533 result = KAUTH_RESULT_DENY; 534 break; 535 default: 536 break; 537 } 538 return result; 539} 540