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