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