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