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
75static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
76
77static secmodel_t keylock_sm;
78
79SYSCTL_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
104void
105secmodel_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
115void
116secmodel_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
130void
131secmodel_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 */
154int
155secmodel_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 */
263int
264secmodel_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 */
323int
324secmodel_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 */
370int
371secmodel_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 */
408int
409secmodel_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