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