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@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.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
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, "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
111void
112secmodel_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
122void
123secmodel_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
137void
138secmodel_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 */
161int
162secmodel_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 */
278int
279secmodel_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 */
338int
339secmodel_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 */
385int
386secmodel_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 */
423int
424secmodel_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