Annotation of src/sys/secmodel/securelevel/secmodel_securelevel.c, Revision 1.26.2.1
1.26.2.1! riz 1: /* $NetBSD: secmodel_securelevel.c,v 1.26 2012/01/17 10:47:27 cegger Exp $ */
1.1 elad 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
1.22 jym 31: * NetBSD securelevel.
1.1 elad 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>
1.26.2.1! riz 38: __KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.26 2012/01/17 10:47:27 cegger Exp $");
1.1 elad 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>
1.14 elad 52: #include <sys/module.h>
1.16 elad 53: #include <sys/timevar.h>
1.1 elad 54:
55: #include <miscfs/specfs/specdev.h>
56:
1.23 jym 57: #include <secmodel/secmodel.h>
1.1 elad 58: #include <secmodel/securelevel/securelevel.h>
59:
1.14 elad 60: MODULE(MODULE_CLASS_SECMODEL, securelevel, NULL);
61:
1.1 elad 62: static int securelevel;
63:
1.13 elad 64: static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device,
65: l_vnode;
1.1 elad 66:
1.23 jym 67: static secmodel_t securelevel_sm;
1.14 elad 68: static struct sysctllog *securelevel_sysctl_log;
69:
1.1 elad 70: /*
1.20 elad 71: * Sysctl helper routine for securelevel. Ensures that the value only rises
72: * unless the caller is init.
1.1 elad 73: */
74: int
75: secmodel_securelevel_sysctl(SYSCTLFN_ARGS)
1.22 jym 76: {
1.1 elad 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);
1.22 jym 86:
1.20 elad 87: if ((newsecurelevel < securelevel) && (l->l_proc != initproc))
1.1 elad 88: return (EPERM);
89:
90: securelevel = newsecurelevel;
91:
92: return (error);
93: }
94:
95: void
1.14 elad 96: sysctl_security_securelevel_setup(struct sysctllog **clog)
1.1 elad 97: {
1.26.2.1! riz 98: const struct sysctlnode *rnode, *rnode2;
1.14 elad 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:
1.26.2.1! riz 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:
1.14 elad 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,
1.23 jym 137: NULL, 0, __UNCONST(SECMODEL_SECURELEVEL_NAME), 0,
1.14 elad 138: CTL_CREATE, CTL_EOL);
1.1 elad 139:
1.15 elad 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:
1.14 elad 147: /* Compatibility: kern.securelevel */
1.1 elad 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
1.14 elad 163: secmodel_securelevel_init(void)
164: {
165: #ifdef INSECURE
166: securelevel = -1;
167: #else
168: securelevel = 0;
169: #endif /* INSECURE */
170: }
171:
172: void
1.1 elad 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);
1.13 elad 185: l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
186: secmodel_securelevel_vnode_cb, NULL);
1.1 elad 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);
1.13 elad 197: kauth_unlisten_scope(l_vnode);
1.1 elad 198: }
1.14 elad 199:
200: static int
1.23 jym 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
1.14 elad 218: securelevel_modcmd(modcmd_t cmd, void *arg)
219: {
220: int error = 0;
221:
222: switch (cmd) {
223: case MODULE_CMD_INIT:
1.24 jym 224: secmodel_securelevel_init();
1.23 jym 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:
1.14 elad 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();
1.23 jym 239:
240: error = secmodel_deregister(securelevel_sm);
241: if (error != 0)
242: printf("securelevel_modcmd::fini: secmodel_deregister "
243: "returned %d\n", error);
244:
1.14 elad 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: }
1.1 elad 258:
259: /*
260: * kauth(9) listener
261: *
262: * Security model: Traditional NetBSD
263: * Scope: System
264: * Responsibility: Securelevel
265: */
266: int
1.18 elad 267: secmodel_securelevel_system_cb(kauth_cred_t cred, kauth_action_t action,
268: void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
1.1 elad 269: {
270: int result;
271: enum kauth_system_req req;
272:
1.2 elad 273: result = KAUTH_RESULT_DEFER;
1.1 elad 274: req = (enum kauth_system_req)arg0;
275:
276: switch (action) {
277: case KAUTH_SYSTEM_CHSYSFLAGS:
1.2 elad 278: if (securelevel > 0)
279: result = KAUTH_RESULT_DENY;
1.1 elad 280: break;
281:
282: case KAUTH_SYSTEM_TIME:
283: switch (req) {
284: case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
1.2 elad 285: if (securelevel > 0)
286: result = KAUTH_RESULT_DENY;
1.1 elad 287: break;
288:
1.3 elad 289: case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
290: struct timespec *ts = arg1;
1.10 christos 291: struct timespec *delta = arg2;
1.3 elad 292:
1.16 elad 293: if (securelevel > 1 && time_wraps(ts, delta))
1.3 elad 294: result = KAUTH_RESULT_DENY;
1.16 elad 295:
1.3 elad 296: break;
297: }
298:
1.1 elad 299: default:
300: break;
301: }
302: break;
303:
1.7 ad 304: case KAUTH_SYSTEM_MODULE:
1.2 elad 305: if (securelevel > 0)
306: result = KAUTH_RESULT_DENY;
1.1 elad 307: break;
308:
309: case KAUTH_SYSTEM_MOUNT:
310: switch (req) {
311: case KAUTH_REQ_SYSTEM_MOUNT_NEW:
312: if (securelevel > 1)
1.2 elad 313: result = KAUTH_RESULT_DENY;
1.1 elad 314:
315: break;
316:
317: case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
318: if (securelevel > 1) {
319: struct mount *mp = arg1;
320: u_long flags = (u_long)arg2;
321:
322: /* Can only degrade from read/write to read-only. */
323: if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD |
324: MNT_FORCE | MNT_UPDATE))
1.2 elad 325: result = KAUTH_RESULT_DENY;
1.1 elad 326: }
327:
328: break;
329:
330: default:
331: break;
332: }
333:
334: break;
335:
336: case KAUTH_SYSTEM_SYSCTL:
337: switch (req) {
338: case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
339: case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
340: case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
1.2 elad 341: if (securelevel > 0)
342: result = KAUTH_RESULT_DENY;
1.1 elad 343: break;
344:
345: default:
346: break;
347: }
348: break;
349:
350: case KAUTH_SYSTEM_SETIDCORE:
1.2 elad 351: if (securelevel > 0)
352: result = KAUTH_RESULT_DENY;
1.1 elad 353: break;
354:
355: case KAUTH_SYSTEM_DEBUG:
356: switch (req) {
357: case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
1.2 elad 358: if (securelevel > 0)
359: result = KAUTH_RESULT_DENY;
1.1 elad 360: break;
361:
362: default:
363: break;
364: }
365: break;
1.11 elad 366:
367: default:
368: break;
1.1 elad 369: }
370:
371: return (result);
372: }
373:
374: /*
375: * kauth(9) listener
376: *
377: * Security model: Traditional NetBSD
378: * Scope: Process
379: * Responsibility: Securelevel
380: */
381: int
1.18 elad 382: secmodel_securelevel_process_cb(kauth_cred_t cred, kauth_action_t action,
383: void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
1.1 elad 384: {
385: struct proc *p;
386: int result;
387:
1.2 elad 388: result = KAUTH_RESULT_DEFER;
1.1 elad 389: p = arg0;
390:
391: switch (action) {
1.8 elad 392: case KAUTH_PROCESS_PROCFS: {
1.1 elad 393: enum kauth_process_req req;
394:
395: req = (enum kauth_process_req)arg2;
396: switch (req) {
1.8 elad 397: case KAUTH_REQ_PROCESS_PROCFS_READ:
1.1 elad 398: break;
399:
1.8 elad 400: case KAUTH_REQ_PROCESS_PROCFS_RW:
401: case KAUTH_REQ_PROCESS_PROCFS_WRITE:
1.1 elad 402: if ((p == initproc) && (securelevel > -1))
403: result = KAUTH_RESULT_DENY;
404:
405: break;
1.2 elad 406:
1.1 elad 407: default:
408: break;
409: }
410:
411: break;
412: }
413:
1.8 elad 414: case KAUTH_PROCESS_PTRACE:
1.19 elad 415: if ((p == initproc) && (securelevel > -1))
1.1 elad 416: result = KAUTH_RESULT_DENY;
417:
418: break;
419:
420: case KAUTH_PROCESS_CORENAME:
1.2 elad 421: if (securelevel > 1)
422: result = KAUTH_RESULT_DENY;
1.1 elad 423: break;
1.11 elad 424:
425: default:
426: break;
1.1 elad 427: }
428:
429: return (result);
430: }
431:
432: /*
433: * kauth(9) listener
434: *
435: * Security model: Traditional NetBSD
436: * Scope: Network
437: * Responsibility: Securelevel
438: */
439: int
1.18 elad 440: secmodel_securelevel_network_cb(kauth_cred_t cred, kauth_action_t action,
441: void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
1.1 elad 442: {
443: int result;
444: enum kauth_network_req req;
445:
1.2 elad 446: result = KAUTH_RESULT_DEFER;
1.1 elad 447: req = (enum kauth_network_req)arg0;
448:
449: switch (action) {
450: case KAUTH_NETWORK_FIREWALL:
451: switch (req) {
452: case KAUTH_REQ_NETWORK_FIREWALL_FW:
453: case KAUTH_REQ_NETWORK_FIREWALL_NAT:
1.2 elad 454: if (securelevel > 1)
455: result = KAUTH_RESULT_DENY;
1.1 elad 456: break;
457:
458: default:
459: break;
460: }
461: break;
462:
463: case KAUTH_NETWORK_FORWSRCRT:
1.2 elad 464: if (securelevel > 0)
465: result = KAUTH_RESULT_DENY;
1.1 elad 466: break;
1.11 elad 467:
468: default:
469: break;
1.1 elad 470: }
471:
472: return (result);
473: }
474:
1.22 jym 475: /*
1.1 elad 476: * kauth(9) listener
477: *
478: * Security model: Traditional NetBSD
479: * Scope: Machdep
480: * Responsibility: Securelevel
481: */
482: int
1.18 elad 483: secmodel_securelevel_machdep_cb(kauth_cred_t cred, kauth_action_t action,
484: void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
1.1 elad 485: {
486: int result;
487:
1.2 elad 488: result = KAUTH_RESULT_DEFER;
1.1 elad 489:
490: switch (action) {
491: case KAUTH_MACHDEP_IOPERM_SET:
492: case KAUTH_MACHDEP_IOPL:
1.2 elad 493: if (securelevel > 0)
494: result = KAUTH_RESULT_DENY;
1.1 elad 495: break;
496:
497: case KAUTH_MACHDEP_UNMANAGEDMEM:
1.2 elad 498: if (securelevel > 0)
499: result = KAUTH_RESULT_DENY;
1.1 elad 500: break;
1.11 elad 501:
1.25 cegger 502: case KAUTH_MACHDEP_CPU_UCODE_APPLY:
1.26 cegger 503: if (securelevel > 1)
504: result = KAUTH_RESULT_DENY;
1.25 cegger 505: break;
506:
1.11 elad 507: default:
508: break;
1.1 elad 509: }
510:
511: return (result);
512: }
513:
514: /*
515: * kauth(9) listener
516: *
517: * Security model: Traditional NetBSD
1.22 jym 518: * Scope: Device
1.1 elad 519: * Responsibility: Securelevel
520: */
521: int
1.18 elad 522: secmodel_securelevel_device_cb(kauth_cred_t cred, kauth_action_t action,
523: void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
1.1 elad 524: {
525: int result;
526:
1.2 elad 527: result = KAUTH_RESULT_DEFER;
1.1 elad 528:
529: switch (action) {
530: case KAUTH_DEVICE_RAWIO_SPEC: {
1.17 elad 531: struct vnode *vp;
1.1 elad 532: enum kauth_device_req req;
533:
534: req = (enum kauth_device_req)arg0;
535: vp = arg1;
536:
537: KASSERT(vp != NULL);
538:
539: /* Handle /dev/mem and /dev/kmem. */
1.17 elad 540: if (iskmemvp(vp)) {
1.1 elad 541: switch (req) {
542: case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
543: break;
544:
545: case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
546: case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
1.2 elad 547: if (securelevel > 0)
548: result = KAUTH_RESULT_DENY;
1.17 elad 549:
1.1 elad 550: break;
1.11 elad 551:
552: default:
553: break;
1.1 elad 554: }
555:
556: break;
557: }
558:
559: switch (req) {
560: case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
561: break;
562:
563: case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
1.17 elad 564: case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: {
565: int error;
1.1 elad 566:
1.17 elad 567: error = rawdev_mounted(vp, NULL);
1.1 elad 568:
1.17 elad 569: /* Not a disk. */
570: if (error == EINVAL)
1.1 elad 571: break;
1.2 elad 572:
1.17 elad 573: if (error && securelevel > 0)
574: result = KAUTH_RESULT_DENY;
1.1 elad 575:
1.2 elad 576: if (securelevel > 1)
577: result = KAUTH_RESULT_DENY;
1.1 elad 578:
579: break;
1.17 elad 580: }
1.11 elad 581:
582: default:
583: break;
1.1 elad 584: }
585:
586: break;
587: }
588:
1.2 elad 589: case KAUTH_DEVICE_RAWIO_PASSTHRU:
1.1 elad 590: if (securelevel > 0) {
591: u_long bits;
592:
593: bits = (u_long)arg0;
594:
595: KASSERT(bits != 0);
596: KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0);
597:
598: if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
599: result = KAUTH_RESULT_DENY;
600: }
601:
602: break;
1.11 elad 603:
1.12 mbalmer 604: case KAUTH_DEVICE_GPIO_PINSET:
605: if (securelevel > 0)
606: result = KAUTH_RESULT_DENY;
607: break;
608:
1.21 tls 609: case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE:
610: if (securelevel > 0)
611: result = KAUTH_RESULT_DENY;
612: break;
613:
1.11 elad 614: default:
615: break;
1.1 elad 616: }
617:
618: return (result);
619: }
1.13 elad 620:
621: int
622: secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action,
623: void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
624: {
625: int result;
626:
627: result = KAUTH_RESULT_DEFER;
628:
629: if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) &&
630: (action & KAUTH_VNODE_HAS_SYSFLAGS)) {
631: if (securelevel > 0)
632: result = KAUTH_RESULT_DENY;
633: }
634:
635: return (result);
636: }
637:
CVSweb <webmaster@jp.NetBSD.org>