secmodel_keylock.c revision 1.10 1 /* $NetBSD: secmodel_keylock.c,v 1.10 2020/02/21 00:26:23 joerg 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.10 2020/02/21 00:26:23 joerg 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, "models", NULL,
88 NULL, 0, NULL, 0,
89 CTL_SECURITY, CTL_CREATE, CTL_EOL);
90
91 sysctl_createv(clog, 0, &rnode, &rnode,
92 CTLFLAG_PERMANENT,
93 CTLTYPE_NODE, "keylock",
94 SYSCTL_DESCR("Keylock security model"),
95 NULL, 0, NULL, 0,
96 CTL_CREATE, CTL_EOL);
97
98 sysctl_createv(clog, 0, &rnode, NULL,
99 CTLFLAG_PERMANENT,
100 CTLTYPE_STRING, "name", NULL,
101 NULL, 0, __UNCONST("Keylock"), 0,
102 CTL_CREATE, CTL_EOL);
103 }
104
105 void
106 secmodel_keylock_init(void)
107 {
108 int error = secmodel_register(&keylock_sm,
109 "org.netbsd.secmodel.keylock",
110 "NetBSD Security Model: Keylock", NULL, NULL, NULL);
111 if (error != 0)
112 printf("secmodel_keylock_init: secmodel_register "
113 "returned %d\n", error);
114 }
115
116 void
117 secmodel_keylock_start(void)
118 {
119 l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
120 secmodel_keylock_system_cb, NULL);
121 l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
122 secmodel_keylock_process_cb, NULL);
123 l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
124 secmodel_keylock_network_cb, NULL);
125 l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
126 secmodel_keylock_machdep_cb, NULL);
127 l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
128 secmodel_keylock_device_cb, NULL);
129 }
130
131 void
132 secmodel_keylock_stop(void)
133 {
134 int error;
135
136 kauth_unlisten_scope(l_system);
137 kauth_unlisten_scope(l_process);
138 kauth_unlisten_scope(l_network);
139 kauth_unlisten_scope(l_machdep);
140 kauth_unlisten_scope(l_device);
141
142 error = secmodel_deregister(keylock_sm);
143 if (error != 0)
144 printf("secmodel_keylock_stop: secmodel_deregister "
145 "returned %d\n", error);
146 }
147
148 /*
149 * kauth(9) listener
150 *
151 * Security model: Multi-position keylock
152 * Scope: System
153 * Responsibility: Keylock
154 */
155 int
156 secmodel_keylock_system_cb(kauth_cred_t cred,
157 kauth_action_t action, void *cookie, void *arg0, void *arg1,
158 void *arg2, void *arg3)
159 {
160 int result;
161 enum kauth_system_req req;
162 int kstate;
163
164 kstate = keylock_state();
165 if (kstate == KEYLOCK_ABSENT)
166 return KAUTH_RESULT_DEFER;
167 else if (kstate == KEYLOCK_TAMPER)
168 return KAUTH_RESULT_DENY;
169
170 result = KAUTH_RESULT_DEFER;
171 req = (enum kauth_system_req)(uintptr_t)arg0;
172
173 switch (action) {
174 case KAUTH_SYSTEM_CHSYSFLAGS:
175 if (kstate == KEYLOCK_CLOSE)
176 result = KAUTH_RESULT_DENY;
177 break;
178
179 case KAUTH_SYSTEM_TIME:
180 switch (req) {
181 case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
182 if (kstate == KEYLOCK_CLOSE)
183 result = KAUTH_RESULT_DENY;
184 break;
185
186 case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
187 struct timespec *ts = arg1;
188 struct timespec *delta = arg2;
189
190 if (keylock_position() > 1 && time_wraps(ts, delta))
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 break;
252 }
253
254 return result;
255 }
256
257 /*
258 * kauth(9) listener
259 *
260 * Security model: Multi-position keylock
261 * Scope: Process
262 * Responsibility: Keylock
263 */
264 int
265 secmodel_keylock_process_cb(kauth_cred_t cred,
266 kauth_action_t action, void *cookie, void *arg0,
267 void *arg1, void *arg2, void *arg3)
268 {
269 struct proc *p;
270 int result, kstate;
271
272 kstate = keylock_state();
273 if (kstate == KEYLOCK_ABSENT)
274 return KAUTH_RESULT_DEFER;
275 else if (kstate == KEYLOCK_TAMPER)
276 return KAUTH_RESULT_DENY;
277
278 result = KAUTH_RESULT_DEFER;
279 p = arg0;
280
281 switch (action) {
282 case KAUTH_PROCESS_PROCFS: {
283 enum kauth_process_req req;
284
285 req = (enum kauth_process_req)(uintptr_t)arg2;
286 switch (req) {
287 case KAUTH_REQ_PROCESS_PROCFS_READ:
288 break;
289
290 case KAUTH_REQ_PROCESS_PROCFS_RW:
291 case KAUTH_REQ_PROCESS_PROCFS_WRITE:
292 if ((p == initproc) && (kstate != KEYLOCK_OPEN))
293 result = KAUTH_RESULT_DENY;
294
295 break;
296 default:
297 break;
298 }
299
300 break;
301 }
302
303 case KAUTH_PROCESS_PTRACE:
304 if ((p == initproc) && (kstate != KEYLOCK_OPEN))
305 result = KAUTH_RESULT_DENY;
306
307 break;
308
309 case KAUTH_PROCESS_CORENAME:
310 if (kstate == KEYLOCK_CLOSE)
311 result = KAUTH_RESULT_DENY;
312 break;
313 }
314 return result;
315 }
316
317 /*
318 * kauth(9) listener
319 *
320 * Security model: Multi-position keylock
321 * Scope: Network
322 * Responsibility: Keylock
323 */
324 int
325 secmodel_keylock_network_cb(kauth_cred_t cred,
326 kauth_action_t action, void *cookie, void *arg0,
327 void *arg1, void *arg2, void *arg3)
328 {
329 int result, kstate;
330 enum kauth_network_req req;
331
332 kstate = keylock_state();
333 if (kstate == KEYLOCK_ABSENT)
334 return KAUTH_RESULT_DEFER;
335 else if (kstate == KEYLOCK_TAMPER)
336 return KAUTH_RESULT_DENY;
337
338 result = KAUTH_RESULT_DEFER;
339 req = (enum kauth_network_req)(uintptr_t)arg0;
340
341 switch (action) {
342 case KAUTH_NETWORK_FIREWALL:
343 switch (req) {
344 case KAUTH_REQ_NETWORK_FIREWALL_FW:
345 case KAUTH_REQ_NETWORK_FIREWALL_NAT:
346 if (kstate == KEYLOCK_CLOSE)
347 result = KAUTH_RESULT_DENY;
348 break;
349
350 default:
351 break;
352 }
353 break;
354
355 case KAUTH_NETWORK_FORWSRCRT:
356 if (kstate != KEYLOCK_OPEN)
357 result = KAUTH_RESULT_DENY;
358 break;
359 }
360
361 return result;
362 }
363
364 /*
365 * kauth(9) listener
366 *
367 * Security model: Multi-position keylock
368 * Scope: Machdep
369 * Responsibility: Keylock
370 */
371 int
372 secmodel_keylock_machdep_cb(kauth_cred_t cred,
373 kauth_action_t action, void *cookie, void *arg0,
374 void *arg1, void *arg2, void *arg3)
375 {
376 int result, kstate;
377
378 kstate = keylock_state();
379 if (kstate == KEYLOCK_ABSENT)
380 return KAUTH_RESULT_DEFER;
381 else if (kstate == KEYLOCK_TAMPER)
382 return KAUTH_RESULT_DENY;
383
384 result = KAUTH_RESULT_DEFER;
385
386 switch (action) {
387 case KAUTH_MACHDEP_IOPERM_SET:
388 case KAUTH_MACHDEP_IOPL:
389 if (kstate != KEYLOCK_OPEN)
390 result = KAUTH_RESULT_DENY;
391 break;
392
393 case KAUTH_MACHDEP_UNMANAGEDMEM:
394 if (kstate != KEYLOCK_OPEN)
395 result = KAUTH_RESULT_DENY;
396 break;
397 }
398
399 return result;
400 }
401
402 /*
403 * kauth(9) listener
404 *
405 * Security model: Multi-position keylock
406 * Scope: Device
407 * Responsibility: Keylock
408 */
409 int
410 secmodel_keylock_device_cb(kauth_cred_t cred,
411 kauth_action_t action, void *cookie, void *arg0,
412 void *arg1, void *arg2, void *arg3)
413 {
414 int result, kstate, error;
415
416 kstate = keylock_state();
417 if (kstate == KEYLOCK_ABSENT)
418 return KAUTH_RESULT_DEFER;
419 else if (kstate == KEYLOCK_TAMPER)
420 return KAUTH_RESULT_DENY;
421
422 result = KAUTH_RESULT_DEFER;
423
424 switch (action) {
425 case KAUTH_DEVICE_RAWIO_SPEC: {
426 struct vnode *vp;
427 enum kauth_device_req req;
428
429 req = (enum kauth_device_req)(uintptr_t)arg0;
430 vp = arg1;
431
432 KASSERT(vp != NULL);
433
434 /* Handle /dev/mem and /dev/kmem. */
435 if (iskmemvp(vp)) {
436 switch (req) {
437 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
438 break;
439
440 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
441 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
442 if (kstate != KEYLOCK_OPEN)
443 result = KAUTH_RESULT_DENY;
444 break;
445 default:
446 break;
447 }
448 break;
449 }
450
451 switch (req) {
452 case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
453 break;
454
455 case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
456 case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
457 error = rawdev_mounted(vp, NULL);
458
459 if (error == EINVAL)
460 break;
461
462 if (error && (kstate != KEYLOCK_OPEN))
463 break;
464
465 if (kstate == KEYLOCK_CLOSE)
466 result = KAUTH_RESULT_DENY;
467
468 break;
469 default:
470 break;
471 }
472 break;
473 }
474
475 case KAUTH_DEVICE_RAWIO_PASSTHRU:
476 if (kstate != KEYLOCK_OPEN) {
477 u_long bits;
478
479 bits = (u_long)arg0;
480
481 KASSERT(bits != 0);
482 KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL)
483 == 0);
484
485 if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
486 result = KAUTH_RESULT_DENY;
487 }
488 break;
489
490 case KAUTH_DEVICE_GPIO_PINSET:
491 if (kstate != KEYLOCK_OPEN)
492 result = KAUTH_RESULT_DENY;
493 break;
494 default:
495 break;
496 }
497 return result;
498 }
499