Home | History | Annotate | Line # | Download | only in keylock
      1 /* $NetBSD: secmodel_keylock.c,v 1.12 2021/12/07 21:45:31 andvar Exp $ */
      2 /*-
      3  * Copyright (c) 2009 Marc Balmer <marc (at) msys.ch>
      4  * Copyright (c) 2006 Elad Efrat <elad (at) 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 
     75 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
     76 
     77 static secmodel_t keylock_sm;
     78 
     79 SYSCTL_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 
    104 void
    105 secmodel_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 
    115 void
    116 secmodel_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 
    130 void
    131 secmodel_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  */
    154 int
    155 secmodel_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  */
    263 int
    264 secmodel_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  */
    323 int
    324 secmodel_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  */
    370 int
    371 secmodel_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  */
    408 int
    409 secmodel_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