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