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