Add support for multi-position electro-mechanical keylocks. An example

driver, gpiolock(4), is provided as an example how to interface real hardware.
A new securemodel, securemodel_keylock, is provided to show how this can
be used to tie keylocks to overall system security.  This is experimental
code.  The diff has been on tech-kern for several weeks.

Reviewed by many, kauth(9) integration reviewed by Elad Efrat; approved by
tonnerre@ and tron@.  Thanks to everyone who provided feedback.
This commit is contained in:
mbalmer 2009-08-14 21:17:21 +00:00
parent eaf64f1b6c
commit 3ab4ce4739
13 changed files with 1132 additions and 9 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1152 2009/08/09 08:20:53 mbalmer Exp $
# $NetBSD: mi,v 1.1153 2009/08/14 21:17:21 mbalmer Exp $
#
# Note: don't delete entries from here - mark them as "obsolete" instead.
#
@ -939,6 +939,7 @@
./usr/share/man/cat4/gpib.0 man-sys-catman .cat
./usr/share/man/cat4/gpio.0 man-sys-catman .cat
./usr/share/man/cat4/gpioiic.0 man-sys-catman .cat
./usr/share/man/cat4/gpiolock.0 man-sys-catman .cat
./usr/share/man/cat4/gpioow.0 man-sys-catman .cat
./usr/share/man/cat4/gpiosim.0 man-sys-catman .cat
./usr/share/man/cat4/gre.0 man-sys-catman .cat
@ -3548,6 +3549,7 @@
./usr/share/man/html4/gpib.html man-sys-htmlman html
./usr/share/man/html4/gpio.html man-sys-htmlman html
./usr/share/man/html4/gpioiic.html man-sys-htmlman html
./usr/share/man/html4/gpiolock.html man-sys-htmlman html
./usr/share/man/html4/gpioow.html man-sys-htmlman html
./usr/share/man/html4/gpiosim.html man-sys-htmlman html
./usr/share/man/html4/gre.html man-sys-htmlman html
@ -5937,6 +5939,7 @@
./usr/share/man/man4/gpib.4 man-sys-man .man
./usr/share/man/man4/gpio.4 man-sys-man .man
./usr/share/man/man4/gpioiic.4 man-sys-man .man
./usr/share/man/man4/gpiolock.4 man-sys-man .man
./usr/share/man/man4/gpioow.4 man-sys-man .man
./usr/share/man/man4/gpiosim.4 man-sys-man .man
./usr/share/man/man4/gre.4 man-sys-man .man

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.496 2009/08/09 08:20:53 mbalmer Exp $
# $NetBSD: Makefile,v 1.497 2009/08/14 21:17:21 mbalmer Exp $
# @(#)Makefile 8.1 (Berkeley) 6/18/93
MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 acpidalb.4 \
@ -25,8 +25,8 @@ MAN= aac.4 ac97.4 acardide.4 aceride.4 acphy.4 acpidalb.4 \
esa.4 esiop.4 esm.4 eso.4 etherip.4 exphy.4 \
fast_ipsec.4 fd.4 finsio.4 fpa.4 fms.4 fss.4 fxp.4 \
gcscaudio.4 gem.4 genfb.4 gentbi.4 geodeide.4 \
glxtphy.4 gpib.4 gpio.4 gpiosim.4 gre.4 gphyter.4 gsip.4 hifn.4 hme.4 \
hpqlb.4 hptide.4 \
glxtphy.4 gpib.4 gpio.4 gpiolock.4 gpiosim.4 gre.4 gphyter.4 gsip.4 \
hifn.4 hme.4 hpqlb.4 hptide.4 \
ichlpcib.4 ichsmb.4 icmp.4 icp.4 icsphy.4 iee.4 ieee80211.4 \
ifmedia.4 igsfb.4 iha.4 iic.4 inet.4 ikphy.4 inphy.4 intersil7170.4 \
ioasic.4 ioat.4 iop.4 iophy.4 iopsp.4 ip.4 ipkdb.4 ipmi.4 ipw.4 \

67
share/man/man4/gpiolock.4 Normal file
View File

@ -0,0 +1,67 @@
.\" $NetBSD: gpiolock.4,v 1.1 2009/08/14 21:17:21 mbalmer Exp $
.\"
.\" Copyright (c) 2009 Marc Balmer <marc@msys.ch>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd August 10, 2009
.Dt GPIOLOCK 4
.Os
.Sh NAME
.Nm gpiolock
.Nd support for multi-position keylocks attached to GPIO pins
.Sh SYNOPSIS
.Cd "gpiolock* at gpio? offset ? mask ?"
.Cd "gpiolock* at gpio?"
.Sh DESCRIPTION
The
.Nm
driver allows connecting of multi-position keylocks over GPIO pins.
The keylock driver registers with a in-kernel keylock supporting system
and provides
.Xr kauth 9
support through an experimental security model.
The keylock state can be queried using the hw.keylock sysctl variables.
Only locks with 2-4 positions are currently supported.
The pin number is specified in the kernel configuration with the
.Ar offset
locator.
The
.Ar mask
locator denotes the pins used for the lock (minimum 2, maximum 4 pins are used).
The
.Ar offset
and
.Ar mask
can also be specified when
.Nm
is attached at runtime using the
.Dv GPIOATTACH
.Xr ioctl 2
on the
.Xr gpio 4
device.
.Sh SEE ALSO
.Xr gpio 4 ,
.Xr intro 4 ,
.Sh HISTORY
The
.Nm
driver first appeared in
.Nx 5.0 .
.Sh AUTHORS
.An -nosplit
The
.Nm
driver was written by
.An Marc Balmer Aq marc@msys.ch .

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.952 2009/08/09 06:40:10 kiyohara Exp $
# $NetBSD: files,v 1.953 2009/08/14 21:17:21 mbalmer Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20090313
@ -24,6 +24,7 @@ defflag MBUFTRACE
defflag PTRACE
defflag COREDUMP
defflag MODULAR
defflag KEYLOCK
defparam DEFCORENAME
defparam HZ
@ -1371,6 +1372,7 @@ file dev/dkwedge/dkwedge_gpt.c dkwedge_method_gpt
file dev/dkwedge/dkwedge_mbr.c dkwedge_method_mbr
file dev/firmload.c firmload
file dev/fss.c fss needs-count
file dev/keylock.c keylock
file dev/lockstat.c lockstat needs-flag
file dev/md.c md needs-count
file dev/midi.c midi | midibus needs-flag

View File

@ -1,4 +1,4 @@
# $NetBSD: files.gpio,v 1.7 2009/08/09 08:18:00 mbalmer Exp $
# $NetBSD: files.gpio,v 1.8 2009/08/14 21:17:22 mbalmer Exp $
define gpio {[offset = -1], [mask = 0]}
@ -19,3 +19,8 @@ file dev/gpio/gpioiic.c gpioiic
device gpioow: onewirebus, onewire_bitbang
attach gpioow at gpio
file dev/gpio/gpioow.c gpioow
# Keylock
device gpiolock: gpiobus
attach gpiolock at gpio
file dev/gpio/gpiolock.c gpiolock

178
sys/dev/gpio/gpiolock.c Normal file
View File

@ -0,0 +1,178 @@
/* $NetBSD: gpiolock.c,v 1.1 2009/08/14 21:17:22 mbalmer Exp $ */
/*
* Copyright (c) 2009 Marc Balmer <marc@msys.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Driver for multi-position keylocks on GPIO pins
*/
#include "opt_keylock.h"
#include <sys/param.h>
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/keylock.h>
#include <dev/gpio/gpiovar.h>
#define GPIOLOCK_MAXPINS 4
#define GPIOLOCK_MINPINS 2
struct gpiolock_softc {
void * sc_gpio;
struct gpio_pinmap sc_map;
int _map[GPIOLOCK_MAXPINS];
int sc_npins;
int sc_data;
int sc_dying;
};
int gpiolock_match(device_t, cfdata_t, void *);
void gpiolock_attach(device_t, device_t, void *);
int gpiolock_detach(device_t, int);
int gpiolock_activate(device_t, enum devact);
int gpiolock_position(void *);
CFATTACH_DECL_NEW(gpiolock, sizeof(struct gpiolock_softc),
gpiolock_match, gpiolock_attach, gpiolock_detach, gpiolock_activate);
extern struct cfdriver gpiolock_cd;
int
gpiolock_match(device_t parent, cfdata_t cf,
void *aux)
{
struct gpio_attach_args *ga = aux;
int npins;
if (strcmp(ga->ga_dvname, cf->cf_name))
return 0;
if (ga->ga_offset == -1)
return 0;
/* Check number of pins */
npins = gpio_npins(ga->ga_mask);
if (npins < GPIOLOCK_MINPINS || npins > GPIOLOCK_MAXPINS) {
aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name,
ga->ga_mask);
return 0;
}
return 1;
}
void
gpiolock_attach(device_t parent, device_t self, void *aux)
{
struct gpiolock_softc *sc = device_private(self);
struct gpio_attach_args *ga = aux;
int pin, caps;
sc->sc_npins = gpio_npins(ga->ga_mask);
/* Map pins */
sc->sc_gpio = ga->ga_gpio;
sc->sc_map.pm_map = sc->_map;
if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
&sc->sc_map)) {
aprint_error(": can't map pins\n");
return;
}
/* Configure data pins */
for (pin = 0; pin < sc->sc_npins; pin++) {
caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, pin);
if (!(caps & GPIO_PIN_INPUT)) {
aprint_error(": data pin is unable to read input\n");
goto fail;
}
aprint_normal(" [%d]", sc->sc_map.pm_map[pin]);
sc->sc_data = GPIO_PIN_INPUT;
gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, pin, sc->sc_data);
}
#ifdef KEYLOCK
/* Register keylock */
if (keylock_register(self, sc->sc_npins, gpiolock_position)) {
aprint_error(": can't register keylock\n");
goto fail;
}
#endif
pmf_device_register(self, NULL, NULL);
aprint_normal("\n");
return;
fail:
gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
}
int
gpiolock_detach(device_t self, int flags)
{
struct gpiolock_softc *sc = device_private(self);
pmf_device_deregister(self);
#ifdef KEYLOCK
keylock_unregister(self, gpiolock_position);
#endif
gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
return 0;
}
int
gpiolock_activate(device_t self, enum devact act)
{
struct gpiolock_softc *sc = device_private(self);
switch (act) {
case DVACT_ACTIVATE:
return EOPNOTSUPP;
case DVACT_DEACTIVATE:
sc->sc_dying = 1;
break;
}
return 0;
}
int
gpiolock_position(void *arg)
{
struct gpiolock_softc *sc = device_private((device_t)arg);
int pos, pin;
for (pos = pin = 0; pin < sc->sc_npins; pin++) {
if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, pin) ==
GPIO_PIN_HIGH)
pos = pin + 1;
}
return pos;
}

210
sys/dev/keylock.c Normal file
View File

@ -0,0 +1,210 @@
/* $NetBSD: keylock.c,v 1.1 2009/08/14 21:17:22 mbalmer Exp $ */
/*
* Copyright (c) 2009 Marc Balmer <marc@msys.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_secmodel_keylock.h"
/* Support for multi-position electro-mechanical keylocks */
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/keylock.h>
#include <sys/sysctl.h>
#ifdef secmodel_keylock
#include <sys/kauth.h>
#include <secmodel/keylock/keylock.h>
#endif
static int (*keylock_pos_cb)(void *) = NULL;
static void *keylock_pos_cb_arg = NULL;
static int keylock_npos = 0;
static int keylock_order = 0;
int keylock_pos_sysctl(SYSCTLFN_PROTO);
int keylock_state_sysctl(SYSCTLFN_PROTO);
int keylock_order_sysctl(SYSCTLFN_PROTO);
SYSCTL_SETUP(sysctl_keylock_setup, "sysctl keylock setup")
{
const struct sysctlnode *node = NULL;
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "hw", NULL,
NULL, 0, NULL, 0,
CTL_HW, CTL_EOL);
sysctl_createv(clog, 0, NULL, &node,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "keylock",
SYSCTL_DESCR("Keylock state"),
NULL, 0, NULL, 0,
CTL_HW, CTL_CREATE, CTL_EOL);
if (node == NULL)
return;
sysctl_createv(clog, 0, &node, NULL,
CTLFLAG_PERMANENT | CTLFLAG_READONLY,
CTLTYPE_INT, "pos",
SYSCTL_DESCR("Current keylock position"),
keylock_pos_sysctl, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, &node, NULL,
CTLFLAG_PERMANENT | CTLFLAG_READONLY,
CTLTYPE_INT, "npos",
SYSCTL_DESCR("Number of keylock positions"),
NULL, 0, &keylock_npos, 0,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, &node, NULL,
CTLFLAG_PERMANENT | CTLFLAG_READONLY,
CTLTYPE_INT, "state",
SYSCTL_DESCR("Keylock state"),
keylock_state_sysctl, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, &node, NULL,
CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
CTLTYPE_INT, "order",
SYSCTL_DESCR("Keylock closedness order"),
keylock_order_sysctl, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
}
int
keylock_register(void *cb_arg, int npos, int (*cb)(void *))
{
if (keylock_pos_cb != NULL)
return -1;
keylock_pos_cb = cb;
keylock_pos_cb_arg = cb_arg;
keylock_npos = npos;
#ifdef secmodel_keylock
secmodel_keylock_start();
#endif
return 0;
}
void
keylock_unregister(void *cb_arg, int (*cb)(void *))
{
if (keylock_pos_cb != cb || keylock_pos_cb_arg != cb_arg)
return;
#ifdef secmodel_keylock
secmodel_keylock_stop();
#endif
keylock_pos_cb = NULL;
keylock_pos_cb_arg = NULL;
keylock_npos = 0;
}
int
keylock_position(void)
{
if (keylock_pos_cb == NULL)
return 0;
return (*keylock_pos_cb)(keylock_pos_cb_arg);
}
int
keylock_num_positions(void)
{
return keylock_npos;
}
int
keylock_state(void)
{
int pos;
if (keylock_npos == 0)
return KEYLOCK_ABSENT;
pos = keylock_position();
if (pos == 0)
return KEYLOCK_TAMPER;
/*
* XXX How should the intermediate positions be handled?
* At the moment only the ultimate positions are properly handled,
* we need to think about what we do with the intermediate positions.
* For now we return KEYLOCK_SEMIOPEN for them.
*/
if (pos == 1)
return keylock_order == 0 ? KEYLOCK_CLOSE : KEYLOCK_OPEN;
else if (pos == keylock_npos)
return keylock_order == 0 ? KEYLOCK_OPEN : KEYLOCK_CLOSE;
return KEYLOCK_SEMIOPEN;
}
int
keylock_pos_sysctl(SYSCTLFN_ARGS)
{
struct sysctlnode node;
int val;
node = *rnode;
node.sysctl_data = &val;
val = keylock_position();
return sysctl_lookup(SYSCTLFN_CALL(&node));
}
int
keylock_state_sysctl(SYSCTLFN_ARGS)
{
struct sysctlnode node;
int val;
node = *rnode;
node.sysctl_data = &val;
val = keylock_state();
return sysctl_lookup(SYSCTLFN_CALL(&node));
}
int
keylock_order_sysctl(SYSCTLFN_ARGS)
{
struct sysctlnode node;
int val, error;
node = *rnode;
node.sysctl_data = &val;
val = keylock_order;
error = sysctl_lookup(SYSCTLFN_CALL(&node));
if (error || newp == NULL)
return error;
if (keylock_state() != KEYLOCK_OPEN)
return -1;
keylock_order = val;
return 0;
}

View File

@ -1,4 +1,4 @@
# $NetBSD: files.secmodel,v 1.2 2007/11/21 22:49:07 elad Exp $
# $NetBSD: files.secmodel,v 1.3 2009/08/14 21:17:22 mbalmer Exp $
#
# Traditional 4.4BSD - Securelevel
@ -14,3 +14,8 @@ include "secmodel/bsd44/files.bsd44"
# Sample overlay model on-top of the traditional one
#
include "secmodel/overlay/files.overlay"
#
# Multi-position keylock
#
include "secmodel/keylock/files.keylock"

View File

@ -0,0 +1,5 @@
# $NetBSD: files.keylock,v 1.1 2009/08/14 21:17:22 mbalmer Exp $
defflag secmodel_keylock
file secmodel/keylock/secmodel_keylock.c secmodel_keylock

View File

@ -0,0 +1,51 @@
/* $NetBSD: keylock.h,v 1.1 2009/08/14 21:17:22 mbalmer Exp $ */
/*-
* Copyright (c) 2009 Marc Balmer <marc@msys.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SECMODEL_KEYLOCK_KEYLOCK_H_
#define _SECMODEL_KEYLOCK_KEYLOCK_H_
int secmodel_keylock_sysctl(SYSCTLFN_PROTO);
void secmodel_keylock_init(void);
void secmodel_keylock_start(void);
void secmodel_keylock_stop(void);
#if defined(_LKM)
SYSCTL_SETUP_PROTO(sysctl_security_keylock_setup);
#endif /* _LKM */
int secmodel_keylock_system_cb(kauth_cred_t, kauth_action_t, void *,
void *, void *, void *, void *);
int secmodel_keylock_process_cb(kauth_cred_t, kauth_action_t, void *,
void *, void *, void *, void *);
int secmodel_keylock_network_cb(kauth_cred_t, kauth_action_t, void *,
void *, void *, void *, void *);
int secmodel_keylock_machdep_cb(kauth_cred_t, kauth_action_t, void *,
void *, void *, void *, void *);
int secmodel_keylock_device_cb(kauth_cred_t, kauth_action_t, void *,
void *, void *, void *, void *);
#endif /* !_SECMODEL_KEYLOCK_KEYLOCK_H_ */

View File

@ -0,0 +1,548 @@
/* $NetBSD: secmodel_keylock.c,v 1.1 2009/08/14 21:17:22 mbalmer Exp $ */
/*-
* Copyright (c) 2009 Marc Balmer <marc@msys.ch>
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This file contains kauth(9) listeners needed to implement an experimental
* keylock based security scheme.
*
* The position of the keylock is a system-global indication on what
* operations are allowed or not. It affects all users, including root.
*
* Rules:
*
* - If the number of possible keylock positions is 0, assume there is no
* keylock present, do not dissallow any action, i.e. do nothing
*
* - If the number of possible keylock positions is greater than 0, but the
* current lock position is 0, assume tampering with the lock and forbid
* all actions.
*
* - If the lock is in the lowest position, assume the system is locked and
* forbid most actions.
*
* - If the lock is in the highest position, assume the system to be open and
* forbid nothing.
*
* - If the security.models.keylock.order sysctl is set to a value != 0,
* reverse this order.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: secmodel_keylock.c,v 1.1 2009/08/14 21:17:22 mbalmer Exp $");
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kauth.h>
#include <sys/conf.h>
#include <sys/keylock.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <miscfs/specfs/specdev.h>
#include <secmodel/keylock/keylock.h>
static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
SYSCTL_SETUP(sysctl_security_keylock_setup,
"sysctl security keylock setup")
{
const struct sysctlnode *rnode;
sysctl_createv(clog, 0, NULL, &rnode,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "security", NULL,
NULL, 0, NULL, 0,
CTL_SECURITY, CTL_EOL);
sysctl_createv(clog, 0, &rnode, &rnode,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "models", NULL,
NULL, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, &rnode, &rnode,
CTLFLAG_PERMANENT,
CTLTYPE_NODE, "keylock",
SYSCTL_DESCR("Keylock security model"),
NULL, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, &rnode, NULL,
CTLFLAG_PERMANENT,
CTLTYPE_STRING, "name", NULL,
NULL, 0, __UNCONST("Keylock"), 0,
CTL_CREATE, CTL_EOL);
}
void
secmodel_keylock_init(void)
{
}
void
secmodel_keylock_start(void)
{
l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
secmodel_keylock_system_cb, NULL);
l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
secmodel_keylock_process_cb, NULL);
l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
secmodel_keylock_network_cb, NULL);
l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
secmodel_keylock_machdep_cb, NULL);
l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
secmodel_keylock_device_cb, NULL);
}
void
secmodel_keylock_stop(void)
{
kauth_unlisten_scope(l_system);
kauth_unlisten_scope(l_process);
kauth_unlisten_scope(l_network);
kauth_unlisten_scope(l_machdep);
kauth_unlisten_scope(l_device);
}
/*
* kauth(9) listener
*
* Security model: Multi-position keylock
* Scope: System
* Responsibility: Keylock
*/
int
secmodel_keylock_system_cb(kauth_cred_t cred,
kauth_action_t action, void *cookie, void *arg0, void *arg1,
void *arg2, void *arg3)
{
int result;
enum kauth_system_req req;
int kstate;
kstate = keylock_state();
if (kstate == KEYLOCK_ABSENT)
return KAUTH_RESULT_DEFER;
else if (kstate == KEYLOCK_TAMPER)
return KAUTH_RESULT_DENY;
result = KAUTH_RESULT_DEFER;
req = (enum kauth_system_req)arg0;
switch (action) {
case KAUTH_SYSTEM_CHSYSFLAGS:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
case KAUTH_SYSTEM_TIME:
switch (req) {
case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
case KAUTH_REQ_SYSTEM_TIME_SYSTEM: {
struct timespec *ts = arg1;
struct timespec *delta = arg2;
/*
* Don't allow the time to be set forward so far it
* will wrap and become negative, thus allowing an
* attacker to bypass the next check below. The
* cutoff is 1 year before rollover occurs, so even
* if the attacker uses adjtime(2) to move the time
* past the cutoff, it will take a very long time
* to get to the wrap point.
*/
if (keylock_position() > 1 &&
((ts->tv_sec > LLONG_MAX - 365*24*60*60) ||
(delta->tv_sec < 0 || delta->tv_nsec < 0)))
result = KAUTH_RESULT_DENY;
break;
}
default:
break;
}
break;
case KAUTH_SYSTEM_MODULE:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
case KAUTH_SYSTEM_MOUNT:
switch (req) {
case KAUTH_REQ_SYSTEM_MOUNT_NEW:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
if (kstate == KEYLOCK_CLOSE) {
struct mount *mp = arg1;
u_long flags = (u_long)arg2;
/*
* Can only degrade from read/write to
* read-only.
*/
if (flags != (mp->mnt_flag | MNT_RDONLY |
MNT_RELOAD | MNT_FORCE | MNT_UPDATE))
result = KAUTH_RESULT_DENY;
}
break;
default:
break;
}
break;
case KAUTH_SYSTEM_SYSCTL:
switch (req) {
case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
break;
case KAUTH_SYSTEM_SETIDCORE:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
case KAUTH_SYSTEM_DEBUG:
switch (req) {
case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
break;
}
return result;
}
/*
* kauth(9) listener
*
* Security model: Multi-position keylock
* Scope: Process
* Responsibility: Keylock
*/
int
secmodel_keylock_process_cb(kauth_cred_t cred,
kauth_action_t action, void *cookie, void *arg0,
void *arg1, void *arg2, void *arg3)
{
struct proc *p;
int result, kstate;
kstate = keylock_state();
if (kstate == KEYLOCK_ABSENT)
return KAUTH_RESULT_DEFER;
else if (kstate == KEYLOCK_TAMPER)
return KAUTH_RESULT_DENY;
result = KAUTH_RESULT_DEFER;
p = arg0;
switch (action) {
case KAUTH_PROCESS_PROCFS: {
enum kauth_process_req req;
req = (enum kauth_process_req)arg2;
switch (req) {
case KAUTH_REQ_PROCESS_PROCFS_READ:
break;
case KAUTH_REQ_PROCESS_PROCFS_RW:
case KAUTH_REQ_PROCESS_PROCFS_WRITE:
if ((p == initproc) && (kstate != KEYLOCK_OPEN))
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
break;
}
case KAUTH_PROCESS_PTRACE:
if ((p == initproc) && (kstate != KEYLOCK_OPEN))
result = KAUTH_RESULT_DENY;
break;
case KAUTH_PROCESS_CORENAME:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
}
return result;
}
/*
* kauth(9) listener
*
* Security model: Multi-position keylock
* Scope: Network
* Responsibility: Keylock
*/
int
secmodel_keylock_network_cb(kauth_cred_t cred,
kauth_action_t action, void *cookie, void *arg0,
void *arg1, void *arg2, void *arg3)
{
int result, kstate;
enum kauth_network_req req;
kstate = keylock_state();
if (kstate == KEYLOCK_ABSENT)
return KAUTH_RESULT_DEFER;
else if (kstate == KEYLOCK_TAMPER)
return KAUTH_RESULT_DENY;
result = KAUTH_RESULT_DEFER;
req = (enum kauth_network_req)arg0;
switch (action) {
case KAUTH_NETWORK_FIREWALL:
switch (req) {
case KAUTH_REQ_NETWORK_FIREWALL_FW:
case KAUTH_REQ_NETWORK_FIREWALL_NAT:
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
break;
case KAUTH_NETWORK_FORWSRCRT:
if (kstate != KEYLOCK_OPEN)
result = KAUTH_RESULT_DENY;
break;
}
return result;
}
/*
* kauth(9) listener
*
* Security model: Multi-position keylock
* Scope: Machdep
* Responsibility: Keylock
*/
int
secmodel_keylock_machdep_cb(kauth_cred_t cred,
kauth_action_t action, void *cookie, void *arg0,
void *arg1, void *arg2, void *arg3)
{
int result, kstate;
kstate = keylock_state();
if (kstate == KEYLOCK_ABSENT)
return KAUTH_RESULT_DEFER;
else if (kstate == KEYLOCK_TAMPER)
return KAUTH_RESULT_DENY;
result = KAUTH_RESULT_DEFER;
switch (action) {
case KAUTH_MACHDEP_IOPERM_SET:
case KAUTH_MACHDEP_IOPL:
if (kstate != KEYLOCK_OPEN)
result = KAUTH_RESULT_DENY;
break;
case KAUTH_MACHDEP_UNMANAGEDMEM:
if (kstate != KEYLOCK_OPEN)
result = KAUTH_RESULT_DENY;
break;
}
return result;
}
/*
* kauth(9) listener
*
* Security model: Multi-position keylock
* Scope: Device
* Responsibility: Keylock
*/
int
secmodel_keylock_device_cb(kauth_cred_t cred,
kauth_action_t action, void *cookie, void *arg0,
void *arg1, void *arg2, void *arg3)
{
int result, kstate;
kstate = keylock_state();
if (kstate == KEYLOCK_ABSENT)
return KAUTH_RESULT_DEFER;
else if (kstate == KEYLOCK_TAMPER)
return KAUTH_RESULT_DENY;
result = KAUTH_RESULT_DEFER;
switch (action) {
case KAUTH_DEVICE_RAWIO_SPEC: {
struct vnode *vp, *bvp;
enum kauth_device_req req;
dev_t dev;
int d_type;
req = (enum kauth_device_req)arg0;
vp = arg1;
KASSERT(vp != NULL);
dev = vp->v_rdev;
d_type = D_OTHER;
bvp = NULL;
/* Handle /dev/mem and /dev/kmem. */
if ((vp->v_type == VCHR) && iskmemdev(dev)) {
switch (req) {
case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
break;
case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
if (kstate != KEYLOCK_OPEN)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
break;
}
switch (req) {
case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
break;
case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
switch (vp->v_type) {
case VCHR: {
const struct cdevsw *cdev;
cdev = cdevsw_lookup(dev);
if (cdev != NULL) {
dev_t blkdev;
blkdev = devsw_chr2blk(dev);
if (blkdev != NODEV) {
vfinddev(blkdev, VBLK, &bvp);
if (bvp != NULL)
d_type = (cdev->d_flag
& D_TYPEMASK);
}
}
break;
}
case VBLK: {
const struct bdevsw *bdev;
bdev = bdevsw_lookup(dev);
if (bdev != NULL)
d_type = (bdev->d_flag & D_TYPEMASK);
bvp = vp;
break;
}
default:
break;
}
if (d_type != D_DISK)
break;
/*
* XXX: This is bogus. We should be failing the request
* XXX: not only if this specific slice is mounted, but
* XXX: if it's on a disk with any other mounted slice.
*/
if (vfs_mountedon(bvp) && (kstate != KEYLOCK_OPEN))
break;
if (kstate == KEYLOCK_CLOSE)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
break;
}
case KAUTH_DEVICE_RAWIO_PASSTHRU:
if (kstate != KEYLOCK_OPEN) {
u_long bits;
bits = (u_long)arg0;
KASSERT(bits != 0);
KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL)
== 0);
if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
result = KAUTH_RESULT_DENY;
}
break;
case KAUTH_DEVICE_GPIO_PINSET:
if (kstate != KEYLOCK_OPEN)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}
return result;
}

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.118 2008/11/24 16:05:21 joerg Exp $
# $NetBSD: Makefile,v 1.119 2009/08/14 21:17:22 mbalmer Exp $
.include <bsd.sys.mk>
@ -17,7 +17,7 @@ INCS= acct.h agpio.h aio.h ansi.h ataio.h atomic.h audioio.h \
float_ieee754.h fstypes.h gcq.h gmon.h gpio.h hash.h \
ieee754.h inttypes.h ioccom.h ioctl.h ioctl_compat.h iostat.h ipc.h \
joystick.h \
kcore.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
kcore.h keylock.h kgdb.h kmem.h ksem.h ksyms.h ktrace.h \
localedef.h lock.h lockf.h lwp.h lwpctl.h \
malloc.h mallocvar.h mbuf.h md4.h md5.h midiio.h \
mman.h module.h mount.h mqueue.h msg.h msgbuf.h mtio.h mutex.h \

49
sys/sys/keylock.h Normal file
View File

@ -0,0 +1,49 @@
/* $NetBSD: keylock.h,v 1.1 2009/08/14 21:17:22 mbalmer Exp $ */
/*
* Copyright (c) 2009 Marc Balmer <marc@msys.ch>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SYS_KEYLOCK_H
#define _SYS_KEYLOCK_H
#define KEYLOCK_ABSENT 0
#define KEYLOCK_TAMPER 1
#define KEYLOCK_OPEN 2
#define KEYLOCK_SEMIOPEN 3
#define KEYLOCK_SEMICLOSE 4
#define KEYLOCK_CLOSE 5
#ifdef _KERNEL
/* Functions for keylock drivers */
extern int keylock_register(void *, int, int (*)(void *));
extern void keylock_unregister(void *, int (*)(void *));
/* Functions to query the keylock state */
extern int keylock_state(void);
extern int keylock_position(void);
extern int keylock_num_positions(void);
#endif
#endif /* _SYS_KEYLOCK_H */