g_bde.c revision 112828
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: head/sys/geom/bde/g_bde.c 112828 2003-03-29 22:14:21Z phk $ 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> 44105464Sphk 45106407Sphk#include <crypto/rijndael/rijndael.h> 46106407Sphk#include <crypto/sha2/sha2.h> 47106407Sphk#include <geom/geom.h> 48106407Sphk#include <geom/bde/g_bde.h> 49105464Sphk#define BDE_CLASS_NAME "BDE" 50105464Sphk 51105464Sphkstatic void 52105464Sphkg_bde_start(struct bio *bp) 53105464Sphk{ 54105464Sphk struct g_geom *gp; 55105464Sphk struct g_consumer *cp; 56105464Sphk struct g_bde_softc *sc; 57105464Sphk 58105464Sphk gp = bp->bio_to->geom; 59105464Sphk cp = LIST_FIRST(&gp->consumer); 60105464Sphk sc = gp->softc; 61105464Sphk switch (bp->bio_cmd) { 62105464Sphk case BIO_DELETE: 63105464Sphk case BIO_READ: 64105464Sphk case BIO_WRITE: 65105464Sphk g_bde_start1(bp); 66105464Sphk break; 67105464Sphk case BIO_GETATTR: 68105464Sphk case BIO_SETATTR: 69105464Sphk g_io_deliver(bp, EOPNOTSUPP); 70105464Sphk break; 71105464Sphk default: 72105464Sphk g_io_deliver(bp, EOPNOTSUPP); 73105464Sphk return; 74105464Sphk } 75105464Sphk return; 76105464Sphk} 77105464Sphk 78105464Sphkstatic void 79105464Sphkg_bde_orphan(struct g_consumer *cp) 80105464Sphk{ 81105464Sphk struct g_geom *gp; 82105464Sphk struct g_provider *pp; 83105464Sphk struct g_bde_softc *sc; 84105464Sphk int error; 85105464Sphk 86105464Sphk g_trace(G_T_TOPOLOGY, "g_bde_orphan(%p/%s)", cp, cp->provider->name); 87105464Sphk g_topology_assert(); 88105464Sphk KASSERT(cp->provider->error != 0, 89105464Sphk ("g_bde_orphan with error == 0")); 90105464Sphk 91105464Sphk gp = cp->geom; 92105464Sphk sc = gp->softc; 93105464Sphk gp->flags |= G_GEOM_WITHER; 94105464Sphk error = cp->provider->error; 95105464Sphk LIST_FOREACH(pp, &gp->provider, provider) 96105464Sphk g_orphan_provider(pp, error); 97105464Sphk bzero(sc, sizeof(struct g_bde_softc)); /* destroy evidence */ 98105464Sphk return; 99105464Sphk} 100105464Sphk 101105464Sphkstatic int 102105464Sphkg_bde_access(struct g_provider *pp, int dr, int dw, int de) 103105464Sphk{ 104105464Sphk struct g_geom *gp; 105105464Sphk struct g_consumer *cp; 106105464Sphk 107105464Sphk gp = pp->geom; 108105464Sphk cp = LIST_FIRST(&gp->consumer); 109105464Sphk if (cp->acr == 0 && cp->acw == 0 && cp->ace == 0) { 110105464Sphk de++; 111105464Sphk dr++; 112105464Sphk } 113105464Sphk /* ... and let go of it on last close */ 114105464Sphk if ((cp->acr + dr) == 0 && (cp->acw + dw) == 0 && (cp->ace + de) == 1) { 115105464Sphk de--; 116105464Sphk dr--; 117105464Sphk } 118105464Sphk return (g_access_rel(cp, dr, dw, de)); 119105464Sphk} 120105464Sphk 121105464Sphkstatic int 122112828Sphkg_bde_create_geom(struct gctl_req *req, struct g_class *mp, struct g_provider *pp) 123112828Sphk{ 124112828Sphk struct g_geom *gp; 125112828Sphk struct g_consumer *cp; 126112828Sphk struct g_bde_key *kp; 127112828Sphk int error, i; 128112828Sphk u_int sectorsize; 129112828Sphk off_t mediasize; 130112828Sphk struct g_bde_softc *sc; 131112828Sphk void *pass; 132112828Sphk void *key; 133112828Sphk 134112828Sphk if (pp == NULL) 135112828Sphk return (gctl_error(req, "Provider needed")); 136112828Sphk g_trace(G_T_TOPOLOGY, "g_bde_create_geom(%s, %s)", mp->name, pp->name); 137112828Sphk g_topology_assert(); 138112828Sphk gp = NULL; 139112828Sphk 140112828Sphk pass = gctl_get_param(req, "pass", &i); 141112828Sphk if (pass == NULL || i != SHA512_DIGEST_LENGTH) { 142112828Sphk if (pass != NULL) { 143112828Sphk bzero(pass, i); 144112828Sphk g_free(pass); 145112828Sphk } 146112828Sphk return (gctl_error(req, "No usable key presented")); 147112828Sphk } 148112828Sphk key = gctl_get_param(req, "key", &i); 149112828Sphk if (key != NULL && i != 16) { 150112828Sphk bzero(key, i); 151112828Sphk bzero(pass, SHA512_DIGEST_LENGTH); 152112828Sphk g_free(pass); 153112828Sphk g_free(key); 154112828Sphk return (gctl_error(req, "Invalid key presented")); 155112828Sphk } 156112828Sphk 157112828Sphk gp = g_new_geomf(mp, "%s.bde", pp->name); 158112828Sphk gp->start = g_bde_start; 159112828Sphk gp->orphan = g_bde_orphan; 160112828Sphk gp->access = g_bde_access; 161112828Sphk gp->spoiled = g_std_spoiled; 162112828Sphk cp = g_new_consumer(gp); 163112828Sphk g_attach(cp, pp); 164112828Sphk error = g_access_rel(cp, 1, 1, 1); 165112828Sphk if (error) { 166112828Sphk g_detach(cp); 167112828Sphk g_destroy_consumer(cp); 168112828Sphk g_destroy_geom(gp); 169112828Sphk return (error); 170112828Sphk } 171112828Sphk g_topology_unlock(); 172112828Sphk g_waitidle(); 173112828Sphk while (1) { 174112828Sphk sectorsize = cp->provider->sectorsize; 175112828Sphk mediasize = cp->provider->mediasize; 176112828Sphk sc = g_malloc(sizeof(struct g_bde_softc), M_WAITOK | M_ZERO); 177112828Sphk gp->softc = sc; 178112828Sphk sc->geom = gp; 179112828Sphk sc->consumer = cp; 180112828Sphk 181112828Sphk error = g_bde_decrypt_lock(sc, pass, key, 182112828Sphk mediasize, sectorsize, NULL); 183112828Sphk bzero(pass, SHA512_DIGEST_LENGTH); 184112828Sphk if (key != NULL) 185112828Sphk bzero(key, 16); 186112828Sphk bzero(sc->sha2, sizeof sc->sha2); 187112828Sphk if (error) 188112828Sphk break; 189112828Sphk kp = &sc->key; 190112828Sphk 191112828Sphk /* Initialize helper-fields */ 192112828Sphk kp->keys_per_sector = kp->sectorsize / G_BDE_SKEYLEN; 193112828Sphk kp->zone_cont = kp->keys_per_sector * kp->sectorsize; 194112828Sphk kp->zone_width = kp->zone_cont + kp->sectorsize; 195112828Sphk kp->media_width = kp->sectorN - kp->sector0 - 196112828Sphk G_BDE_MAXKEYS * kp->sectorsize; 197112828Sphk 198112828Sphk /* Our external parameters */ 199112828Sphk sc->zone_cont = kp->zone_cont; 200112828Sphk sc->mediasize = g_bde_max_sector(kp); 201112828Sphk sc->sectorsize = kp->sectorsize; 202112828Sphk 203112828Sphk TAILQ_INIT(&sc->freelist); 204112828Sphk TAILQ_INIT(&sc->worklist); 205112828Sphk mtx_init(&sc->worklist_mutex, "g_bde_worklist", NULL, MTX_DEF); 206112828Sphk mtx_lock(&Giant); 207112828Sphk /* XXX: error check */ 208112828Sphk kthread_create(g_bde_worker, gp, &sc->thread, 0, 0, 209112828Sphk "g_bde %s", gp->name); 210112828Sphk mtx_unlock(&Giant); 211112828Sphk g_topology_lock(); 212112828Sphk pp = g_new_providerf(gp, gp->name); 213112828Sphk pp->flags |= G_PF_CANDELETE; 214112828Sphk pp->stripesize = kp->zone_cont; 215112828Sphk pp->stripeoffset = 0; 216112828Sphk pp->mediasize = sc->mediasize; 217112828Sphk pp->sectorsize = sc->sectorsize; 218112828Sphk g_error_provider(pp, 0); 219112828Sphk g_topology_unlock(); 220112828Sphk break; 221112828Sphk } 222112828Sphk g_topology_lock(); 223112828Sphk if (error == 0) { 224112828Sphk return (0); 225112828Sphk } else { 226112828Sphk g_access_rel(cp, -1, -1, -1); 227112828Sphk } 228112828Sphk g_detach(cp); 229112828Sphk g_destroy_consumer(cp); 230112828Sphk if (gp->softc != NULL) 231112828Sphk g_free(gp->softc); 232112828Sphk g_destroy_geom(gp); 233112828Sphk return (error); 234112828Sphk} 235112828Sphk 236112828Sphk 237112828Sphkstatic int 238112828Sphkg_bde_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) 239112828Sphk{ 240112828Sphk struct g_consumer *cp; 241112828Sphk struct g_provider *pp; 242112828Sphk int error; 243112828Sphk struct g_bde_softc *sc; 244112828Sphk 245112828Sphk g_trace(G_T_TOPOLOGY, "g_bde_destroy_geom(%s, %s)", mp->name, gp->name); 246112828Sphk g_topology_assert(); 247112828Sphk /* 248112828Sphk * Orderly detachment. 249112828Sphk */ 250112828Sphk KASSERT(gp != NULL, ("NULL geom")); 251112828Sphk pp = LIST_FIRST(&gp->provider); 252112828Sphk KASSERT(pp != NULL, ("NULL provider")); 253112828Sphk if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) 254112828Sphk return (EBUSY); 255112828Sphk g_orphan_provider(pp, ENXIO); 256112828Sphk sc = gp->softc; 257112828Sphk cp = LIST_FIRST(&gp->consumer); 258112828Sphk KASSERT(cp != NULL, ("NULL consumer")); 259112828Sphk sc->dead = 1; 260112828Sphk wakeup(sc); 261112828Sphk error = g_access_rel(cp, -1, -1, -1); 262112828Sphk KASSERT(error == 0, ("error on close")); 263112828Sphk g_detach(cp); 264112828Sphk g_destroy_consumer(cp); 265112828Sphk g_topology_unlock(); 266112828Sphk while (sc->dead != 2 && !LIST_EMPTY(&pp->consumers)) 267112828Sphk tsleep(sc, PRIBIO, "g_bdedie", hz); 268112828Sphk g_waitidle(); 269112828Sphk g_topology_lock(); 270112828Sphk g_destroy_provider(pp); 271112828Sphk mtx_destroy(&sc->worklist_mutex); 272112828Sphk bzero(&sc->key, sizeof sc->key); 273112828Sphk g_free(sc); 274112828Sphk g_destroy_geom(gp); 275112828Sphk return (0); 276112828Sphk} 277112828Sphk 278112828Sphkstatic int 279106518Sphkg_bde_config(struct g_configargs *ga) 280105464Sphk{ 281105464Sphk struct g_geom *gp; 282105464Sphk struct g_consumer *cp; 283105464Sphk struct g_provider *pp; 284105464Sphk struct g_bde_key *kp; 285105464Sphk int error; 286105464Sphk u_int sectorsize; 287105464Sphk off_t mediasize; 288105464Sphk struct g_bde_softc *sc; 289105464Sphk 290106518Sphk g_trace(G_T_TOPOLOGY, "g_bde_config(%d)", ga->flag); 291105464Sphk g_topology_assert(); 292105465Sphk gp = NULL; 293106518Sphk if (ga->flag == GCFG_DISMANTLE) { 294105464Sphk /* 295107831Sphk * Orderly detachment. 296105464Sphk */ 297105464Sphk if (ga->geom != NULL) { 298105464Sphk gp = ga->geom; 299105464Sphk } else if (ga->provider != NULL) { 300105464Sphk if (ga->provider->geom->class == ga->class) { 301105464Sphk gp = ga->provider->geom; 302105464Sphk } else { 303105464Sphk LIST_FOREACH(cp, &ga->provider->consumers, 304105464Sphk consumers) { 305105464Sphk if (cp->geom->class == ga->class) { 306105464Sphk gp = cp->geom; 307105464Sphk break; 308105464Sphk } 309105464Sphk } 310105464Sphk } 311105464Sphk if (gp == NULL) 312105464Sphk return (EINVAL); 313105464Sphk } else { 314105464Sphk return (EINVAL); 315105464Sphk } 316105464Sphk KASSERT(gp != NULL, ("NULL geom")); 317105464Sphk pp = LIST_FIRST(&gp->provider); 318105464Sphk KASSERT(pp != NULL, ("NULL provider")); 319105464Sphk if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) 320105464Sphk return (EBUSY); 321105464Sphk g_orphan_provider(pp, ENXIO); 322105464Sphk sc = gp->softc; 323105464Sphk cp = LIST_FIRST(&gp->consumer); 324105464Sphk KASSERT(cp != NULL, ("NULL consumer")); 325105464Sphk sc->dead = 1; 326105464Sphk wakeup(sc); 327105464Sphk error = g_access_rel(cp, -1, -1, -1); 328105464Sphk KASSERT(error == 0, ("error on close")); 329105464Sphk g_detach(cp); 330105464Sphk g_destroy_consumer(cp); 331105464Sphk g_topology_unlock(); 332105464Sphk while (sc->dead != 2 && !LIST_EMPTY(&pp->consumers)) 333105464Sphk tsleep(sc, PRIBIO, "g_bdedie", hz); 334106407Sphk g_waitidle(); 335105464Sphk g_topology_lock(); 336105464Sphk g_destroy_provider(pp); 337105464Sphk mtx_destroy(&sc->worklist_mutex); 338105464Sphk bzero(&sc->key, sizeof sc->key); 339105464Sphk g_free(sc); 340105464Sphk g_destroy_geom(gp); 341105464Sphk return (0); 342105464Sphk } 343105464Sphk 344106518Sphk if (ga->flag != GCFG_CREATE) 345105464Sphk return (EOPNOTSUPP); 346105464Sphk 347105464Sphk if (ga->provider == NULL) 348105464Sphk return (EINVAL); 349105464Sphk /* 350105464Sphk * Attach 351105464Sphk */ 352105464Sphk gp = g_new_geomf(ga->class, "%s.bde", ga->provider->name); 353105464Sphk gp->start = g_bde_start; 354105464Sphk gp->orphan = g_bde_orphan; 355105464Sphk gp->access = g_bde_access; 356105464Sphk gp->spoiled = g_std_spoiled; 357105464Sphk cp = g_new_consumer(gp); 358105464Sphk g_attach(cp, ga->provider); 359105464Sphk error = g_access_rel(cp, 1, 1, 1); 360105464Sphk if (error) { 361105464Sphk g_detach(cp); 362105464Sphk g_destroy_consumer(cp); 363105464Sphk g_destroy_geom(gp); 364105464Sphk return (error); 365105464Sphk } 366105464Sphk g_topology_unlock(); 367106407Sphk g_waitidle(); 368105464Sphk while (1) { 369105551Sphk sectorsize = cp->provider->sectorsize; 370105551Sphk mediasize = cp->provider->mediasize; 371111119Simp sc = g_malloc(sizeof(struct g_bde_softc), M_WAITOK | M_ZERO); 372105464Sphk gp->softc = sc; 373105464Sphk sc->geom = gp; 374105464Sphk sc->consumer = cp; 375105464Sphk 376105464Sphk error = g_bde_decrypt_lock(sc, ga->ptr, 377106407Sphk (u_char *)ga->ptr + (sizeof sc->sha2), 378106407Sphk mediasize, sectorsize, NULL); 379106407Sphk bzero(sc->sha2, sizeof sc->sha2); 380105464Sphk if (error) 381105464Sphk break; 382105464Sphk kp = &sc->key; 383105464Sphk 384105464Sphk /* Initialize helper-fields */ 385105464Sphk kp->keys_per_sector = kp->sectorsize / G_BDE_SKEYLEN; 386105464Sphk kp->zone_cont = kp->keys_per_sector * kp->sectorsize; 387105464Sphk kp->zone_width = kp->zone_cont + kp->sectorsize; 388105464Sphk kp->media_width = kp->sectorN - kp->sector0 - 389105464Sphk G_BDE_MAXKEYS * kp->sectorsize; 390105464Sphk 391105464Sphk /* Our external parameters */ 392105464Sphk sc->zone_cont = kp->zone_cont; 393105464Sphk sc->mediasize = g_bde_max_sector(kp); 394105464Sphk sc->sectorsize = kp->sectorsize; 395105464Sphk 396105464Sphk TAILQ_INIT(&sc->freelist); 397105464Sphk TAILQ_INIT(&sc->worklist); 398105464Sphk mtx_init(&sc->worklist_mutex, "g_bde_worklist", NULL, MTX_DEF); 399105464Sphk mtx_lock(&Giant); 400105464Sphk /* XXX: error check */ 401105464Sphk kthread_create(g_bde_worker, gp, &sc->thread, 0, 0, 402105464Sphk "g_bde %s", gp->name); 403105464Sphk mtx_unlock(&Giant); 404105464Sphk g_topology_lock(); 405105464Sphk pp = g_new_providerf(gp, gp->name); 406110697Sphk pp->flags |= G_PF_CANDELETE; 407110712Sphk pp->stripesize = kp->zone_cont; 408110712Sphk pp->stripeoffset = 0; 409105464Sphk pp->mediasize = sc->mediasize; 410105542Sphk pp->sectorsize = sc->sectorsize; 411105464Sphk g_error_provider(pp, 0); 412105464Sphk g_topology_unlock(); 413105464Sphk break; 414105464Sphk } 415105464Sphk g_topology_lock(); 416105464Sphk if (error == 0) { 417105464Sphk ga->geom = gp; 418105464Sphk return (0); 419105464Sphk } else { 420105464Sphk g_access_rel(cp, -1, -1, -1); 421105464Sphk } 422105464Sphk g_detach(cp); 423105464Sphk g_destroy_consumer(cp); 424105464Sphk if (gp->softc != NULL) 425105464Sphk g_free(gp->softc); 426105464Sphk g_destroy_geom(gp); 427105464Sphk return (error); 428105464Sphk} 429105464Sphk 430105464Sphkstatic struct g_class g_bde_class = { 431112552Sphk .name = BDE_CLASS_NAME, 432112552Sphk .config = g_bde_config, 433112828Sphk .create_geom = g_bde_create_geom, 434112828Sphk .destroy_geom = g_bde_destroy_geom, 435105464Sphk G_CLASS_INITIALIZER 436105464Sphk}; 437105464Sphk 438105464SphkDECLARE_GEOM_CLASS(g_bde_class, g_bde); 439