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