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@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 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
76static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
77
78static secmodel_t keylock_sm;
79
80SYSCTL_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
105void
106secmodel_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
116void
117secmodel_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
131void
132secmodel_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 */
155int
156secmodel_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 */
264int
265secmodel_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 */
324int
325secmodel_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 */
371int
372secmodel_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 */
409int
410secmodel_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