xref: /netbsd-src/sys/secmodel/securelevel/secmodel_securelevel.c (revision de4fa6c51a9708fc05f88b618fa6fad87c9508ec)
1 /* $NetBSD: secmodel_securelevel.c,v 1.13 2009/09/03 04:45:28 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.13 2009/09/03 04:45:28 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 
53 #include <miscfs/specfs/specdev.h>
54 
55 #include <secmodel/securelevel/securelevel.h>
56 
57 static int securelevel;
58 
59 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device,
60     l_vnode;
61 
62 /*
63  * sysctl helper routine for securelevel. ensures that the value
64  * only rises unless the caller has pid 1 (assumed to be init).
65  */
66 int
67 secmodel_securelevel_sysctl(SYSCTLFN_ARGS)
68 {
69 	int newsecurelevel, error;
70 	struct sysctlnode node;
71 
72 	newsecurelevel = securelevel;
73 	node = *rnode;
74 	node.sysctl_data = &newsecurelevel;
75 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
76 	if (error || newp == NULL)
77 		return (error);
78 
79 	if (newsecurelevel < securelevel && l && l->l_proc->p_pid != 1)
80 		return (EPERM);
81 
82 	securelevel = newsecurelevel;
83 
84 	return (error);
85 }
86 
87 void
88 secmodel_securelevel_init(void)
89 {
90 #ifdef INSECURE
91 	securelevel = -1;
92 #else
93 	securelevel = 0;
94 #endif /* INSECURE */
95 }
96 
97 SYSCTL_SETUP(sysctl_security_securelevel_setup,
98     "sysctl security securelevel setup")
99 {
100 	/*
101 	 * For compatibility, we create a kern.securelevel variable.
102 	 */
103 	sysctl_createv(clog, 0, NULL, NULL,
104 		       CTLFLAG_PERMANENT,
105 		       CTLTYPE_NODE, "kern", NULL,
106 		       NULL, 0, NULL, 0,
107 		       CTL_KERN, CTL_EOL);
108 
109 	sysctl_createv(clog, 0, NULL, NULL,
110 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
111 		       CTLTYPE_INT, "securelevel",
112 		       SYSCTL_DESCR("System security level"),
113 		       secmodel_securelevel_sysctl, 0, NULL, 0,
114 		       CTL_KERN, KERN_SECURELVL, CTL_EOL);
115 }
116 
117 void
118 secmodel_securelevel_start(void)
119 {
120 	l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
121 	    secmodel_securelevel_system_cb, NULL);
122 	l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
123 	    secmodel_securelevel_process_cb, NULL);
124 	l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
125 	    secmodel_securelevel_network_cb, NULL);
126 	l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
127 	    secmodel_securelevel_machdep_cb, NULL);
128 	l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
129 	    secmodel_securelevel_device_cb, NULL);
130 	l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
131 	    secmodel_securelevel_vnode_cb, NULL);
132 }
133 
134 #if defined(_LKM)
135 void
136 secmodel_securelevel_stop(void)
137 {
138 	kauth_unlisten_scope(l_system);
139 	kauth_unlisten_scope(l_process);
140 	kauth_unlisten_scope(l_network);
141 	kauth_unlisten_scope(l_machdep);
142 	kauth_unlisten_scope(l_device);
143 	kauth_unlisten_scope(l_vnode);
144 }
145 #endif /* _LKM */
146 
147 /*
148  * kauth(9) listener
149  *
150  * Security model: Traditional NetBSD
151  * Scope: System
152  * Responsibility: Securelevel
153  */
154 int
155 secmodel_securelevel_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 
162 	result = KAUTH_RESULT_DEFER;
163 	req = (enum kauth_system_req)arg0;
164 
165 	switch (action) {
166 	case KAUTH_SYSTEM_CHSYSFLAGS:
167 		if (securelevel > 0)
168 			result = KAUTH_RESULT_DENY;
169 		break;
170 
171 	case KAUTH_SYSTEM_TIME:
172 		switch (req) {
173 		case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
174 			if (securelevel > 0)
175 				result = KAUTH_RESULT_DENY;
176 			break;
177 
178 		case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
179 			struct timespec *ts = arg1;
180 			struct timespec *delta = arg2;
181 
182 			/*
183 			 * Don't allow the time to be set forward so far it
184 			 * will wrap and become negative, thus allowing an
185 			 * attacker to bypass the next check below.  The
186 			 * cutoff is 1 year before rollover occurs, so even
187 			 * if the attacker uses adjtime(2) to move the time
188 			 * past the cutoff, it will take a very long time
189 			 * to get to the wrap point.
190 			 */
191 			if (securelevel > 1 &&
192 			    ((ts->tv_sec > LLONG_MAX - 365*24*60*60) ||
193 			     (delta->tv_sec < 0 || delta->tv_nsec < 0)))
194 				result = KAUTH_RESULT_DENY;
195 			break;
196 		}
197 
198 		default:
199 			break;
200 		}
201 		break;
202 
203 	case KAUTH_SYSTEM_MODULE:
204 		if (securelevel > 0)
205 			result = KAUTH_RESULT_DENY;
206 		break;
207 
208 	case KAUTH_SYSTEM_MOUNT:
209 		switch (req) {
210 		case KAUTH_REQ_SYSTEM_MOUNT_NEW:
211 			if (securelevel > 1)
212 				result = KAUTH_RESULT_DENY;
213 
214 			break;
215 
216 		case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
217 			if (securelevel > 1) {
218 				struct mount *mp = arg1;
219 				u_long flags = (u_long)arg2;
220 
221 				/* Can only degrade from read/write to read-only. */
222 				if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD |
223 				    MNT_FORCE | MNT_UPDATE))
224 					result = KAUTH_RESULT_DENY;
225 			}
226 
227 			break;
228 
229 		default:
230 			break;
231 		}
232 
233 		break;
234 
235 	case KAUTH_SYSTEM_SYSCTL:
236 		switch (req) {
237 		case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
238 		case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
239 		case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
240 			if (securelevel > 0)
241 				result = KAUTH_RESULT_DENY;
242 			break;
243 
244 		default:
245 			break;
246 		}
247 		break;
248 
249 	case KAUTH_SYSTEM_SETIDCORE:
250 		if (securelevel > 0)
251 			result = KAUTH_RESULT_DENY;
252 		break;
253 
254 	case KAUTH_SYSTEM_DEBUG:
255 		switch (req) {
256 		case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
257 			if (securelevel > 0)
258 				result = KAUTH_RESULT_DENY;
259 			break;
260 
261 		default:
262 			break;
263 		}
264 		break;
265 
266 	default:
267 		break;
268 	}
269 
270 	return (result);
271 }
272 
273 /*
274  * kauth(9) listener
275  *
276  * Security model: Traditional NetBSD
277  * Scope: Process
278  * Responsibility: Securelevel
279  */
280 int
281 secmodel_securelevel_process_cb(kauth_cred_t cred,
282     kauth_action_t action, void *cookie, void *arg0,
283     void *arg1, void *arg2, void *arg3)
284 {
285 	struct proc *p;
286 	int result;
287 
288 	result = KAUTH_RESULT_DEFER;
289 	p = arg0;
290 
291 	switch (action) {
292 	case KAUTH_PROCESS_PROCFS: {
293 		enum kauth_process_req req;
294 
295 		req = (enum kauth_process_req)arg2;
296 		switch (req) {
297 		case KAUTH_REQ_PROCESS_PROCFS_READ:
298 			break;
299 
300 		case KAUTH_REQ_PROCESS_PROCFS_RW:
301 		case KAUTH_REQ_PROCESS_PROCFS_WRITE:
302 			if ((p == initproc) && (securelevel > -1))
303 				result = KAUTH_RESULT_DENY;
304 
305 			break;
306 
307 		default:
308 			break;
309 		}
310 
311 		break;
312 		}
313 
314 	case KAUTH_PROCESS_PTRACE:
315 		if ((p == initproc) && (securelevel >= 0))
316 			result = KAUTH_RESULT_DENY;
317 
318 		break;
319 
320 	case KAUTH_PROCESS_CORENAME:
321 		if (securelevel > 1)
322 			result = KAUTH_RESULT_DENY;
323 		break;
324 
325 	default:
326 		break;
327 	}
328 
329 	return (result);
330 }
331 
332 /*
333  * kauth(9) listener
334  *
335  * Security model: Traditional NetBSD
336  * Scope: Network
337  * Responsibility: Securelevel
338  */
339 int
340 secmodel_securelevel_network_cb(kauth_cred_t cred,
341     kauth_action_t action, void *cookie, void *arg0,
342     void *arg1, void *arg2, void *arg3)
343 {
344 	int result;
345 	enum kauth_network_req req;
346 
347 	result = KAUTH_RESULT_DEFER;
348 	req = (enum kauth_network_req)arg0;
349 
350 	switch (action) {
351 	case KAUTH_NETWORK_FIREWALL:
352 		switch (req) {
353 		case KAUTH_REQ_NETWORK_FIREWALL_FW:
354 		case KAUTH_REQ_NETWORK_FIREWALL_NAT:
355 			if (securelevel > 1)
356 				result = KAUTH_RESULT_DENY;
357 			break;
358 
359 		default:
360 			break;
361 		}
362 		break;
363 
364 	case KAUTH_NETWORK_FORWSRCRT:
365 		if (securelevel > 0)
366 			result = KAUTH_RESULT_DENY;
367 		break;
368 
369 	default:
370 		break;
371 	}
372 
373 	return (result);
374 }
375 
376 /*
377  * kauth(9) listener
378  *
379  * Security model: Traditional NetBSD
380  * Scope: Machdep
381  * Responsibility: Securelevel
382  */
383 int
384 secmodel_securelevel_machdep_cb(kauth_cred_t cred,
385     kauth_action_t action, void *cookie, void *arg0,
386     void *arg1, void *arg2, void *arg3)
387 {
388         int result;
389 
390         result = KAUTH_RESULT_DEFER;
391 
392         switch (action) {
393 	case KAUTH_MACHDEP_IOPERM_SET:
394 	case KAUTH_MACHDEP_IOPL:
395 		if (securelevel > 0)
396 			result = KAUTH_RESULT_DENY;
397 		break;
398 
399 	case KAUTH_MACHDEP_UNMANAGEDMEM:
400 		if (securelevel > 0)
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: Device
416  * Responsibility: Securelevel
417  */
418 int
419 secmodel_securelevel_device_cb(kauth_cred_t cred,
420     kauth_action_t action, void *cookie, void *arg0,
421     void *arg1, void *arg2, void *arg3)
422 {
423 	int result;
424 
425 	result = KAUTH_RESULT_DEFER;
426 
427 	switch (action) {
428 	case KAUTH_DEVICE_RAWIO_SPEC: {
429 		struct vnode *vp, *bvp;
430 		enum kauth_device_req req;
431 		dev_t dev;
432 		int d_type;
433 
434 		req = (enum kauth_device_req)arg0;
435 		vp = arg1;
436 
437 		KASSERT(vp != NULL);
438 
439 		dev = vp->v_rdev;
440 		d_type = D_OTHER;
441 		bvp = NULL;
442 
443 		/* Handle /dev/mem and /dev/kmem. */
444 		if ((vp->v_type == VCHR) && iskmemdev(dev)) {
445 			switch (req) {
446 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
447 				break;
448 
449 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
450 			case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
451 				if (securelevel > 0)
452 					result = KAUTH_RESULT_DENY;
453 				break;
454 
455 			default:
456 				break;
457 			}
458 
459 			break;
460 		}
461 
462 		switch (req) {
463 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
464 			break;
465 
466 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
467 		case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
468 			switch (vp->v_type) {
469 			case VCHR: {
470 				const struct cdevsw *cdev;
471 
472 				cdev = cdevsw_lookup(dev);
473 				if (cdev != NULL) {
474 					dev_t blkdev;
475 
476 					blkdev = devsw_chr2blk(dev);
477 					if (blkdev != NODEV) {
478 						vfinddev(blkdev, VBLK, &bvp);
479 						if (bvp != NULL)
480 							d_type = (cdev->d_flag
481 							    & D_TYPEMASK);
482 					}
483 				}
484 
485 				break;
486 				}
487 			case VBLK: {
488 				const struct bdevsw *bdev;
489 
490 				bdev = bdevsw_lookup(dev);
491 				if (bdev != NULL)
492 					d_type = (bdev->d_flag & D_TYPEMASK);
493 
494 				bvp = vp;
495 
496 				break;
497 				}
498 
499 			default:
500 				break;
501 			}
502 
503 			if (d_type != D_DISK)
504 				break;
505 
506 			/*
507 			 * XXX: This is bogus. We should be failing the request
508 			 * XXX: not only if this specific slice is mounted, but
509 			 * XXX: if it's on a disk with any other mounted slice.
510 			 */
511 			if (vfs_mountedon(bvp) && (securelevel > 0))
512 				break;
513 
514 			if (securelevel > 1)
515 				result = KAUTH_RESULT_DENY;
516 
517 			break;
518 
519 		default:
520 			break;
521 		}
522 
523 		break;
524 		}
525 
526 	case KAUTH_DEVICE_RAWIO_PASSTHRU:
527 		if (securelevel > 0) {
528 			u_long bits;
529 
530 			bits = (u_long)arg0;
531 
532 			KASSERT(bits != 0);
533 			KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0);
534 
535 			if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
536 				result = KAUTH_RESULT_DENY;
537 		}
538 
539 		break;
540 
541 	case KAUTH_DEVICE_GPIO_PINSET:
542 		if (securelevel > 0)
543 			result = KAUTH_RESULT_DENY;
544 		break;
545 
546 	default:
547 		break;
548 	}
549 
550 	return (result);
551 }
552 
553 int
554 secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action,
555     void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
556 {
557 	int result;
558 
559 	result = KAUTH_RESULT_DEFER;
560 
561 	if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) &&
562 	    (action & KAUTH_VNODE_HAS_SYSFLAGS)) {
563 		if (securelevel > 0)
564 			result = KAUTH_RESULT_DENY;
565 	}
566 
567 	return (result);
568 }
569 
570