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