1105464Sphk/*- 2105464Sphk * Copyright (c) 2002 Poul-Henning Kamp 3105464Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 4105464Sphk * All rights reserved. 5105464Sphk * 6105464Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7105464Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 8105464Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9105464Sphk * DARPA CHATS research program. 10105464Sphk * 11105464Sphk * Redistribution and use in source and binary forms, with or without 12105464Sphk * modification, are permitted provided that the following conditions 13105464Sphk * are met: 14105464Sphk * 1. Redistributions of source code must retain the above copyright 15105464Sphk * notice, this list of conditions and the following disclaimer. 16105464Sphk * 2. Redistributions in binary form must reproduce the above copyright 17105464Sphk * notice, this list of conditions and the following disclaimer in the 18105464Sphk * documentation and/or other materials provided with the distribution. 19105464Sphk * 20105464Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21105464Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22105464Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23105464Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24105464Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25105464Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26105464Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27105464Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28105464Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29105464Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30105464Sphk * SUCH DAMAGE. 31105464Sphk * 32105464Sphk * $FreeBSD$ 33105464Sphk * 34105464Sphk */ 35105464Sphk 36105464Sphk#include <sys/param.h> 37105464Sphk#include <sys/bio.h> 38105464Sphk#include <sys/lock.h> 39105464Sphk#include <sys/mutex.h> 40105464Sphk#include <sys/malloc.h> 41105464Sphk#include <sys/systm.h> 42105464Sphk#include <sys/kernel.h> 43105464Sphk#include <sys/kthread.h> 44219029Snetchild#include <sys/sysctl.h> 45105464Sphk 46143418Sume#include <crypto/rijndael/rijndael-api-fst.h> 47106407Sphk#include <crypto/sha2/sha2.h> 48106407Sphk#include <geom/geom.h> 49106407Sphk#include <geom/bde/g_bde.h> 50105464Sphk#define BDE_CLASS_NAME "BDE" 51105464Sphk 52219029SnetchildFEATURE(geom_bde, "GEOM-based Disk Encryption"); 53219029Snetchild 54105464Sphkstatic void 55105464Sphkg_bde_start(struct bio *bp) 56105464Sphk{ 57105464Sphk 58105464Sphk switch (bp->bio_cmd) { 59105464Sphk case BIO_DELETE: 60105464Sphk case BIO_READ: 61105464Sphk case BIO_WRITE: 62105464Sphk g_bde_start1(bp); 63105464Sphk break; 64105464Sphk case BIO_GETATTR: 65105464Sphk g_io_deliver(bp, EOPNOTSUPP); 66105464Sphk break; 67105464Sphk default: 68105464Sphk g_io_deliver(bp, EOPNOTSUPP); 69105464Sphk return; 70105464Sphk } 71105464Sphk return; 72105464Sphk} 73105464Sphk 74105464Sphkstatic void 75105464Sphkg_bde_orphan(struct g_consumer *cp) 76105464Sphk{ 77105464Sphk struct g_geom *gp; 78105464Sphk struct g_provider *pp; 79105464Sphk struct g_bde_softc *sc; 80105464Sphk 81105464Sphk g_trace(G_T_TOPOLOGY, "g_bde_orphan(%p/%s)", cp, cp->provider->name); 82105464Sphk g_topology_assert(); 83105464Sphk 84105464Sphk gp = cp->geom; 85105464Sphk sc = gp->softc; 86105464Sphk gp->flags |= G_GEOM_WITHER; 87105464Sphk LIST_FOREACH(pp, &gp->provider, provider) 88238198Strasz g_orphan_provider(pp, ENXIO); 89105464Sphk bzero(sc, sizeof(struct g_bde_softc)); /* destroy evidence */ 90105464Sphk return; 91105464Sphk} 92105464Sphk 93105464Sphkstatic int 94105464Sphkg_bde_access(struct g_provider *pp, int dr, int dw, int de) 95105464Sphk{ 96105464Sphk struct g_geom *gp; 97105464Sphk struct g_consumer *cp; 98105464Sphk 99105464Sphk gp = pp->geom; 100105464Sphk cp = LIST_FIRST(&gp->consumer); 101105464Sphk if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) { 102105464Sphk de++; 103105464Sphk dr++; 104105464Sphk } 105105464Sphk /* ... and let go of it on last close */ 106105464Sphk if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) { 107105464Sphk de--; 108105464Sphk dr--; 109105464Sphk } 110125755Sphk return (g_access(cp, dr, dw, de)); 111105464Sphk} 112105464Sphk 113115624Sphkstatic void 114112828Sphkg_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *pp) 115112828Sphk{ 116112828Sphk struct g_geom *gp; 117112828Sphk struct g_consumer *cp; 118112828Sphk struct g_bde_key *kp; 119112828Sphk int error, i; 120112828Sphk u_int sectorsize; 121112828Sphk off_t mediasize; 122112828Sphk struct g_bde_softc *sc; 123112828Sphk void *pass; 124112828Sphk void *key; 125112828Sphk 126112828Sphk g_trace(G_T_TOPOLOGY, "g_bde_create_geom(%s, %s)", mp->name, pp->name); 127112828Sphk g_topology_assert(); 128112828Sphk gp = NULL; 129112828Sphk 130112828Sphk 131112828Sphk gp = g_new_geomf(mp, "%s.bde", pp->name); 132112828Sphk cp = g_new_consumer(gp); 133112828Sphk g_attach(cp, pp); 134125755Sphk error = g_access(cp, 1, 1, 1); 135112828Sphk if (error) { 136112828Sphk g_detach(cp); 137112828Sphk g_destroy_consumer(cp); 138112828Sphk g_destroy_geom(gp); 139115624Sphk gctl_error(req, "could not access consumer"); 140125590Sphk return; 141112828Sphk } 142114720Sphk pass = NULL; 143114720Sphk key = NULL; 144114720Sphk do { 145114720Sphk pass = gctl_get_param(req, "pass", &i); 146114720Sphk if (pass == NULL || i != SHA512_DIGEST_LENGTH) { 147115624Sphk gctl_error(req, "No usable key presented"); 148114720Sphk break; 149114720Sphk } 150114720Sphk key = gctl_get_param(req, "key", &i); 151114720Sphk if (key != NULL && i != 16) { 152115624Sphk gctl_error(req, "Invalid key presented"); 153114720Sphk break; 154114720Sphk } 155112828Sphk sectorsize = cp->provider->sectorsize; 156112828Sphk mediasize = cp->provider->mediasize; 157112828Sphk sc = g_malloc(sizeof(struct g_bde_softc), M_WAITOK | M_ZERO); 158112828Sphk gp->softc = sc; 159112828Sphk sc->geom = gp; 160112828Sphk sc->consumer = cp; 161112828Sphk 162112828Sphk error = g_bde_decrypt_lock(sc, pass, key, 163112828Sphk mediasize, sectorsize, NULL); 164112828Sphk bzero(sc->sha2, sizeof sc->sha2); 165112828Sphk if (error) 166112828Sphk break; 167112828Sphk kp = &sc->key; 168112828Sphk 169112828Sphk /* Initialize helper-fields */ 170112828Sphk kp->keys_per_sector = kp->sectorsize / G_BDE_SKEYLEN; 171112828Sphk kp->zone_cont = kp->keys_per_sector * kp->sectorsize; 172112828Sphk kp->zone_width = kp->zone_cont + kp->sectorsize; 173112828Sphk kp->media_width = kp->sectorN - kp->sector0 - 174112828Sphk G_BDE_MAXKEYS * kp->sectorsize; 175112828Sphk 176112828Sphk /* Our external parameters */ 177112828Sphk sc->zone_cont = kp->zone_cont; 178112828Sphk sc->mediasize = g_bde_max_sector(kp); 179112828Sphk sc->sectorsize = kp->sectorsize; 180112828Sphk 181112828Sphk TAILQ_INIT(&sc->freelist); 182112828Sphk TAILQ_INIT(&sc->worklist); 183112828Sphk mtx_init(&sc->worklist_mutex, "g_bde_worklist", NULL, MTX_DEF); 184112828Sphk /* XXX: error check */ 185172836Sjulian kproc_create(g_bde_worker, gp, &sc->thread, 0, 0, 186112828Sphk "g_bde %s", gp->name); 187243333Sjh pp = g_new_providerf(gp, "%s", gp->name); 188112828Sphk pp->stripesize = kp->zone_cont; 189112828Sphk pp->stripeoffset = 0; 190112828Sphk pp->mediasize = sc->mediasize; 191112828Sphk pp->sectorsize = sc->sectorsize; 192112828Sphk g_error_provider(pp, 0); 193112828Sphk break; 194114720Sphk } while (0); 195115624Sphk if (pass != NULL) 196114720Sphk bzero(pass, SHA512_DIGEST_LENGTH); 197115624Sphk if (key != NULL) 198114720Sphk bzero(key, 16); 199115624Sphk if (error == 0) 200115624Sphk return; 201125755Sphk g_access(cp, -1, -1, -1); 202112828Sphk g_detach(cp); 203112828Sphk g_destroy_consumer(cp); 204112828Sphk if (gp->softc != NULL) 205112828Sphk g_free(gp->softc); 206112828Sphk g_destroy_geom(gp); 207115624Sphk return; 208112828Sphk} 209112828Sphk 210112828Sphk 211112828Sphkstatic int 212112828Sphkg_bde_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) 213112828Sphk{ 214112828Sphk struct g_consumer *cp; 215112828Sphk struct g_provider *pp; 216112828Sphk struct g_bde_softc *sc; 217112828Sphk 218112828Sphk g_trace(G_T_TOPOLOGY, "g_bde_destroy_geom(%s, %s)", mp->name, gp->name); 219112828Sphk g_topology_assert(); 220112828Sphk /* 221112828Sphk * Orderly detachment. 222112828Sphk */ 223112828Sphk KASSERT(gp != NULL, ("NULL geom")); 224112828Sphk pp = LIST_FIRST(&gp->provider); 225112828Sphk KASSERT(pp != NULL, ("NULL provider")); 226112828Sphk if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) 227112828Sphk return (EBUSY); 228112828Sphk sc = gp->softc; 229112828Sphk cp = LIST_FIRST(&gp->consumer); 230112828Sphk KASSERT(cp != NULL, ("NULL consumer")); 231112828Sphk sc->dead = 1; 232112828Sphk wakeup(sc); 233125803Sphk g_access(cp, -1, -1, -1); 234112828Sphk g_detach(cp); 235112828Sphk g_destroy_consumer(cp); 236112828Sphk while (sc->dead != 2 && !LIST_EMPTY(&pp->consumers)) 237112828Sphk tsleep(sc, PRIBIO, "g_bdedie", hz); 238112828Sphk mtx_destroy(&sc->worklist_mutex); 239112828Sphk bzero(&sc->key, sizeof sc->key); 240112828Sphk g_free(sc); 241115624Sphk g_wither_geom(gp, ENXIO); 242112828Sphk return (0); 243112828Sphk} 244112828Sphk 245115624Sphkstatic void 246115624Sphkg_bde_ctlreq(struct gctl_req *req, struct g_class *mp, char const *verb) 247115624Sphk{ 248115624Sphk struct g_geom *gp; 249115624Sphk struct g_provider *pp; 250115624Sphk 251115624Sphk if (!strcmp(verb, "create geom")) { 252115624Sphk pp = gctl_get_provider(req, "provider"); 253115624Sphk if (pp != NULL) 254115624Sphk g_bde_create_geom(req, mp, pp); 255115624Sphk } else if (!strcmp(verb, "destroy geom")) { 256115624Sphk gp = gctl_get_geom(req, mp, "geom"); 257115624Sphk if (gp != NULL) 258115624Sphk g_bde_destroy_geom(req, mp, gp); 259115624Sphk } else { 260115624Sphk gctl_error(req, "unknown verb"); 261115624Sphk } 262115624Sphk} 263115624Sphk 264105464Sphkstatic struct g_class g_bde_class = { 265112552Sphk .name = BDE_CLASS_NAME, 266133318Sphk .version = G_VERSION, 267112828Sphk .destroy_geom = g_bde_destroy_geom, 268115624Sphk .ctlreq = g_bde_ctlreq, 269133314Sphk .start = g_bde_start, 270133314Sphk .orphan = g_bde_orphan, 271133314Sphk .access = g_bde_access, 272133314Sphk .spoiled = g_std_spoiled, 273105464Sphk}; 274105464Sphk 275105464SphkDECLARE_GEOM_CLASS(g_bde_class, g_bde); 276