Home | History | Annotate | Line # | Download | only in securelevel
secmodel_securelevel.c revision 1.14
      1 /* $NetBSD: secmodel_securelevel.c,v 1.14 2009/10/02 18:50:14 elad Exp $ */
      2 /*-
      3  * Copyright (c) 2006 Elad Efrat <elad (at) 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.14 2009/10/02 18:50:14 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 #include <sys/module.h>
     53 
     54 #include <miscfs/specfs/specdev.h>
     55 
     56 #include <secmodel/securelevel/securelevel.h>
     57 
     58 MODULE(MODULE_CLASS_SECMODEL, securelevel, NULL);
     59 
     60 static int securelevel;
     61 
     62 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device,
     63     l_vnode;
     64 
     65 static struct sysctllog *securelevel_sysctl_log;
     66 
     67 /*
     68  * sysctl helper routine for securelevel. ensures that the value
     69  * only rises unless the caller has pid 1 (assumed to be init).
     70  */
     71 int
     72 secmodel_securelevel_sysctl(SYSCTLFN_ARGS)
     73 {
     74 	int newsecurelevel, error;
     75 	struct sysctlnode node;
     76 
     77 	newsecurelevel = securelevel;
     78 	node = *rnode;
     79 	node.sysctl_data = &newsecurelevel;
     80 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
     81 	if (error || newp == NULL)
     82 		return (error);
     83 
     84 	if (newsecurelevel < securelevel && l && l->l_proc->p_pid != 1)
     85 		return (EPERM);
     86 
     87 	securelevel = newsecurelevel;
     88 
     89 	return (error);
     90 }
     91 
     92 void
     93 sysctl_security_securelevel_setup(struct sysctllog **clog)
     94 {
     95 	const struct sysctlnode *rnode;
     96 
     97 	sysctl_createv(clog, 0, NULL, &rnode,
     98 		       CTLFLAG_PERMANENT,
     99 		       CTLTYPE_NODE, "security", NULL,
    100 		       NULL, 0, NULL, 0,
    101 		       CTL_SECURITY, CTL_EOL);
    102 
    103 	sysctl_createv(clog, 0, &rnode, &rnode,
    104 		       CTLFLAG_PERMANENT,
    105 		       CTLTYPE_NODE, "models", NULL,
    106 		       NULL, 0, NULL, 0,
    107 		       CTL_CREATE, CTL_EOL);
    108 
    109 	sysctl_createv(clog, 0, &rnode, &rnode,
    110 		       CTLFLAG_PERMANENT,
    111 		       CTLTYPE_NODE, "securelevel", NULL,
    112 		       NULL, 0, NULL, 0,
    113 		       CTL_CREATE, CTL_EOL);
    114 
    115 	sysctl_createv(clog, 0, &rnode, NULL,
    116 		       CTLFLAG_PERMANENT,
    117 		       CTLTYPE_STRING, "name", NULL,
    118 		       NULL, 0, __UNCONST("Traditional NetBSD: Securelevel"), 0,
    119 		       CTL_CREATE, CTL_EOL);
    120 
    121 	/* Compatibility: kern.securelevel */
    122 	sysctl_createv(clog, 0, NULL, NULL,
    123 		       CTLFLAG_PERMANENT,
    124 		       CTLTYPE_NODE, "kern", NULL,
    125 		       NULL, 0, NULL, 0,
    126 		       CTL_KERN, CTL_EOL);
    127 
    128 	sysctl_createv(clog, 0, NULL, NULL,
    129 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
    130 		       CTLTYPE_INT, "securelevel",
    131 		       SYSCTL_DESCR("System security level"),
    132 		       secmodel_securelevel_sysctl, 0, NULL, 0,
    133 		       CTL_KERN, KERN_SECURELVL, CTL_EOL);
    134 }
    135 
    136 void
    137 secmodel_securelevel_init(void)
    138 {
    139 #ifdef INSECURE
    140 	securelevel = -1;
    141 #else
    142 	securelevel = 0;
    143 #endif /* INSECURE */
    144 }
    145 
    146 void
    147 secmodel_securelevel_start(void)
    148 {
    149 	l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
    150 	    secmodel_securelevel_system_cb, NULL);
    151 	l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
    152 	    secmodel_securelevel_process_cb, NULL);
    153 	l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
    154 	    secmodel_securelevel_network_cb, NULL);
    155 	l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
    156 	    secmodel_securelevel_machdep_cb, NULL);
    157 	l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
    158 	    secmodel_securelevel_device_cb, NULL);
    159 	l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
    160 	    secmodel_securelevel_vnode_cb, NULL);
    161 }
    162 
    163 void
    164 secmodel_securelevel_stop(void)
    165 {
    166 	kauth_unlisten_scope(l_system);
    167 	kauth_unlisten_scope(l_process);
    168 	kauth_unlisten_scope(l_network);
    169 	kauth_unlisten_scope(l_machdep);
    170 	kauth_unlisten_scope(l_device);
    171 	kauth_unlisten_scope(l_vnode);
    172 }
    173 
    174 static int
    175 securelevel_modcmd(modcmd_t cmd, void *arg)
    176 {
    177 	int error = 0;
    178 
    179 	switch (cmd) {
    180 	case MODULE_CMD_INIT:
    181 		secmodel_securelevel_init();
    182 		secmodel_securelevel_start();
    183 		sysctl_security_securelevel_setup(&securelevel_sysctl_log);
    184 		break;
    185 
    186 	case MODULE_CMD_FINI:
    187 		sysctl_teardown(&securelevel_sysctl_log);
    188 		secmodel_securelevel_stop();
    189 		break;
    190 
    191 	case MODULE_CMD_AUTOUNLOAD:
    192 		error = EPERM;
    193 		break;
    194 
    195 	default:
    196 		error = ENOTTY;
    197 		break;
    198 	}
    199 
    200 	return (error);
    201 }
    202 
    203 /*
    204  * kauth(9) listener
    205  *
    206  * Security model: Traditional NetBSD
    207  * Scope: System
    208  * Responsibility: Securelevel
    209  */
    210 int
    211 secmodel_securelevel_system_cb(kauth_cred_t cred,
    212     kauth_action_t action, void *cookie, void *arg0, void *arg1,
    213     void *arg2, void *arg3)
    214 {
    215 	int result;
    216 	enum kauth_system_req req;
    217 
    218 	result = KAUTH_RESULT_DEFER;
    219 	req = (enum kauth_system_req)arg0;
    220 
    221 	switch (action) {
    222 	case KAUTH_SYSTEM_CHSYSFLAGS:
    223 		if (securelevel > 0)
    224 			result = KAUTH_RESULT_DENY;
    225 		break;
    226 
    227 	case KAUTH_SYSTEM_TIME:
    228 		switch (req) {
    229 		case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
    230 			if (securelevel > 0)
    231 				result = KAUTH_RESULT_DENY;
    232 			break;
    233 
    234 		case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
    235 			struct timespec *ts = arg1;
    236 			struct timespec *delta = arg2;
    237 
    238 			/*
    239 			 * Don't allow the time to be set forward so far it
    240 			 * will wrap and become negative, thus allowing an
    241 			 * attacker to bypass the next check below.  The
    242 			 * cutoff is 1 year before rollover occurs, so even
    243 			 * if the attacker uses adjtime(2) to move the time
    244 			 * past the cutoff, it will take a very long time
    245 			 * to get to the wrap point.
    246 			 */
    247 			if (securelevel > 1 &&
    248 			    ((ts->tv_sec > LLONG_MAX - 365*24*60*60) ||
    249 			     (delta->tv_sec < 0 || delta->tv_nsec < 0)))
    250 				result = KAUTH_RESULT_DENY;
    251 			break;
    252 		}
    253 
    254 		default:
    255 			break;
    256 		}
    257 		break;
    258 
    259 	case KAUTH_SYSTEM_MODULE:
    260 		if (securelevel > 0)
    261 			result = KAUTH_RESULT_DENY;
    262 		break;
    263 
    264 	case KAUTH_SYSTEM_MOUNT:
    265 		switch (req) {
    266 		case KAUTH_REQ_SYSTEM_MOUNT_NEW:
    267 			if (securelevel > 1)
    268 				result = KAUTH_RESULT_DENY;
    269 
    270 			break;
    271 
    272 		case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
    273 			if (securelevel > 1) {
    274 				struct mount *mp = arg1;
    275 				u_long flags = (u_long)arg2;
    276 
    277 				/* Can only degrade from read/write to read-only. */
    278 				if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD |
    279 				    MNT_FORCE | MNT_UPDATE))
    280 					result = KAUTH_RESULT_DENY;
    281 			}
    282 
    283 			break;
    284 
    285 		default:
    286 			break;
    287 		}
    288 
    289 		break;
    290 
    291 	case KAUTH_SYSTEM_SYSCTL:
    292 		switch (req) {
    293 		case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
    294 		case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
    295 		case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
    296 			if (securelevel > 0)
    297 				result = KAUTH_RESULT_DENY;
    298 			break;
    299 
    300 		default:
    301 			break;
    302 		}
    303 		break;
    304 
    305 	case KAUTH_SYSTEM_SETIDCORE:
    306 		if (securelevel > 0)
    307 			result = KAUTH_RESULT_DENY;
    308 		break;
    309 
    310 	case KAUTH_SYSTEM_DEBUG:
    311 		switch (req) {
    312 		case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
    313 			if (securelevel > 0)
    314 				result = KAUTH_RESULT_DENY;
    315 			break;
    316 
    317 		default:
    318 			break;
    319 		}
    320 		break;
    321 
    322 	default:
    323 		break;
    324 	}
    325 
    326 	return (result);
    327 }
    328 
    329 /*
    330  * kauth(9) listener
    331  *
    332  * Security model: Traditional NetBSD
    333  * Scope: Process
    334  * Responsibility: Securelevel
    335  */
    336 int
    337 secmodel_securelevel_process_cb(kauth_cred_t cred,
    338     kauth_action_t action, void *cookie, void *arg0,
    339     void *arg1, void *arg2, void *arg3)
    340 {
    341 	struct proc *p;
    342 	int result;
    343 
    344 	result = KAUTH_RESULT_DEFER;
    345 	p = arg0;
    346 
    347 	switch (action) {
    348 	case KAUTH_PROCESS_PROCFS: {
    349 		enum kauth_process_req req;
    350 
    351 		req = (enum kauth_process_req)arg2;
    352 		switch (req) {
    353 		case KAUTH_REQ_PROCESS_PROCFS_READ:
    354 			break;
    355 
    356 		case KAUTH_REQ_PROCESS_PROCFS_RW:
    357 		case KAUTH_REQ_PROCESS_PROCFS_WRITE:
    358 			if ((p == initproc) && (securelevel > -1))
    359 				result = KAUTH_RESULT_DENY;
    360 
    361 			break;
    362 
    363 		default:
    364 			break;
    365 		}
    366 
    367 		break;
    368 		}
    369 
    370 	case KAUTH_PROCESS_PTRACE:
    371 		if ((p == initproc) && (securelevel >= 0))
    372 			result = KAUTH_RESULT_DENY;
    373 
    374 		break;
    375 
    376 	case KAUTH_PROCESS_CORENAME:
    377 		if (securelevel > 1)
    378 			result = KAUTH_RESULT_DENY;
    379 		break;
    380 
    381 	default:
    382 		break;
    383 	}
    384 
    385 	return (result);
    386 }
    387 
    388 /*
    389  * kauth(9) listener
    390  *
    391  * Security model: Traditional NetBSD
    392  * Scope: Network
    393  * Responsibility: Securelevel
    394  */
    395 int
    396 secmodel_securelevel_network_cb(kauth_cred_t cred,
    397     kauth_action_t action, void *cookie, void *arg0,
    398     void *arg1, void *arg2, void *arg3)
    399 {
    400 	int result;
    401 	enum kauth_network_req req;
    402 
    403 	result = KAUTH_RESULT_DEFER;
    404 	req = (enum kauth_network_req)arg0;
    405 
    406 	switch (action) {
    407 	case KAUTH_NETWORK_FIREWALL:
    408 		switch (req) {
    409 		case KAUTH_REQ_NETWORK_FIREWALL_FW:
    410 		case KAUTH_REQ_NETWORK_FIREWALL_NAT:
    411 			if (securelevel > 1)
    412 				result = KAUTH_RESULT_DENY;
    413 			break;
    414 
    415 		default:
    416 			break;
    417 		}
    418 		break;
    419 
    420 	case KAUTH_NETWORK_FORWSRCRT:
    421 		if (securelevel > 0)
    422 			result = KAUTH_RESULT_DENY;
    423 		break;
    424 
    425 	default:
    426 		break;
    427 	}
    428 
    429 	return (result);
    430 }
    431 
    432 /*
    433  * kauth(9) listener
    434  *
    435  * Security model: Traditional NetBSD
    436  * Scope: Machdep
    437  * Responsibility: Securelevel
    438  */
    439 int
    440 secmodel_securelevel_machdep_cb(kauth_cred_t cred,
    441     kauth_action_t action, void *cookie, void *arg0,
    442     void *arg1, void *arg2, void *arg3)
    443 {
    444         int result;
    445 
    446         result = KAUTH_RESULT_DEFER;
    447 
    448         switch (action) {
    449 	case KAUTH_MACHDEP_IOPERM_SET:
    450 	case KAUTH_MACHDEP_IOPL:
    451 		if (securelevel > 0)
    452 			result = KAUTH_RESULT_DENY;
    453 		break;
    454 
    455 	case KAUTH_MACHDEP_UNMANAGEDMEM:
    456 		if (securelevel > 0)
    457 			result = KAUTH_RESULT_DENY;
    458 		break;
    459 
    460 	default:
    461 		break;
    462 	}
    463 
    464 	return (result);
    465 }
    466 
    467 /*
    468  * kauth(9) listener
    469  *
    470  * Security model: Traditional NetBSD
    471  * Scope: Device
    472  * Responsibility: Securelevel
    473  */
    474 int
    475 secmodel_securelevel_device_cb(kauth_cred_t cred,
    476     kauth_action_t action, void *cookie, void *arg0,
    477     void *arg1, void *arg2, void *arg3)
    478 {
    479 	int result;
    480 
    481 	result = KAUTH_RESULT_DEFER;
    482 
    483 	switch (action) {
    484 	case KAUTH_DEVICE_RAWIO_SPEC: {
    485 		struct vnode *vp, *bvp;
    486 		enum kauth_device_req req;
    487 		dev_t dev;
    488 		int d_type;
    489 
    490 		req = (enum kauth_device_req)arg0;
    491 		vp = arg1;
    492 
    493 		KASSERT(vp != NULL);
    494 
    495 		dev = vp->v_rdev;
    496 		d_type = D_OTHER;
    497 		bvp = NULL;
    498 
    499 		/* Handle /dev/mem and /dev/kmem. */
    500 		if ((vp->v_type == VCHR) && iskmemdev(dev)) {
    501 			switch (req) {
    502 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
    503 				break;
    504 
    505 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
    506 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
    507 				if (securelevel > 0)
    508 					result = KAUTH_RESULT_DENY;
    509 				break;
    510 
    511 			default:
    512 				break;
    513 			}
    514 
    515 			break;
    516 		}
    517 
    518 		switch (req) {
    519 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
    520 			break;
    521 
    522 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
    523 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
    524 			switch (vp->v_type) {
    525 			case VCHR: {
    526 				const struct cdevsw *cdev;
    527 
    528 				cdev = cdevsw_lookup(dev);
    529 				if (cdev != NULL) {
    530 					dev_t blkdev;
    531 
    532 					blkdev = devsw_chr2blk(dev);
    533 					if (blkdev != NODEV) {
    534 						vfinddev(blkdev, VBLK, &bvp);
    535 						if (bvp != NULL)
    536 							d_type = (cdev->d_flag
    537 							    & D_TYPEMASK);
    538 					}
    539 				}
    540 
    541 				break;
    542 				}
    543 			case VBLK: {
    544 				const struct bdevsw *bdev;
    545 
    546 				bdev = bdevsw_lookup(dev);
    547 				if (bdev != NULL)
    548 					d_type = (bdev->d_flag & D_TYPEMASK);
    549 
    550 				bvp = vp;
    551 
    552 				break;
    553 				}
    554 
    555 			default:
    556 				break;
    557 			}
    558 
    559 			if (d_type != D_DISK)
    560 				break;
    561 
    562 			/*
    563 			 * XXX: This is bogus. We should be failing the request
    564 			 * XXX: not only if this specific slice is mounted, but
    565 			 * XXX: if it's on a disk with any other mounted slice.
    566 			 */
    567 			if (vfs_mountedon(bvp) && (securelevel > 0))
    568 				break;
    569 
    570 			if (securelevel > 1)
    571 				result = KAUTH_RESULT_DENY;
    572 
    573 			break;
    574 
    575 		default:
    576 			break;
    577 		}
    578 
    579 		break;
    580 		}
    581 
    582 	case KAUTH_DEVICE_RAWIO_PASSTHRU:
    583 		if (securelevel > 0) {
    584 			u_long bits;
    585 
    586 			bits = (u_long)arg0;
    587 
    588 			KASSERT(bits != 0);
    589 			KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0);
    590 
    591 			if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
    592 				result = KAUTH_RESULT_DENY;
    593 		}
    594 
    595 		break;
    596 
    597 	case KAUTH_DEVICE_GPIO_PINSET:
    598 		if (securelevel > 0)
    599 			result = KAUTH_RESULT_DENY;
    600 		break;
    601 
    602 	default:
    603 		break;
    604 	}
    605 
    606 	return (result);
    607 }
    608 
    609 int
    610 secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action,
    611     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
    612 {
    613 	int result;
    614 
    615 	result = KAUTH_RESULT_DEFER;
    616 
    617 	if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) &&
    618 	    (action & KAUTH_VNODE_HAS_SYSFLAGS)) {
    619 		if (securelevel > 0)
    620 			result = KAUTH_RESULT_DENY;
    621 	}
    622 
    623 	return (result);
    624 }
    625 
    626