secmodel_keylock.c revision 1.2 1 /* $NetBSD: secmodel_keylock.c,v 1.2 2009/08/15 09:43:59 mbalmer Exp $ */
2 /*-
3 * Copyright (c) 2009 Marc Balmer <marc (at) msys.ch>
4 * Copyright (c) 2006 Elad Efrat <elad (at) NetBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * This file contains kauth(9) listeners needed to implement an experimental
32 * keylock based security scheme.
33 *
34 * The position of the keylock is a system-global indication on what
35 * operations are allowed or not. It affects all users, including root.
36 *
37 * Rules:
38 *
39 * - If the number of possible keylock positions is 0, assume there is no
40 * keylock present, do not dissallow any action, i.e. do nothing
41 *
42 * - If the number of possible keylock positions is greater than 0, but the
43 * current lock position is 0, assume tampering with the lock and forbid
44 * all actions.
45 *
46 * - If the lock is in the lowest position, assume the system is locked and
47 * forbid most actions.
48 *
49 * - If the lock is in the highest position, assume the system to be open and
50 * forbid nothing.
51 *
52 * - If the security.models.keylock.order sysctl is set to a value != 0,
53 * reverse this order.
54 */
55
56 #include <sys/cdefs.h>
57 __KERNEL_RCSID(0, "$NetBSD: secmodel_keylock.c,v 1.2 2009/08/15 09:43:59 mbalmer Exp $");
58
59 #include <sys/types.h>
60 #include <sys/param.h>
61 #include <sys/kauth.h>
62
63 #include <sys/conf.h>
64 #include <sys/mount.h>
65 #include <sys/sysctl.h>
66 #include <sys/vnode.h>
67
68 #include <dev/keylock.h>
69
70 #include <miscfs/specfs/specdev.h>
71
72 #include <secmodel/keylock/keylock.h>
73
74 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
75
76 SYSCTL_SETUP(sysctl_security_keylock_setup,
77 "sysctl security keylock setup")
78 {
79 const struct sysctlnode *rnode;
80
81 sysctl_createv(clog, 0, NULL, &rnode,
82 CTLFLAG_PERMANENT,
83 CTLTYPE_NODE, "security", NULL,
84 NULL, 0, NULL, 0,
85 CTL_SECURITY, CTL_EOL);
86
87 sysctl_createv(clog, 0, &rnode, &rnode,
88 CTLFLAG_PERMANENT,
89 CTLTYPE_NODE, "models", NULL,
90 NULL, 0, NULL, 0,
91 CTL_CREATE, CTL_EOL);
92
93 sysctl_createv(clog, 0, &rnode, &rnode,
94 CTLFLAG_PERMANENT,
95 CTLTYPE_NODE, "keylock",
96 SYSCTL_DESCR("Keylock security model"),
97 NULL, 0, NULL, 0,
98 CTL_CREATE, CTL_EOL);
99
100 sysctl_createv(clog, 0, &rnode, NULL,
101 CTLFLAG_PERMANENT,
102 CTLTYPE_STRING, "name", NULL,
103 NULL, 0, __UNCONST("Keylock"), 0,
104 CTL_CREATE, CTL_EOL);
105 }
106
107 void
108 secmodel_keylock_init(void)
109 {
110 }
111
112 void
113 secmodel_keylock_start(void)
114 {
115 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
116 secmodel_keylock_system_cb, NULL);
117 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
118 secmodel_keylock_process_cb, NULL);
119 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
120 secmodel_keylock_network_cb, NULL);
121 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
122 secmodel_keylock_machdep_cb, NULL);
123 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
124 secmodel_keylock_device_cb, NULL);
125 }
126
127 void
128 secmodel_keylock_stop(void)
129 {
130 kauth_unlisten_scope(l_system);
131 kauth_unlisten_scope(l_process);
132 kauth_unlisten_scope(l_network);
133 kauth_unlisten_scope(l_machdep);
134 kauth_unlisten_scope(l_device);
135 }
136
137 /*
138 * kauth(9) listener
139 *
140 * Security model: Multi-position keylock
141 * Scope: System
142 * Responsibility: Keylock
143 */
144 int
145 secmodel_keylock_system_cb(kauth_cred_t cred,
146 kauth_action_t action, void *cookie, void *arg0, void *arg1,
147 void *arg2, void *arg3)
148 {
149 int result;
150 enum kauth_system_req req;
151 int kstate;
152
153 kstate = keylock_state();
154 if (kstate == KEYLOCK_ABSENT)
155 return KAUTH_RESULT_DEFER;
156 else if (kstate == KEYLOCK_TAMPER)
157 return KAUTH_RESULT_DENY;
158
159 result = KAUTH_RESULT_DEFER;
160 req = (enum kauth_system_req)arg0;
161
162 switch (action) {
163 case KAUTH_SYSTEM_CHSYSFLAGS:
164 if (kstate == KEYLOCK_CLOSE)
165 result = KAUTH_RESULT_DENY;
166 break;
167
168 case KAUTH_SYSTEM_TIME:
169 switch (req) {
170 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
171 if (kstate == KEYLOCK_CLOSE)
172 result = KAUTH_RESULT_DENY;
173 break;
174
175 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
176 struct timespec *ts = arg1;
177 struct timespec *delta = arg2;
178
179 /*
180 * Don't allow the time to be set forward so far it
181 * will wrap and become negative, thus allowing an
182 * attacker to bypass the next check below. The
183 * cutoff is 1 year before rollover occurs, so even
184 * if the attacker uses adjtime(2) to move the time
185 * past the cutoff, it will take a very long time
186 * to get to the wrap point.
187 */
188 if (keylock_position() > 1 &&
189 ((ts->tv_sec > LLONG_MAX - 365*24*60*60) ||
190 (delta->tv_sec < 0 || delta->tv_nsec < 0)))
191 result = KAUTH_RESULT_DENY;
192 break;
193 }
194 default:
195 break;
196 }
197 break;
198
199 case KAUTH_SYSTEM_MODULE:
200 if (kstate == KEYLOCK_CLOSE)
201 result = KAUTH_RESULT_DENY;
202 break;
203
204 case KAUTH_SYSTEM_MOUNT:
205 switch (req) {
206 case KAUTH_REQ_SYSTEM_MOUNT_NEW:
207 if (kstate == KEYLOCK_CLOSE)
208 result = KAUTH_RESULT_DENY;
209
210 break;
211
212 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
213 if (kstate == KEYLOCK_CLOSE) {
214 struct mount *mp = arg1;
215 u_long flags = (u_long)arg2;
216
217 /*
218 * Can only degrade from read/write to
219 * read-only.
220 */
221 if (flags != (mp->mnt_flag | MNT_RDONLY |
222 MNT_RELOAD | MNT_FORCE | MNT_UPDATE))
223 result = KAUTH_RESULT_DENY;
224 }
225 break;
226 default:
227 break;
228 }
229
230 break;
231
232 case KAUTH_SYSTEM_SYSCTL:
233 switch (req) {
234 case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
235 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
236 case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
237 if (kstate == KEYLOCK_CLOSE)
238 result = KAUTH_RESULT_DENY;
239 break;
240 default:
241 break;
242 }
243 break;
244
245 case KAUTH_SYSTEM_SETIDCORE:
246 if (kstate == KEYLOCK_CLOSE)
247 result = KAUTH_RESULT_DENY;
248 break;
249
250 case KAUTH_SYSTEM_DEBUG:
251 switch (req) {
252 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
253 if (kstate == KEYLOCK_CLOSE)
254 result = KAUTH_RESULT_DENY;
255 break;
256 default:
257 break;
258 }
259 break;
260 }
261
262 return result;
263 }
264
265 /*
266 * kauth(9) listener
267 *
268 * Security model: Multi-position keylock
269 * Scope: Process
270 * Responsibility: Keylock
271 */
272 int
273 secmodel_keylock_process_cb(kauth_cred_t cred,
274 kauth_action_t action, void *cookie, void *arg0,
275 void *arg1, void *arg2, void *arg3)
276 {
277 struct proc *p;
278 int result, kstate;
279
280 kstate = keylock_state();
281 if (kstate == KEYLOCK_ABSENT)
282 return KAUTH_RESULT_DEFER;
283 else if (kstate == KEYLOCK_TAMPER)
284 return KAUTH_RESULT_DENY;
285
286 result = KAUTH_RESULT_DEFER;
287 p = arg0;
288
289 switch (action) {
290 case KAUTH_PROCESS_PROCFS: {
291 enum kauth_process_req req;
292
293 req = (enum kauth_process_req)arg2;
294 switch (req) {
295 case KAUTH_REQ_PROCESS_PROCFS_READ:
296 break;
297
298 case KAUTH_REQ_PROCESS_PROCFS_RW:
299 case KAUTH_REQ_PROCESS_PROCFS_WRITE:
300 if ((p == initproc) && (kstate != KEYLOCK_OPEN))
301 result = KAUTH_RESULT_DENY;
302
303 break;
304 default:
305 break;
306 }
307
308 break;
309 }
310
311 case KAUTH_PROCESS_PTRACE:
312 if ((p == initproc) && (kstate != KEYLOCK_OPEN))
313 result = KAUTH_RESULT_DENY;
314
315 break;
316
317 case KAUTH_PROCESS_CORENAME:
318 if (kstate == KEYLOCK_CLOSE)
319 result = KAUTH_RESULT_DENY;
320 break;
321 }
322 return result;
323 }
324
325 /*
326 * kauth(9) listener
327 *
328 * Security model: Multi-position keylock
329 * Scope: Network
330 * Responsibility: Keylock
331 */
332 int
333 secmodel_keylock_network_cb(kauth_cred_t cred,
334 kauth_action_t action, void *cookie, void *arg0,
335 void *arg1, void *arg2, void *arg3)
336 {
337 int result, kstate;
338 enum kauth_network_req req;
339
340 kstate = keylock_state();
341 if (kstate == KEYLOCK_ABSENT)
342 return KAUTH_RESULT_DEFER;
343 else if (kstate == KEYLOCK_TAMPER)
344 return KAUTH_RESULT_DENY;
345
346 result = KAUTH_RESULT_DEFER;
347 req = (enum kauth_network_req)arg0;
348
349 switch (action) {
350 case KAUTH_NETWORK_FIREWALL:
351 switch (req) {
352 case KAUTH_REQ_NETWORK_FIREWALL_FW:
353 case KAUTH_REQ_NETWORK_FIREWALL_NAT:
354 if (kstate == KEYLOCK_CLOSE)
355 result = KAUTH_RESULT_DENY;
356 break;
357
358 default:
359 break;
360 }
361 break;
362
363 case KAUTH_NETWORK_FORWSRCRT:
364 if (kstate != KEYLOCK_OPEN)
365 result = KAUTH_RESULT_DENY;
366 break;
367 }
368
369 return result;
370 }
371
372 /*
373 * kauth(9) listener
374 *
375 * Security model: Multi-position keylock
376 * Scope: Machdep
377 * Responsibility: Keylock
378 */
379 int
380 secmodel_keylock_machdep_cb(kauth_cred_t cred,
381 kauth_action_t action, void *cookie, void *arg0,
382 void *arg1, void *arg2, void *arg3)
383 {
384 int result, kstate;
385
386 kstate = keylock_state();
387 if (kstate == KEYLOCK_ABSENT)
388 return KAUTH_RESULT_DEFER;
389 else if (kstate == KEYLOCK_TAMPER)
390 return KAUTH_RESULT_DENY;
391
392 result = KAUTH_RESULT_DEFER;
393
394 switch (action) {
395 case KAUTH_MACHDEP_IOPERM_SET:
396 case KAUTH_MACHDEP_IOPL:
397 if (kstate != KEYLOCK_OPEN)
398 result = KAUTH_RESULT_DENY;
399 break;
400
401 case KAUTH_MACHDEP_UNMANAGEDMEM:
402 if (kstate != KEYLOCK_OPEN)
403 result = KAUTH_RESULT_DENY;
404 break;
405 }
406
407 return result;
408 }
409
410 /*
411 * kauth(9) listener
412 *
413 * Security model: Multi-position keylock
414 * Scope: Device
415 * Responsibility: Keylock
416 */
417 int
418 secmodel_keylock_device_cb(kauth_cred_t cred,
419 kauth_action_t action, void *cookie, void *arg0,
420 void *arg1, void *arg2, void *arg3)
421 {
422 int result, kstate;
423
424 kstate = keylock_state();
425 if (kstate == KEYLOCK_ABSENT)
426 return KAUTH_RESULT_DEFER;
427 else if (kstate == KEYLOCK_TAMPER)
428 return KAUTH_RESULT_DENY;
429
430 result = KAUTH_RESULT_DEFER;
431
432 switch (action) {
433 case KAUTH_DEVICE_RAWIO_SPEC: {
434 struct vnode *vp, *bvp;
435 enum kauth_device_req req;
436 dev_t dev;
437 int d_type;
438
439 req = (enum kauth_device_req)arg0;
440 vp = arg1;
441
442 KASSERT(vp != NULL);
443
444 dev = vp->v_rdev;
445 d_type = D_OTHER;
446 bvp = NULL;
447
448 /* Handle /dev/mem and /dev/kmem. */
449 if ((vp->v_type == VCHR) && iskmemdev(dev)) {
450 switch (req) {
451 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
452 break;
453
454 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
455 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
456 if (kstate != KEYLOCK_OPEN)
457 result = KAUTH_RESULT_DENY;
458 break;
459 default:
460 break;
461 }
462 break;
463 }
464
465 switch (req) {
466 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
467 break;
468
469 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
470 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
471 switch (vp->v_type) {
472 case VCHR: {
473 const struct cdevsw *cdev;
474
475 cdev = cdevsw_lookup(dev);
476 if (cdev != NULL) {
477 dev_t blkdev;
478
479 blkdev = devsw_chr2blk(dev);
480 if (blkdev != NODEV) {
481 vfinddev(blkdev, VBLK, &bvp);
482 if (bvp != NULL)
483 d_type = (cdev->d_flag
484 & D_TYPEMASK);
485 }
486 }
487
488 break;
489 }
490 case VBLK: {
491 const struct bdevsw *bdev;
492
493 bdev = bdevsw_lookup(dev);
494 if (bdev != NULL)
495 d_type = (bdev->d_flag & D_TYPEMASK);
496
497 bvp = vp;
498
499 break;
500 }
501 default:
502 break;
503 }
504
505 if (d_type != D_DISK)
506 break;
507
508 /*
509 * XXX: This is bogus. We should be failing the request
510 * XXX: not only if this specific slice is mounted, but
511 * XXX: if it's on a disk with any other mounted slice.
512 */
513 if (vfs_mountedon(bvp) && (kstate != KEYLOCK_OPEN))
514 break;
515
516 if (kstate == KEYLOCK_CLOSE)
517 result = KAUTH_RESULT_DENY;
518
519 break;
520 default:
521 break;
522 }
523 break;
524 }
525
526 case KAUTH_DEVICE_RAWIO_PASSTHRU:
527 if (kstate != KEYLOCK_OPEN) {
528 u_long bits;
529
530 bits = (u_long)arg0;
531
532 KASSERT(bits != 0);
533 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL)
534 == 0);
535
536 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
537 result = KAUTH_RESULT_DENY;
538 }
539 break;
540
541 case KAUTH_DEVICE_GPIO_PINSET:
542 if (kstate != KEYLOCK_OPEN)
543 result = KAUTH_RESULT_DENY;
544 break;
545 default:
546 break;
547 }
548 return result;
549 }
550