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