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