secmodel_keylock.c revision 1.7 1 /* $NetBSD: secmodel_keylock.c,v 1.7 2011/12/08 11:01:59 jym 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.7 2011/12/08 11:01:59 jym 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 #include <sys/timevar.h>
68
69 #include <dev/keylock.h>
70
71 #include <miscfs/specfs/specdev.h>
72
73 #include <secmodel/secmodel.h>
74 #include <secmodel/keylock/keylock.h>
75
76 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
77
78 static secmodel_t keylock_sm;
79
80 SYSCTL_SETUP(sysctl_security_keylock_setup,
81 "sysctl security keylock setup")
82 {
83 const struct sysctlnode *rnode;
84
85 sysctl_createv(clog, 0, NULL, &rnode,
86 CTLFLAG_PERMANENT,
87 CTLTYPE_NODE, "security", NULL,
88 NULL, 0, NULL, 0,
89 CTL_SECURITY, CTL_EOL);
90
91 sysctl_createv(clog, 0, &rnode, &rnode,
92 CTLFLAG_PERMANENT,
93 CTLTYPE_NODE, "models", NULL,
94 NULL, 0, NULL, 0,
95 CTL_CREATE, CTL_EOL);
96
97 sysctl_createv(clog, 0, &rnode, &rnode,
98 CTLFLAG_PERMANENT,
99 CTLTYPE_NODE, "keylock",
100 SYSCTL_DESCR("Keylock security model"),
101 NULL, 0, NULL, 0,
102 CTL_CREATE, CTL_EOL);
103
104 sysctl_createv(clog, 0, &rnode, NULL,
105 CTLFLAG_PERMANENT,
106 CTLTYPE_STRING, "name", NULL,
107 NULL, 0, __UNCONST("Keylock"), 0,
108 CTL_CREATE, CTL_EOL);
109 }
110
111 void
112 secmodel_keylock_init(void)
113 {
114 int error = secmodel_register(&keylock_sm,
115 "org.netbsd.secmodel.keylock",
116 "NetBSD Security Model: Keylock", NULL, NULL, NULL);
117 if (error != 0)
118 printf("secmodel_keylock_init: secmodel_register "
119 "returned %d\n", error);
120 }
121
122 void
123 secmodel_keylock_start(void)
124 {
125 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
126 secmodel_keylock_system_cb, NULL);
127 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
128 secmodel_keylock_process_cb, NULL);
129 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
130 secmodel_keylock_network_cb, NULL);
131 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
132 secmodel_keylock_machdep_cb, NULL);
133 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
134 secmodel_keylock_device_cb, NULL);
135 }
136
137 void
138 secmodel_keylock_stop(void)
139 {
140 int error;
141
142 kauth_unlisten_scope(l_system);
143 kauth_unlisten_scope(l_process);
144 kauth_unlisten_scope(l_network);
145 kauth_unlisten_scope(l_machdep);
146 kauth_unlisten_scope(l_device);
147
148 error = secmodel_deregister(keylock_sm);
149 if (error != 0)
150 printf("secmodel_keylock_stop: secmodel_deregister "
151 "returned %d\n", error);
152 }
153
154 /*
155 * kauth(9) listener
156 *
157 * Security model: Multi-position keylock
158 * Scope: System
159 * Responsibility: Keylock
160 */
161 int
162 secmodel_keylock_system_cb(kauth_cred_t cred,
163 kauth_action_t action, void *cookie, void *arg0, void *arg1,
164 void *arg2, void *arg3)
165 {
166 int result;
167 enum kauth_system_req req;
168 int kstate;
169
170 kstate = keylock_state();
171 if (kstate == KEYLOCK_ABSENT)
172 return KAUTH_RESULT_DEFER;
173 else if (kstate == KEYLOCK_TAMPER)
174 return KAUTH_RESULT_DENY;
175
176 result = KAUTH_RESULT_DEFER;
177 req = (enum kauth_system_req)arg0;
178
179 switch (action) {
180 case KAUTH_SYSTEM_CHSYSFLAGS:
181 if (kstate == KEYLOCK_CLOSE)
182 result = KAUTH_RESULT_DENY;
183 break;
184
185 case KAUTH_SYSTEM_TIME:
186 switch (req) {
187 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
188 if (kstate == KEYLOCK_CLOSE)
189 result = KAUTH_RESULT_DENY;
190 break;
191
192 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
193 struct timespec *ts = arg1;
194 struct timespec *delta = arg2;
195
196 if (keylock_position() > 1 && time_wraps(ts, delta))
197 result = KAUTH_RESULT_DENY;
198 break;
199 }
200 default:
201 break;
202 }
203 break;
204
205 case KAUTH_SYSTEM_MODULE:
206 if (kstate == KEYLOCK_CLOSE)
207 result = KAUTH_RESULT_DENY;
208 break;
209
210 case KAUTH_SYSTEM_MOUNT:
211 switch (req) {
212 case KAUTH_REQ_SYSTEM_MOUNT_NEW:
213 if (kstate == KEYLOCK_CLOSE)
214 result = KAUTH_RESULT_DENY;
215
216 break;
217
218 case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
219 if (kstate == KEYLOCK_CLOSE) {
220 struct mount *mp = arg1;
221 u_long flags = (u_long)arg2;
222
223 /*
224 * Can only degrade from read/write to
225 * read-only.
226 */
227 if (flags != (mp->mnt_flag | MNT_RDONLY |
228 MNT_RELOAD | MNT_FORCE | MNT_UPDATE))
229 result = KAUTH_RESULT_DENY;
230 }
231 break;
232 default:
233 break;
234 }
235
236 break;
237
238 case KAUTH_SYSTEM_SYSCTL:
239 switch (req) {
240 case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
241 case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
242 case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
243 if (kstate == KEYLOCK_CLOSE)
244 result = KAUTH_RESULT_DENY;
245 break;
246 default:
247 break;
248 }
249 break;
250
251 case KAUTH_SYSTEM_SETIDCORE:
252 if (kstate == KEYLOCK_CLOSE)
253 result = KAUTH_RESULT_DENY;
254 break;
255
256 case KAUTH_SYSTEM_DEBUG:
257 switch (req) {
258 case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
259 if (kstate == KEYLOCK_CLOSE)
260 result = KAUTH_RESULT_DENY;
261 break;
262 default:
263 break;
264 }
265 break;
266 }
267
268 return result;
269 }
270
271 /*
272 * kauth(9) listener
273 *
274 * Security model: Multi-position keylock
275 * Scope: Process
276 * Responsibility: Keylock
277 */
278 int
279 secmodel_keylock_process_cb(kauth_cred_t cred,
280 kauth_action_t action, void *cookie, void *arg0,
281 void *arg1, void *arg2, void *arg3)
282 {
283 struct proc *p;
284 int result, kstate;
285
286 kstate = keylock_state();
287 if (kstate == KEYLOCK_ABSENT)
288 return KAUTH_RESULT_DEFER;
289 else if (kstate == KEYLOCK_TAMPER)
290 return KAUTH_RESULT_DENY;
291
292 result = KAUTH_RESULT_DEFER;
293 p = arg0;
294
295 switch (action) {
296 case KAUTH_PROCESS_PROCFS: {
297 enum kauth_process_req req;
298
299 req = (enum kauth_process_req)arg2;
300 switch (req) {
301 case KAUTH_REQ_PROCESS_PROCFS_READ:
302 break;
303
304 case KAUTH_REQ_PROCESS_PROCFS_RW:
305 case KAUTH_REQ_PROCESS_PROCFS_WRITE:
306 if ((p == initproc) && (kstate != KEYLOCK_OPEN))
307 result = KAUTH_RESULT_DENY;
308
309 break;
310 default:
311 break;
312 }
313
314 break;
315 }
316
317 case KAUTH_PROCESS_PTRACE:
318 if ((p == initproc) && (kstate != KEYLOCK_OPEN))
319 result = KAUTH_RESULT_DENY;
320
321 break;
322
323 case KAUTH_PROCESS_CORENAME:
324 if (kstate == KEYLOCK_CLOSE)
325 result = KAUTH_RESULT_DENY;
326 break;
327 }
328 return result;
329 }
330
331 /*
332 * kauth(9) listener
333 *
334 * Security model: Multi-position keylock
335 * Scope: Network
336 * Responsibility: Keylock
337 */
338 int
339 secmodel_keylock_network_cb(kauth_cred_t cred,
340 kauth_action_t action, void *cookie, void *arg0,
341 void *arg1, void *arg2, void *arg3)
342 {
343 int result, kstate;
344 enum kauth_network_req req;
345
346 kstate = keylock_state();
347 if (kstate == KEYLOCK_ABSENT)
348 return KAUTH_RESULT_DEFER;
349 else if (kstate == KEYLOCK_TAMPER)
350 return KAUTH_RESULT_DENY;
351
352 result = KAUTH_RESULT_DEFER;
353 req = (enum kauth_network_req)arg0;
354
355 switch (action) {
356 case KAUTH_NETWORK_FIREWALL:
357 switch (req) {
358 case KAUTH_REQ_NETWORK_FIREWALL_FW:
359 case KAUTH_REQ_NETWORK_FIREWALL_NAT:
360 if (kstate == KEYLOCK_CLOSE)
361 result = KAUTH_RESULT_DENY;
362 break;
363
364 default:
365 break;
366 }
367 break;
368
369 case KAUTH_NETWORK_FORWSRCRT:
370 if (kstate != KEYLOCK_OPEN)
371 result = KAUTH_RESULT_DENY;
372 break;
373 }
374
375 return result;
376 }
377
378 /*
379 * kauth(9) listener
380 *
381 * Security model: Multi-position keylock
382 * Scope: Machdep
383 * Responsibility: Keylock
384 */
385 int
386 secmodel_keylock_machdep_cb(kauth_cred_t cred,
387 kauth_action_t action, void *cookie, void *arg0,
388 void *arg1, void *arg2, void *arg3)
389 {
390 int result, kstate;
391
392 kstate = keylock_state();
393 if (kstate == KEYLOCK_ABSENT)
394 return KAUTH_RESULT_DEFER;
395 else if (kstate == KEYLOCK_TAMPER)
396 return KAUTH_RESULT_DENY;
397
398 result = KAUTH_RESULT_DEFER;
399
400 switch (action) {
401 case KAUTH_MACHDEP_IOPERM_SET:
402 case KAUTH_MACHDEP_IOPL:
403 if (kstate != KEYLOCK_OPEN)
404 result = KAUTH_RESULT_DENY;
405 break;
406
407 case KAUTH_MACHDEP_UNMANAGEDMEM:
408 if (kstate != KEYLOCK_OPEN)
409 result = KAUTH_RESULT_DENY;
410 break;
411 }
412
413 return result;
414 }
415
416 /*
417 * kauth(9) listener
418 *
419 * Security model: Multi-position keylock
420 * Scope: Device
421 * Responsibility: Keylock
422 */
423 int
424 secmodel_keylock_device_cb(kauth_cred_t cred,
425 kauth_action_t action, void *cookie, void *arg0,
426 void *arg1, void *arg2, void *arg3)
427 {
428 int result, kstate, error;
429
430 kstate = keylock_state();
431 if (kstate == KEYLOCK_ABSENT)
432 return KAUTH_RESULT_DEFER;
433 else if (kstate == KEYLOCK_TAMPER)
434 return KAUTH_RESULT_DENY;
435
436 result = KAUTH_RESULT_DEFER;
437
438 switch (action) {
439 case KAUTH_DEVICE_RAWIO_SPEC: {
440 struct vnode *vp;
441 enum kauth_device_req req;
442
443 req = (enum kauth_device_req)arg0;
444 vp = arg1;
445
446 KASSERT(vp != NULL);
447
448 /* Handle /dev/mem and /dev/kmem. */
449 if (iskmemvp(vp)) {
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 error = rawdev_mounted(vp, NULL);
472
473 if (error == EINVAL)
474 break;
475
476 if (error && (kstate != KEYLOCK_OPEN))
477 break;
478
479 if (kstate == KEYLOCK_CLOSE)
480 result = KAUTH_RESULT_DENY;
481
482 break;
483 default:
484 break;
485 }
486 break;
487 }
488
489 case KAUTH_DEVICE_RAWIO_PASSTHRU:
490 if (kstate != KEYLOCK_OPEN) {
491 u_long bits;
492
493 bits = (u_long)arg0;
494
495 KASSERT(bits != 0);
496 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL)
497 == 0);
498
499 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
500 result = KAUTH_RESULT_DENY;
501 }
502 break;
503
504 case KAUTH_DEVICE_GPIO_PINSET:
505 if (kstate != KEYLOCK_OPEN)
506 result = KAUTH_RESULT_DENY;
507 break;
508 default:
509 break;
510 }
511 return result;
512 }
513