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