secmodel_securelevel.c revision 1.27 1 /* $NetBSD: secmodel_securelevel.c,v 1.27 2012/03/13 18:41:02 elad Exp $ */
2 /*-
3 * Copyright (c) 2006 Elad Efrat <elad (at) 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