1 /* $NetBSD: secmodel_securelevel.c,v 1.37 2020/12/05 17:33:53 thorpej 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.37 2020/12/05 17:33:53 thorpej 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/secmodel.h>
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 secmodel_t securelevel_sm;
67
68 /*
69 * Sysctl helper routine for securelevel. Ensures that the value only rises
70 * unless the caller is init.
71 */
72 int
secmodel_securelevel_sysctl(SYSCTLFN_ARGS)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 SYSCTL_SETUP(sysctl_security_securelevel_setup, "securelevel sysctl")
94 {
95 const struct sysctlnode *rnode, *rnode2;
96
97 sysctl_createv(clog, 0, NULL, &rnode,
98 CTLFLAG_PERMANENT,
99 CTLTYPE_NODE, "models", NULL,
100 NULL, 0, NULL, 0,
101 CTL_SECURITY, CTL_CREATE, CTL_EOL);
102
103 /* Compatibility: security.models.bsd44 */
104 rnode2 = rnode;
105 sysctl_createv(clog, 0, &rnode2, &rnode2,
106 CTLFLAG_PERMANENT,
107 CTLTYPE_NODE, "bsd44", NULL,
108 NULL, 0, NULL, 0,
109 CTL_CREATE, CTL_EOL);
110
111 /* Compatibility: security.models.bsd44.securelevel */
112 sysctl_createv(clog, 0, &rnode2, NULL,
113 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
114 CTLTYPE_INT, "securelevel",
115 SYSCTL_DESCR("System security level"),
116 secmodel_securelevel_sysctl, 0, NULL, 0,
117 CTL_CREATE, CTL_EOL);
118
119 sysctl_createv(clog, 0, &rnode, &rnode,
120 CTLFLAG_PERMANENT,
121 CTLTYPE_NODE, "securelevel", NULL,
122 NULL, 0, NULL, 0,
123 CTL_CREATE, CTL_EOL);
124
125 sysctl_createv(clog, 0, &rnode, NULL,
126 CTLFLAG_PERMANENT,
127 CTLTYPE_STRING, "name", NULL,
128 NULL, 0, __UNCONST(SECMODEL_SECURELEVEL_NAME), 0,
129 CTL_CREATE, CTL_EOL);
130
131 sysctl_createv(clog, 0, &rnode, NULL,
132 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
133 CTLTYPE_INT, "securelevel",
134 SYSCTL_DESCR("System security level"),
135 secmodel_securelevel_sysctl, 0, NULL, 0,
136 CTL_CREATE, CTL_EOL);
137
138 /* Compatibility: kern.securelevel */
139
140 sysctl_createv(clog, 0, NULL, 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_KERN, KERN_SECURELVL, CTL_EOL);
146 }
147
148 void
secmodel_securelevel_init(void)149 secmodel_securelevel_init(void)
150 {
151 #ifdef INSECURE
152 securelevel = -1;
153 #else
154 securelevel = 0;
155 #endif /* INSECURE */
156 }
157
158 void
secmodel_securelevel_start(void)159 secmodel_securelevel_start(void)
160 {
161 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
162 secmodel_securelevel_system_cb, NULL);
163 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
164 secmodel_securelevel_process_cb, NULL);
165 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
166 secmodel_securelevel_network_cb, NULL);
167 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
168 secmodel_securelevel_machdep_cb, NULL);
169 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
170 secmodel_securelevel_device_cb, NULL);
171 l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE,
172 secmodel_securelevel_vnode_cb, NULL);
173 }
174
175 void
secmodel_securelevel_stop(void)176 secmodel_securelevel_stop(void)
177 {
178 kauth_unlisten_scope(l_system);
179 kauth_unlisten_scope(l_process);
180 kauth_unlisten_scope(l_network);
181 kauth_unlisten_scope(l_machdep);
182 kauth_unlisten_scope(l_device);
183 kauth_unlisten_scope(l_vnode);
184 }
185
186 static int
securelevel_eval(const char * what,void * arg,void * ret)187 securelevel_eval(const char *what, void *arg, void *ret)
188 {
189 int error = 0;
190
191 if (strcasecmp(what, "is-securelevel-above") == 0) {
192 int level = (int)(uintptr_t)arg;
193 bool *bp = ret;
194
195 *bp = (securelevel > level);
196 } else {
197 error = ENOENT;
198 }
199
200 return error;
201 }
202
203 static int
securelevel_modcmd(modcmd_t cmd,void * arg)204 securelevel_modcmd(modcmd_t cmd, void *arg)
205 {
206 int error = 0;
207
208 switch (cmd) {
209 case MODULE_CMD_INIT:
210 secmodel_securelevel_init();
211 error = secmodel_register(&securelevel_sm,
212 SECMODEL_SECURELEVEL_ID, SECMODEL_SECURELEVEL_NAME,
213 NULL, securelevel_eval, NULL);
214 if (error != 0)
215 printf("securelevel_modcmd::init: secmodel_register "
216 "returned %d\n", error);
217
218 secmodel_securelevel_start();
219 break;
220
221 case MODULE_CMD_FINI:
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
secmodel_securelevel_system_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)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)(uintptr_t)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 default:
347 break;
348 }
349
350 return (result);
351 }
352
353 /*
354 * kauth(9) listener
355 *
356 * Security model: Traditional NetBSD
357 * Scope: Process
358 * Responsibility: Securelevel
359 */
360 int
secmodel_securelevel_process_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)361 secmodel_securelevel_process_cb(kauth_cred_t cred, kauth_action_t action,
362 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
363 {
364 struct proc *p;
365 int result;
366
367 result = KAUTH_RESULT_DEFER;
368 p = arg0;
369
370 switch (action) {
371 case KAUTH_PROCESS_PROCFS: {
372 enum kauth_process_req req;
373
374 req = (enum kauth_process_req)(uintptr_t)arg2;
375 switch (req) {
376 case KAUTH_REQ_PROCESS_PROCFS_READ:
377 break;
378
379 case KAUTH_REQ_PROCESS_PROCFS_RW:
380 case KAUTH_REQ_PROCESS_PROCFS_WRITE:
381 if ((p == initproc) && (securelevel > -1))
382 result = KAUTH_RESULT_DENY;
383
384 break;
385
386 default:
387 break;
388 }
389
390 break;
391 }
392
393 case KAUTH_PROCESS_PTRACE:
394 if ((p == initproc) && (securelevel > -1))
395 result = KAUTH_RESULT_DENY;
396
397 break;
398
399 case KAUTH_PROCESS_CORENAME:
400 if (securelevel > 1)
401 result = KAUTH_RESULT_DENY;
402 break;
403
404 default:
405 break;
406 }
407
408 return (result);
409 }
410
411 /*
412 * kauth(9) listener
413 *
414 * Security model: Traditional NetBSD
415 * Scope: Network
416 * Responsibility: Securelevel
417 */
418 int
secmodel_securelevel_network_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)419 secmodel_securelevel_network_cb(kauth_cred_t cred, kauth_action_t action,
420 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
421 {
422 int result;
423 enum kauth_network_req req;
424
425 result = KAUTH_RESULT_DEFER;
426 req = (enum kauth_network_req)(uintptr_t)arg0;
427
428 switch (action) {
429 case KAUTH_NETWORK_FIREWALL:
430 switch (req) {
431 case KAUTH_REQ_NETWORK_FIREWALL_FW:
432 case KAUTH_REQ_NETWORK_FIREWALL_NAT:
433 if (securelevel > 1)
434 result = KAUTH_RESULT_DENY;
435 break;
436
437 default:
438 break;
439 }
440 break;
441
442 case KAUTH_NETWORK_FORWSRCRT:
443 if (securelevel > 0)
444 result = KAUTH_RESULT_DENY;
445 break;
446
447 default:
448 break;
449 }
450
451 return (result);
452 }
453
454 /*
455 * kauth(9) listener
456 *
457 * Security model: Traditional NetBSD
458 * Scope: Machdep
459 * Responsibility: Securelevel
460 */
461 int
secmodel_securelevel_machdep_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)462 secmodel_securelevel_machdep_cb(kauth_cred_t cred, kauth_action_t action,
463 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
464 {
465 int result;
466
467 result = KAUTH_RESULT_DEFER;
468
469 switch (action) {
470 case KAUTH_MACHDEP_IOPERM_SET:
471 case KAUTH_MACHDEP_IOPL:
472 if (securelevel > 0)
473 result = KAUTH_RESULT_DENY;
474 break;
475
476 case KAUTH_MACHDEP_UNMANAGEDMEM:
477 if (securelevel > 0)
478 result = KAUTH_RESULT_DENY;
479 break;
480
481 case KAUTH_MACHDEP_SVS_DISABLE:
482 /* Deprecated. */
483 if (securelevel > 0)
484 result = KAUTH_RESULT_DENY;
485 break;
486
487 case KAUTH_MACHDEP_CPU_UCODE_APPLY:
488 if (securelevel > 1)
489 result = KAUTH_RESULT_DENY;
490 break;
491
492 default:
493 break;
494 }
495
496 return (result);
497 }
498
499 /*
500 * kauth(9) listener
501 *
502 * Security model: Traditional NetBSD
503 * Scope: Device
504 * Responsibility: Securelevel
505 */
506 int
secmodel_securelevel_device_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)507 secmodel_securelevel_device_cb(kauth_cred_t cred, kauth_action_t action,
508 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
509 {
510 int result;
511
512 result = KAUTH_RESULT_DEFER;
513
514 switch (action) {
515 case KAUTH_DEVICE_RAWIO_SPEC: {
516 struct vnode *vp;
517 enum kauth_device_req req;
518
519 req = (enum kauth_device_req)(uintptr_t)arg0;
520 vp = arg1;
521
522 KASSERT(vp != NULL);
523
524 /* Handle /dev/mem and /dev/kmem. */
525 if (iskmemvp(vp)) {
526 switch (req) {
527 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
528 break;
529
530 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
531 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
532 if (securelevel > 0)
533 result = KAUTH_RESULT_DENY;
534
535 break;
536
537 default:
538 break;
539 }
540
541 break;
542 }
543
544 switch (req) {
545 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
546 break;
547
548 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
549 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: {
550 int error;
551
552 error = rawdev_mounted(vp, NULL);
553
554 /* Not a disk. */
555 if (error == EINVAL)
556 break;
557
558 if (error && securelevel > 0)
559 result = KAUTH_RESULT_DENY;
560
561 if (securelevel > 1)
562 result = KAUTH_RESULT_DENY;
563
564 break;
565 }
566
567 default:
568 break;
569 }
570
571 break;
572 }
573
574 case KAUTH_DEVICE_RAWIO_PASSTHRU:
575 if (securelevel > 0) {
576 u_long bits;
577
578 bits = (u_long)arg0;
579
580 KASSERT(bits != 0);
581 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0);
582
583 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
584 result = KAUTH_RESULT_DENY;
585 }
586
587 break;
588
589 case KAUTH_DEVICE_GPIO_PINSET:
590 if (securelevel > 0)
591 result = KAUTH_RESULT_DENY;
592 break;
593
594 case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE:
595 if (securelevel > 1)
596 result = KAUTH_RESULT_DENY;
597 break;
598
599 default:
600 break;
601 }
602
603 return (result);
604 }
605
606 int
secmodel_securelevel_vnode_cb(kauth_cred_t cred,kauth_action_t action,void * cookie,void * arg0,void * arg1,void * arg2,void * arg3)607 secmodel_securelevel_vnode_cb(kauth_cred_t cred, kauth_action_t action,
608 void *cookie, void *arg0, void *arg1, void *arg2, void *arg3)
609 {
610 int result;
611
612 result = KAUTH_RESULT_DEFER;
613
614 if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) &&
615 (action & KAUTH_VNODE_HAS_SYSFLAGS)) {
616 if (securelevel > 0)
617 result = KAUTH_RESULT_DENY;
618 }
619
620 return (result);
621 }
622
623