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