1 /* $NetBSD: secmodel_securelevel.c,v 1.8 2008/01/23 15:04:41 elad Exp $ */ 2 /*- 3 * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * This file contains kauth(9) listeners needed to implement the traditional 31 * NetBSD securelevel. 32 * 33 * The securelevel is a system-global indication on what operations are 34 * allowed or not. It affects all users, including root. 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.8 2008/01/23 15:04:41 elad Exp $"); 39 40 #ifdef _KERNEL_OPT 41 #include "opt_insecure.h" 42 #endif /* _KERNEL_OPT */ 43 44 #include <sys/types.h> 45 #include <sys/param.h> 46 #include <sys/kauth.h> 47 48 #include <sys/conf.h> 49 #include <sys/mount.h> 50 #include <sys/sysctl.h> 51 #include <sys/vnode.h> 52 53 #include <miscfs/specfs/specdev.h> 54 55 #include <secmodel/securelevel/securelevel.h> 56 57 static int securelevel; 58 59 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device; 60 61 /* 62 * sysctl helper routine for securelevel. ensures that the value 63 * only rises unless the caller has pid 1 (assumed to be init). 64 */ 65 int 66 secmodel_securelevel_sysctl(SYSCTLFN_ARGS) 67 { 68 int newsecurelevel, error; 69 struct sysctlnode node; 70 71 newsecurelevel = securelevel; 72 node = *rnode; 73 node.sysctl_data = &newsecurelevel; 74 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 75 if (error || newp == NULL) 76 return (error); 77 78 if (newsecurelevel < securelevel && l && l->l_proc->p_pid != 1) 79 return (EPERM); 80 81 securelevel = newsecurelevel; 82 83 return (error); 84 } 85 86 void 87 secmodel_securelevel_init(void) 88 { 89 #ifdef INSECURE 90 securelevel = -1; 91 #else 92 securelevel = 0; 93 #endif /* INSECURE */ 94 } 95 96 SYSCTL_SETUP(sysctl_security_securelevel_setup, 97 "sysctl security securelevel setup") 98 { 99 /* 100 * For compatibility, we create a kern.securelevel variable. 101 */ 102 sysctl_createv(clog, 0, NULL, NULL, 103 CTLFLAG_PERMANENT, 104 CTLTYPE_NODE, "kern", NULL, 105 NULL, 0, NULL, 0, 106 CTL_KERN, CTL_EOL); 107 108 sysctl_createv(clog, 0, NULL, NULL, 109 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 110 CTLTYPE_INT, "securelevel", 111 SYSCTL_DESCR("System security level"), 112 secmodel_securelevel_sysctl, 0, NULL, 0, 113 CTL_KERN, KERN_SECURELVL, CTL_EOL); 114 } 115 116 void 117 secmodel_securelevel_start(void) 118 { 119 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, 120 secmodel_securelevel_system_cb, NULL); 121 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, 122 secmodel_securelevel_process_cb, NULL); 123 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, 124 secmodel_securelevel_network_cb, NULL); 125 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, 126 secmodel_securelevel_machdep_cb, NULL); 127 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, 128 secmodel_securelevel_device_cb, NULL); 129 } 130 131 #if defined(_LKM) 132 void 133 secmodel_securelevel_stop(void) 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 #endif /* _LKM */ 142 143 /* 144 * kauth(9) listener 145 * 146 * Security model: Traditional NetBSD 147 * Scope: System 148 * Responsibility: Securelevel 149 */ 150 int 151 secmodel_securelevel_system_cb(kauth_cred_t cred, 152 kauth_action_t action, void *cookie, void *arg0, void *arg1, 153 void *arg2, void *arg3) 154 { 155 int result; 156 enum kauth_system_req req; 157 158 result = KAUTH_RESULT_DEFER; 159 req = (enum kauth_system_req)arg0; 160 161 switch (action) { 162 case KAUTH_SYSTEM_CHSYSFLAGS: 163 if (securelevel > 0) 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 (securelevel > 0) 171 result = KAUTH_RESULT_DENY; 172 break; 173 174 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: { 175 struct timespec *ts = arg1; 176 struct timeval *delta = arg2; 177 178 /* 179 * Don't allow the time to be set forward so far it will wrap 180 * and become negative, thus allowing an attacker to bypass 181 * the next check below. The cutoff is 1 year before rollover 182 * occurs, so even if the attacker uses adjtime(2) to move 183 * the time past the cutoff, it will take a very long time 184 * to get to the wrap point. 185 * 186 * XXX: we check against INT_MAX since on 64-bit 187 * platforms, sizeof(int) != sizeof(long) and 188 * time_t is 32 bits even when atv.tv_sec is 64 bits. 189 */ 190 if (securelevel > 1 && 191 ((ts->tv_sec > INT_MAX - 365*24*60*60) || 192 (delta->tv_sec < 0 || delta->tv_usec < 0))) 193 result = KAUTH_RESULT_DENY; 194 195 break; 196 } 197 198 default: 199 break; 200 } 201 break; 202 203 case KAUTH_SYSTEM_LKM: 204 case KAUTH_SYSTEM_MODULE: 205 if (securelevel > 0) 206 result = KAUTH_RESULT_DENY; 207 break; 208 209 case KAUTH_SYSTEM_MOUNT: 210 switch (req) { 211 case KAUTH_REQ_SYSTEM_MOUNT_NEW: 212 if (securelevel > 1) 213 result = KAUTH_RESULT_DENY; 214 215 break; 216 217 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: 218 if (securelevel > 1) { 219 struct mount *mp = arg1; 220 u_long flags = (u_long)arg2; 221 222 /* Can only degrade from read/write to read-only. */ 223 if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD | 224 MNT_FORCE | MNT_UPDATE)) 225 result = KAUTH_RESULT_DENY; 226 } 227 228 break; 229 230 default: 231 break; 232 } 233 234 break; 235 236 case KAUTH_SYSTEM_SYSCTL: 237 switch (req) { 238 case KAUTH_REQ_SYSTEM_SYSCTL_ADD: 239 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE: 240 case KAUTH_REQ_SYSTEM_SYSCTL_DESC: 241 if (securelevel > 0) 242 result = KAUTH_RESULT_DENY; 243 break; 244 245 default: 246 break; 247 } 248 break; 249 250 case KAUTH_SYSTEM_SETIDCORE: 251 if (securelevel > 0) 252 result = KAUTH_RESULT_DENY; 253 break; 254 255 case KAUTH_SYSTEM_DEBUG: 256 switch (req) { 257 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: 258 if (securelevel > 0) 259 result = KAUTH_RESULT_DENY; 260 break; 261 262 default: 263 break; 264 } 265 break; 266 } 267 268 return (result); 269 } 270 271 /* 272 * kauth(9) listener 273 * 274 * Security model: Traditional NetBSD 275 * Scope: Process 276 * Responsibility: Securelevel 277 */ 278 int 279 secmodel_securelevel_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; 285 286 result = KAUTH_RESULT_DEFER; 287 p = arg0; 288 289 switch (action) { 290 case KAUTH_PROCESS_PROCFS: { 291 enum kauth_process_req req; 292 293 req = (enum kauth_process_req)arg2; 294 switch (req) { 295 case KAUTH_REQ_PROCESS_PROCFS_READ: 296 break; 297 298 case KAUTH_REQ_PROCESS_PROCFS_RW: 299 case KAUTH_REQ_PROCESS_PROCFS_WRITE: 300 if ((p == initproc) && (securelevel > -1)) 301 result = KAUTH_RESULT_DENY; 302 303 break; 304 305 default: 306 break; 307 } 308 309 break; 310 } 311 312 case KAUTH_PROCESS_PTRACE: 313 if ((p == initproc) && (securelevel >= 0)) 314 result = KAUTH_RESULT_DENY; 315 316 break; 317 318 case KAUTH_PROCESS_CORENAME: 319 if (securelevel > 1) 320 result = KAUTH_RESULT_DENY; 321 break; 322 } 323 324 return (result); 325 } 326 327 /* 328 * kauth(9) listener 329 * 330 * Security model: Traditional NetBSD 331 * Scope: Network 332 * Responsibility: Securelevel 333 */ 334 int 335 secmodel_securelevel_network_cb(kauth_cred_t cred, 336 kauth_action_t action, void *cookie, void *arg0, 337 void *arg1, void *arg2, void *arg3) 338 { 339 int result; 340 enum kauth_network_req req; 341 342 result = KAUTH_RESULT_DEFER; 343 req = (enum kauth_network_req)arg0; 344 345 switch (action) { 346 case KAUTH_NETWORK_FIREWALL: 347 switch (req) { 348 case KAUTH_REQ_NETWORK_FIREWALL_FW: 349 case KAUTH_REQ_NETWORK_FIREWALL_NAT: 350 if (securelevel > 1) 351 result = KAUTH_RESULT_DENY; 352 break; 353 354 default: 355 break; 356 } 357 break; 358 359 case KAUTH_NETWORK_FORWSRCRT: 360 if (securelevel > 0) 361 result = KAUTH_RESULT_DENY; 362 break; 363 } 364 365 return (result); 366 } 367 368 /* 369 * kauth(9) listener 370 * 371 * Security model: Traditional NetBSD 372 * Scope: Machdep 373 * Responsibility: Securelevel 374 */ 375 int 376 secmodel_securelevel_machdep_cb(kauth_cred_t cred, 377 kauth_action_t action, void *cookie, void *arg0, 378 void *arg1, void *arg2, void *arg3) 379 { 380 int result; 381 382 result = KAUTH_RESULT_DEFER; 383 384 switch (action) { 385 case KAUTH_MACHDEP_IOPERM_SET: 386 case KAUTH_MACHDEP_IOPL: 387 if (securelevel > 0) 388 result = KAUTH_RESULT_DENY; 389 break; 390 391 case KAUTH_MACHDEP_UNMANAGEDMEM: 392 if (securelevel > 0) 393 result = KAUTH_RESULT_DENY; 394 break; 395 } 396 397 return (result); 398 } 399 400 /* 401 * kauth(9) listener 402 * 403 * Security model: Traditional NetBSD 404 * Scope: Device 405 * Responsibility: Securelevel 406 */ 407 int 408 secmodel_securelevel_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; 413 414 result = KAUTH_RESULT_DEFER; 415 416 switch (action) { 417 case KAUTH_DEVICE_RAWIO_SPEC: { 418 struct vnode *vp, *bvp; 419 enum kauth_device_req req; 420 dev_t dev; 421 int d_type; 422 423 req = (enum kauth_device_req)arg0; 424 vp = arg1; 425 426 KASSERT(vp != NULL); 427 428 dev = vp->v_rdev; 429 d_type = D_OTHER; 430 bvp = NULL; 431 432 /* Handle /dev/mem and /dev/kmem. */ 433 if ((vp->v_type == VCHR) && iskmemdev(dev)) { 434 switch (req) { 435 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 436 break; 437 438 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 439 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 440 if (securelevel > 0) 441 result = KAUTH_RESULT_DENY; 442 break; 443 } 444 445 break; 446 } 447 448 switch (req) { 449 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: 450 break; 451 452 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: 453 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: 454 switch (vp->v_type) { 455 case VCHR: { 456 const struct cdevsw *cdev; 457 458 cdev = cdevsw_lookup(dev); 459 if (cdev != NULL) { 460 dev_t blkdev; 461 462 blkdev = devsw_chr2blk(dev); 463 if (blkdev != NODEV) { 464 vfinddev(blkdev, VBLK, &bvp); 465 if (bvp != NULL) 466 d_type = (cdev->d_flag 467 & D_TYPEMASK); 468 } 469 } 470 471 break; 472 } 473 case VBLK: { 474 const struct bdevsw *bdev; 475 476 bdev = bdevsw_lookup(dev); 477 if (bdev != NULL) 478 d_type = (bdev->d_flag & D_TYPEMASK); 479 480 bvp = vp; 481 482 break; 483 } 484 485 default: 486 break; 487 } 488 489 if (d_type != D_DISK) 490 break; 491 492 /* 493 * XXX: This is bogus. We should be failing the request 494 * XXX: not only if this specific slice is mounted, but 495 * XXX: if it's on a disk with any other mounted slice. 496 */ 497 if (vfs_mountedon(bvp) && (securelevel > 0)) 498 break; 499 500 if (securelevel > 1) 501 result = KAUTH_RESULT_DENY; 502 503 break; 504 } 505 506 break; 507 } 508 509 case KAUTH_DEVICE_RAWIO_PASSTHRU: 510 if (securelevel > 0) { 511 u_long bits; 512 513 bits = (u_long)arg0; 514 515 KASSERT(bits != 0); 516 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0); 517 518 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF) 519 result = KAUTH_RESULT_DENY; 520 } 521 522 break; 523 } 524 525 return (result); 526 } 527