xref: /netbsd-src/sys/secmodel/securelevel/secmodel_securelevel.c (revision b757af438b42b93f8c6571f026d8b8ef3eaf5fc9)
1 /* $NetBSD: secmodel_securelevel.c,v 1.27 2012/03/13 18:41:02 elad 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.27 2012/03/13 18:41:02 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 #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 		/* 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 		switch (req) {
347 		case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
348 			if (securelevel > 0)
349 				result = KAUTH_RESULT_DENY;
350 			break;
351 
352 		default:
353 			break;
354 		}
355 		break;
356 
357 	default:
358 		break;
359 	}
360 
361 	return (result);
362 }
363 
364 /*
365  * kauth(9) listener
366  *
367  * Security model: Traditional NetBSD
368  * Scope: Process
369  * Responsibility: Securelevel
370  */
371 int
372 secmodel_securelevel_process_cb(kauth_cred_t cred, kauth_action_t action,
373     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
374 {
375 	struct proc *p;
376 	int result;
377 
378 	result = KAUTH_RESULT_DEFER;
379 	p = arg0;
380 
381 	switch (action) {
382 	case KAUTH_PROCESS_PROCFS: {
383 		enum kauth_process_req req;
384 
385 		req = (enum kauth_process_req)arg2;
386 		switch (req) {
387 		case KAUTH_REQ_PROCESS_PROCFS_READ:
388 			break;
389 
390 		case KAUTH_REQ_PROCESS_PROCFS_RW:
391 		case KAUTH_REQ_PROCESS_PROCFS_WRITE:
392 			if ((p == initproc) && (securelevel > -1))
393 				result = KAUTH_RESULT_DENY;
394 
395 			break;
396 
397 		default:
398 			break;
399 		}
400 
401 		break;
402 		}
403 
404 	case KAUTH_PROCESS_PTRACE:
405 		if ((p == initproc) && (securelevel > -1))
406 			result = KAUTH_RESULT_DENY;
407 
408 		break;
409 
410 	case KAUTH_PROCESS_CORENAME:
411 		if (securelevel > 1)
412 			result = KAUTH_RESULT_DENY;
413 		break;
414 
415 	default:
416 		break;
417 	}
418 
419 	return (result);
420 }
421 
422 /*
423  * kauth(9) listener
424  *
425  * Security model: Traditional NetBSD
426  * Scope: Network
427  * Responsibility: Securelevel
428  */
429 int
430 secmodel_securelevel_network_cb(kauth_cred_t cred, kauth_action_t action,
431     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
432 {
433 	int result;
434 	enum kauth_network_req req;
435 
436 	result = KAUTH_RESULT_DEFER;
437 	req = (enum kauth_network_req)arg0;
438 
439 	switch (action) {
440 	case KAUTH_NETWORK_FIREWALL:
441 		switch (req) {
442 		case KAUTH_REQ_NETWORK_FIREWALL_FW:
443 		case KAUTH_REQ_NETWORK_FIREWALL_NAT:
444 			if (securelevel > 1)
445 				result = KAUTH_RESULT_DENY;
446 			break;
447 
448 		default:
449 			break;
450 		}
451 		break;
452 
453 	case KAUTH_NETWORK_FORWSRCRT:
454 		if (securelevel > 0)
455 			result = KAUTH_RESULT_DENY;
456 		break;
457 
458 	default:
459 		break;
460 	}
461 
462 	return (result);
463 }
464 
465 /*
466  * kauth(9) listener
467  *
468  * Security model: Traditional NetBSD
469  * Scope: Machdep
470  * Responsibility: Securelevel
471  */
472 int
473 secmodel_securelevel_machdep_cb(kauth_cred_t cred, kauth_action_t action,
474     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
475 {
476         int result;
477 
478         result = KAUTH_RESULT_DEFER;
479 
480         switch (action) {
481 	case KAUTH_MACHDEP_IOPERM_SET:
482 	case KAUTH_MACHDEP_IOPL:
483 		if (securelevel > 0)
484 			result = KAUTH_RESULT_DENY;
485 		break;
486 
487 	case KAUTH_MACHDEP_UNMANAGEDMEM:
488 		if (securelevel > 0)
489 			result = KAUTH_RESULT_DENY;
490 		break;
491 
492 	case KAUTH_MACHDEP_CPU_UCODE_APPLY:
493 		if (securelevel > 1)
494 			result = KAUTH_RESULT_DENY;
495 		break;
496 
497 	default:
498 		break;
499 	}
500 
501 	return (result);
502 }
503 
504 /*
505  * kauth(9) listener
506  *
507  * Security model: Traditional NetBSD
508  * Scope: Device
509  * Responsibility: Securelevel
510  */
511 int
512 secmodel_securelevel_device_cb(kauth_cred_t cred, kauth_action_t action,
513     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
514 {
515 	int result;
516 
517 	result = KAUTH_RESULT_DEFER;
518 
519 	switch (action) {
520 	case KAUTH_DEVICE_RAWIO_SPEC: {
521 		struct vnode *vp;
522 		enum kauth_device_req req;
523 
524 		req = (enum kauth_device_req)arg0;
525 		vp = arg1;
526 
527 		KASSERT(vp != NULL);
528 
529 		/* Handle /dev/mem and /dev/kmem. */
530 		if (iskmemvp(vp)) {
531 			switch (req) {
532 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
533 				break;
534 
535 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
536 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
537 				if (securelevel > 0)
538 					result = KAUTH_RESULT_DENY;
539 
540 				break;
541 
542 			default:
543 				break;
544 			}
545 
546 			break;
547 		}
548 
549 		switch (req) {
550 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
551 			break;
552 
553 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
554 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: {
555 			int error;
556 
557 			error = rawdev_mounted(vp, NULL);
558 
559 			/* Not a disk. */
560 			if (error == EINVAL)
561 				break;
562 
563 			if (error && securelevel > 0)
564 				result = KAUTH_RESULT_DENY;
565 
566 			if (securelevel > 1)
567 				result = KAUTH_RESULT_DENY;
568 
569 			break;
570 			}
571 
572 		default:
573 			break;
574 		}
575 
576 		break;
577 		}
578 
579 	case KAUTH_DEVICE_RAWIO_PASSTHRU:
580 		if (securelevel > 0) {
581 			u_long bits;
582 
583 			bits = (u_long)arg0;
584 
585 			KASSERT(bits != 0);
586 			KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0);
587 
588 			if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
589 				result = KAUTH_RESULT_DENY;
590 		}
591 
592 		break;
593 
594 	case KAUTH_DEVICE_GPIO_PINSET:
595 		if (securelevel > 0)
596 			result = KAUTH_RESULT_DENY;
597 		break;
598 
599 	case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE:
600 		if (securelevel > 0)
601 			result = KAUTH_RESULT_DENY;
602 		break;
603 
604 	default:
605 		break;
606 	}
607 
608 	return (result);
609 }
610 
611 int
612 secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action,
613     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
614 {
615 	int result;
616 
617 	result = KAUTH_RESULT_DEFER;
618 
619 	if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) &&
620 	    (action & KAUTH_VNODE_HAS_SYSFLAGS)) {
621 		if (securelevel > 0)
622 			result = KAUTH_RESULT_DENY;
623 	}
624 
625 	return (result);
626 }
627 
628