1 /* $NetBSD: cgd.c,v 1.29 2005/08/20 12:03:52 yamt Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Roland C. Dowdeswell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.29 2005/08/20 12:03:52 yamt Exp $"); 41 42 #include <sys/types.h> 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/errno.h> 47 #include <sys/buf.h> 48 #include <sys/bufq.h> 49 #include <sys/malloc.h> 50 #include <sys/pool.h> 51 #include <sys/ioctl.h> 52 #include <sys/device.h> 53 #include <sys/disk.h> 54 #include <sys/disklabel.h> 55 #include <sys/fcntl.h> 56 #include <sys/vnode.h> 57 #include <sys/lock.h> 58 #include <sys/conf.h> 59 60 #include <dev/dkvar.h> 61 #include <dev/cgdvar.h> 62 63 /* Entry Point Functions */ 64 65 void cgdattach(int); 66 67 static dev_type_open(cgdopen); 68 static dev_type_close(cgdclose); 69 static dev_type_read(cgdread); 70 static dev_type_write(cgdwrite); 71 static dev_type_ioctl(cgdioctl); 72 static dev_type_strategy(cgdstrategy); 73 static dev_type_dump(cgddump); 74 static dev_type_size(cgdsize); 75 76 const struct bdevsw cgd_bdevsw = { 77 cgdopen, cgdclose, cgdstrategy, cgdioctl, 78 cgddump, cgdsize, D_DISK 79 }; 80 81 const struct cdevsw cgd_cdevsw = { 82 cgdopen, cgdclose, cgdread, cgdwrite, cgdioctl, 83 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 84 }; 85 86 /* Internal Functions */ 87 88 static int cgdstart(struct dk_softc *, struct buf *); 89 static void cgdiodone(struct buf *); 90 91 static int cgd_ioctl_set(struct cgd_softc *, void *, struct proc *); 92 static int cgd_ioctl_clr(struct cgd_softc *, void *, struct proc *); 93 static int cgdinit(struct cgd_softc *, const char *, struct vnode *, 94 struct proc *); 95 static void cgd_cipher(struct cgd_softc *, caddr_t, caddr_t, 96 size_t, daddr_t, size_t, int); 97 98 /* Pseudo-disk Interface */ 99 100 static struct dk_intf the_dkintf = { 101 DTYPE_CGD, 102 "cgd", 103 cgdopen, 104 cgdclose, 105 cgdstrategy, 106 cgdstart, 107 }; 108 static struct dk_intf *di = &the_dkintf; 109 110 static struct dkdriver cgddkdriver = { 111 .d_strategy = cgdstrategy, 112 .d_minphys = minphys, 113 }; 114 115 /* DIAGNOSTIC and DEBUG definitions */ 116 117 #if defined(CGDDEBUG) && !defined(DEBUG) 118 #define DEBUG 119 #endif 120 121 #ifdef DEBUG 122 int cgddebug = 0; 123 124 #define CGDB_FOLLOW 0x1 125 #define CGDB_IO 0x2 126 #define CGDB_CRYPTO 0x4 127 128 #define IFDEBUG(x,y) if (cgddebug & (x)) y 129 #define DPRINTF(x,y) IFDEBUG(x, printf y) 130 #define DPRINTF_FOLLOW(y) DPRINTF(CGDB_FOLLOW, y) 131 132 static void hexprint(const char *, void *, int); 133 134 #else 135 #define IFDEBUG(x,y) 136 #define DPRINTF(x,y) 137 #define DPRINTF_FOLLOW(y) 138 #endif 139 140 #ifdef DIAGNOSTIC 141 #define DIAGPANIC(x) panic x 142 #define DIAGCONDPANIC(x,y) if (x) panic y 143 #else 144 #define DIAGPANIC(x) 145 #define DIAGCONDPANIC(x,y) 146 #endif 147 148 /* Global variables */ 149 150 struct cgd_softc *cgd_softc; 151 int numcgd = 0; 152 153 /* Utility Functions */ 154 155 #define CGDUNIT(x) DISKUNIT(x) 156 #define GETCGD_SOFTC(_cs, x) if (!((_cs) = getcgd_softc(x))) return ENXIO 157 158 static struct cgd_softc * 159 getcgd_softc(dev_t dev) 160 { 161 int unit = CGDUNIT(dev); 162 163 DPRINTF_FOLLOW(("getcgd_softc(0x%x): unit = %d\n", dev, unit)); 164 if (unit >= numcgd) 165 return NULL; 166 return &cgd_softc[unit]; 167 } 168 169 /* The code */ 170 171 static void 172 cgdsoftc_init(struct cgd_softc *cs, int num) 173 { 174 char sbuf[DK_XNAME_SIZE]; 175 176 memset(cs, 0x0, sizeof(*cs)); 177 snprintf(sbuf, DK_XNAME_SIZE, "cgd%d", num); 178 simple_lock_init(&cs->sc_slock); 179 dk_sc_init(&cs->sc_dksc, cs, sbuf); 180 cs->sc_dksc.sc_dkdev.dk_driver = &cgddkdriver; 181 pseudo_disk_init(&cs->sc_dksc.sc_dkdev); 182 } 183 184 void 185 cgdattach(int num) 186 { 187 int i; 188 189 DPRINTF_FOLLOW(("cgdattach(%d)\n", num)); 190 if (num <= 0) { 191 DIAGPANIC(("cgdattach: count <= 0")); 192 return; 193 } 194 195 cgd_softc = (void *)malloc(num * sizeof(*cgd_softc), M_DEVBUF, M_NOWAIT); 196 if (!cgd_softc) { 197 printf("WARNING: unable to malloc(9) memory for crypt disks\n"); 198 DIAGPANIC(("cgdattach: cannot malloc(9) enough memory")); 199 return; 200 } 201 202 numcgd = num; 203 for (i=0; i<num; i++) 204 cgdsoftc_init(&cgd_softc[i], i); 205 } 206 207 static int 208 cgdopen(dev_t dev, int flags, int fmt, struct proc *p) 209 { 210 struct cgd_softc *cs; 211 212 DPRINTF_FOLLOW(("cgdopen(%d, %d)\n", dev, flags)); 213 GETCGD_SOFTC(cs, dev); 214 return dk_open(di, &cs->sc_dksc, dev, flags, fmt, p); 215 } 216 217 static int 218 cgdclose(dev_t dev, int flags, int fmt, struct proc *p) 219 { 220 struct cgd_softc *cs; 221 222 DPRINTF_FOLLOW(("cgdclose(%d, %d)\n", dev, flags)); 223 GETCGD_SOFTC(cs, dev); 224 return dk_close(di, &cs->sc_dksc, dev, flags, fmt, p); 225 } 226 227 static void 228 cgdstrategy(struct buf *bp) 229 { 230 struct cgd_softc *cs = getcgd_softc(bp->b_dev); 231 232 DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n", bp, 233 (long)bp->b_bcount)); 234 /* XXXrcd: Should we test for (cs != NULL)? */ 235 dk_strategy(di, &cs->sc_dksc, bp); 236 return; 237 } 238 239 static int 240 cgdsize(dev_t dev) 241 { 242 struct cgd_softc *cs = getcgd_softc(dev); 243 244 DPRINTF_FOLLOW(("cgdsize(%d)\n", dev)); 245 if (!cs) 246 return -1; 247 return dk_size(di, &cs->sc_dksc, dev); 248 } 249 250 /* 251 * cgd_{get,put}data are functions that deal with getting a buffer 252 * for the new encrypted data. We have a buffer per device so that 253 * we can ensure that we can always have a transaction in flight. 254 * We use this buffer first so that we have one less piece of 255 * malloc'ed data at any given point. 256 */ 257 258 static void * 259 cgd_getdata(struct dk_softc *dksc, unsigned long size) 260 { 261 struct cgd_softc *cs =dksc->sc_osc; 262 caddr_t data = NULL; 263 264 simple_lock(&cs->sc_slock); 265 if (cs->sc_data_used == 0) { 266 cs->sc_data_used = 1; 267 data = cs->sc_data; 268 } 269 simple_unlock(&cs->sc_slock); 270 271 if (data) 272 return data; 273 274 return malloc(size, M_DEVBUF, M_NOWAIT); 275 } 276 277 static void 278 cgd_putdata(struct dk_softc *dksc, caddr_t data) 279 { 280 struct cgd_softc *cs =dksc->sc_osc; 281 282 if (data == cs->sc_data) { 283 simple_lock(&cs->sc_slock); 284 cs->sc_data_used = 0; 285 simple_unlock(&cs->sc_slock); 286 } else { 287 free(data, M_DEVBUF); 288 } 289 } 290 291 static int 292 cgdstart(struct dk_softc *dksc, struct buf *bp) 293 { 294 struct cgd_softc *cs = dksc->sc_osc; 295 struct buf *nbp; 296 struct partition *pp; 297 caddr_t addr; 298 caddr_t newaddr; 299 daddr_t bn; 300 int s; 301 302 DPRINTF_FOLLOW(("cgdstart(%p, %p)\n", dksc, bp)); 303 disk_busy(&dksc->sc_dkdev); /* XXX: put in dksubr.c */ 304 305 /* XXXrcd: 306 * Translate partition relative blocks to absolute blocks, 307 * this probably belongs (somehow) in dksubr.c, since it 308 * is independant of the underlying code... This will require 309 * that the interface be expanded slightly, though. 310 */ 311 bn = bp->b_blkno; 312 if (DISKPART(bp->b_dev) != RAW_PART) { 313 pp = &cs->sc_dksc.sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)]; 314 bn += pp->p_offset; 315 } 316 317 /* 318 * We attempt to allocate all of our resources up front, so that 319 * we can fail quickly if they are unavailable. 320 */ 321 322 s = splbio(); 323 nbp = pool_get(&bufpool, PR_NOWAIT); 324 splx(s); 325 if (nbp == NULL) { 326 disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ)); 327 return -1; 328 } 329 330 /* 331 * If we are writing, then we need to encrypt the outgoing 332 * block into a new block of memory. If we fail, then we 333 * return an error and let the dksubr framework deal with it. 334 */ 335 newaddr = addr = bp->b_data; 336 if ((bp->b_flags & B_READ) == 0) { 337 newaddr = cgd_getdata(dksc, bp->b_bcount); 338 if (!newaddr) { 339 s = splbio(); 340 pool_put(&bufpool, nbp); 341 splx(s); 342 disk_unbusy(&dksc->sc_dkdev, 0, (bp->b_flags & B_READ)); 343 return -1; 344 } 345 cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn, 346 DEV_BSIZE, CGD_CIPHER_ENCRYPT); 347 } 348 349 BUF_INIT(nbp); 350 nbp->b_data = newaddr; 351 nbp->b_flags = bp->b_flags | B_CALL; 352 nbp->b_iodone = cgdiodone; 353 nbp->b_proc = bp->b_proc; 354 nbp->b_blkno = bn; 355 nbp->b_vp = cs->sc_tvn; 356 nbp->b_bcount = bp->b_bcount; 357 nbp->b_private = bp; 358 359 BIO_COPYPRIO(nbp, bp); 360 361 if ((nbp->b_flags & B_READ) == 0) { 362 V_INCR_NUMOUTPUT(nbp->b_vp); 363 } 364 VOP_STRATEGY(cs->sc_tvn, nbp); 365 return 0; 366 } 367 368 /* expected to be called at splbio() */ 369 static void 370 cgdiodone(struct buf *nbp) 371 { 372 struct buf *obp = nbp->b_private; 373 struct cgd_softc *cs = getcgd_softc(obp->b_dev); 374 struct dk_softc *dksc = &cs->sc_dksc; 375 376 KDASSERT(cs); 377 378 DPRINTF_FOLLOW(("cgdiodone(%p)\n", nbp)); 379 DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %d resid %d\n", 380 obp, obp->b_bcount, obp->b_resid)); 381 DPRINTF(CGDB_IO, (" dev 0x%x, nbp %p bn %" PRId64 " addr %p bcnt %d\n", 382 nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data, 383 nbp->b_bcount)); 384 if (nbp->b_flags & B_ERROR) { 385 obp->b_flags |= B_ERROR; 386 obp->b_error = nbp->b_error ? nbp->b_error : EIO; 387 388 printf("%s: error %d\n", dksc->sc_xname, obp->b_error); 389 } 390 391 /* Perform the decryption if we are reading. 392 * 393 * Note: use the blocknumber from nbp, since it is what 394 * we used to encrypt the blocks. 395 */ 396 397 if (nbp->b_flags & B_READ) 398 cgd_cipher(cs, obp->b_data, obp->b_data, obp->b_bcount, 399 nbp->b_blkno, DEV_BSIZE, CGD_CIPHER_DECRYPT); 400 401 /* If we allocated memory, free it now... */ 402 if (nbp->b_data != obp->b_data) 403 cgd_putdata(dksc, nbp->b_data); 404 405 pool_put(&bufpool, nbp); 406 407 /* Request is complete for whatever reason */ 408 obp->b_resid = 0; 409 if (obp->b_flags & B_ERROR) 410 obp->b_resid = obp->b_bcount; 411 disk_unbusy(&dksc->sc_dkdev, obp->b_bcount - obp->b_resid, 412 (obp->b_flags & B_READ)); 413 biodone(obp); 414 dk_iodone(di, dksc); 415 } 416 417 /* XXX: we should probably put these into dksubr.c, mostly */ 418 static int 419 cgdread(dev_t dev, struct uio *uio, int flags) 420 { 421 struct cgd_softc *cs; 422 struct dk_softc *dksc; 423 424 DPRINTF_FOLLOW(("cgdread(%d, %p, %d)\n", dev, uio, flags)); 425 GETCGD_SOFTC(cs, dev); 426 dksc = &cs->sc_dksc; 427 if ((dksc->sc_flags & DKF_INITED) == 0) 428 return ENXIO; 429 return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio); 430 } 431 432 /* XXX: we should probably put these into dksubr.c, mostly */ 433 static int 434 cgdwrite(dev_t dev, struct uio *uio, int flags) 435 { 436 struct cgd_softc *cs; 437 struct dk_softc *dksc; 438 439 DPRINTF_FOLLOW(("cgdwrite(%d, %p, %d)\n", dev, uio, flags)); 440 GETCGD_SOFTC(cs, dev); 441 dksc = &cs->sc_dksc; 442 if ((dksc->sc_flags & DKF_INITED) == 0) 443 return ENXIO; 444 return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio); 445 } 446 447 static int 448 cgdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 449 { 450 struct cgd_softc *cs; 451 struct dk_softc *dksc; 452 struct disk *dk; 453 int ret; 454 int part = DISKPART(dev); 455 int pmask = 1 << part; 456 457 DPRINTF_FOLLOW(("cgdioctl(%d, %ld, %p, %d, %p)\n", 458 dev, cmd, data, flag, p)); 459 GETCGD_SOFTC(cs, dev); 460 dksc = &cs->sc_dksc; 461 dk = &dksc->sc_dkdev; 462 switch (cmd) { 463 case CGDIOCSET: 464 case CGDIOCCLR: 465 if ((flag & FWRITE) == 0) 466 return EBADF; 467 } 468 469 switch (cmd) { 470 case CGDIOCSET: 471 if (dksc->sc_flags & DKF_INITED) 472 ret = EBUSY; 473 else 474 ret = cgd_ioctl_set(cs, data, p); 475 break; 476 case CGDIOCCLR: 477 if (!(dksc->sc_flags & DKF_INITED)) { 478 ret = ENXIO; 479 break; 480 } 481 if (DK_BUSY(&cs->sc_dksc, pmask)) { 482 ret = EBUSY; 483 break; 484 } 485 ret = cgd_ioctl_clr(cs, data, p); 486 break; 487 default: 488 ret = dk_ioctl(di, dksc, dev, cmd, data, flag, p); 489 break; 490 } 491 492 return ret; 493 } 494 495 static int 496 cgddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 497 { 498 struct cgd_softc *cs; 499 500 DPRINTF_FOLLOW(("cgddump(%d, %" PRId64 ", %p, %lu)\n", dev, blkno, va, 501 (unsigned long)size)); 502 GETCGD_SOFTC(cs, dev); 503 return dk_dump(di, &cs->sc_dksc, dev, blkno, va, size); 504 } 505 506 /* 507 * XXXrcd: 508 * for now we hardcode the maximum key length. 509 */ 510 #define MAX_KEYSIZE 1024 511 512 /* ARGSUSED */ 513 static int 514 cgd_ioctl_set(struct cgd_softc *cs, void *data, struct proc *p) 515 { 516 struct cgd_ioctl *ci = data; 517 struct vnode *vp; 518 int ret; 519 int keybytes; /* key length in bytes */ 520 const char *cp; 521 char inbuf[MAX_KEYSIZE]; 522 523 cp = ci->ci_disk; 524 if ((ret = dk_lookup(cp, p, &vp)) != 0) 525 return ret; 526 527 if ((ret = cgdinit(cs, cp, vp, p)) != 0) 528 goto bail; 529 530 memset(inbuf, 0x0, sizeof(inbuf)); 531 ret = copyinstr(ci->ci_alg, inbuf, 256, NULL); 532 if (ret) 533 goto bail; 534 cs->sc_cfuncs = cryptfuncs_find(inbuf); 535 if (!cs->sc_cfuncs) { 536 ret = EINVAL; 537 goto bail; 538 } 539 540 /* right now we only support encblkno, so hard-code it */ 541 memset(inbuf, 0x0, sizeof(inbuf)); 542 ret = copyinstr(ci->ci_ivmethod, inbuf, sizeof(inbuf), NULL); 543 if (ret) 544 goto bail; 545 if (strcmp("encblkno", inbuf)) { 546 ret = EINVAL; 547 goto bail; 548 } 549 550 keybytes = ci->ci_keylen / 8 + 1; 551 if (keybytes > MAX_KEYSIZE) { 552 ret = EINVAL; 553 goto bail; 554 } 555 memset(inbuf, 0x0, sizeof(inbuf)); 556 ret = copyin(ci->ci_key, inbuf, keybytes); 557 if (ret) 558 goto bail; 559 560 cs->sc_cdata.cf_blocksize = ci->ci_blocksize; 561 cs->sc_cdata.cf_mode = CGD_CIPHER_CBC_ENCBLKNO; 562 cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf, 563 &cs->sc_cdata.cf_blocksize); 564 memset(inbuf, 0x0, sizeof(inbuf)); 565 if (!cs->sc_cdata.cf_priv) { 566 printf("cgd: unable to initialize cipher\n"); 567 ret = EINVAL; /* XXX is this the right error? */ 568 goto bail; 569 } 570 571 bufq_alloc(&cs->sc_dksc.sc_bufq, BUFQ_FCFS); 572 573 cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK); 574 cs->sc_data_used = 0; 575 576 cs->sc_dksc.sc_flags |= DKF_INITED; 577 578 /* Attach the disk. */ 579 pseudo_disk_attach(&cs->sc_dksc.sc_dkdev); 580 581 /* Try and read the disklabel. */ 582 dk_getdisklabel(di, &cs->sc_dksc, 0 /* XXX ? */); 583 584 /* Discover wedges on this disk. */ 585 dkwedge_discover(&cs->sc_dksc.sc_dkdev); 586 587 return 0; 588 589 bail: 590 (void)vn_close(vp, FREAD|FWRITE, p->p_ucred, p); 591 return ret; 592 } 593 594 /* ARGSUSED */ 595 static int 596 cgd_ioctl_clr(struct cgd_softc *cs, void *data, struct proc *p) 597 { 598 int s; 599 600 /* Delete all of our wedges. */ 601 dkwedge_delall(&cs->sc_dksc.sc_dkdev); 602 603 /* Kill off any queued buffers. */ 604 s = splbio(); 605 bufq_drain(&cs->sc_dksc.sc_bufq); 606 splx(s); 607 bufq_free(&cs->sc_dksc.sc_bufq); 608 609 (void)vn_close(cs->sc_tvn, FREAD|FWRITE, p->p_ucred, p); 610 cs->sc_cfuncs->cf_destroy(cs->sc_cdata.cf_priv); 611 free(cs->sc_tpath, M_DEVBUF); 612 free(cs->sc_data, M_DEVBUF); 613 cs->sc_data_used = 0; 614 cs->sc_dksc.sc_flags &= ~DKF_INITED; 615 pseudo_disk_detach(&cs->sc_dksc.sc_dkdev); 616 617 return 0; 618 } 619 620 static int 621 cgdinit(struct cgd_softc *cs, const char *cpath, struct vnode *vp, 622 struct proc *p) 623 { 624 struct dk_geom *pdg; 625 struct partinfo dpart; 626 struct vattr va; 627 size_t size; 628 int maxsecsize = 0; 629 int ret; 630 char tmppath[MAXPATHLEN]; 631 632 cs->sc_dksc.sc_size = 0; 633 cs->sc_tvn = vp; 634 635 memset(tmppath, 0x0, sizeof(tmppath)); 636 ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen); 637 if (ret) 638 goto bail; 639 cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK); 640 memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen); 641 642 if ((ret = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0) 643 goto bail; 644 645 cs->sc_tdev = va.va_rdev; 646 647 ret = VOP_IOCTL(vp, DIOCGPART, &dpart, FREAD, p->p_ucred, p); 648 if (ret) 649 goto bail; 650 651 maxsecsize = 652 ((dpart.disklab->d_secsize > maxsecsize) ? 653 dpart.disklab->d_secsize : maxsecsize); 654 size = dpart.part->p_size; 655 656 if (!size) { 657 ret = ENODEV; 658 goto bail; 659 } 660 661 cs->sc_dksc.sc_size = size; 662 663 /* 664 * XXX here we should probe the underlying device. If we 665 * are accessing a partition of type RAW_PART, then 666 * we should populate our initial geometry with the 667 * geometry that we discover from the device. 668 */ 669 pdg = &cs->sc_dksc.sc_geom; 670 pdg->pdg_secsize = DEV_BSIZE; 671 pdg->pdg_ntracks = 1; 672 pdg->pdg_nsectors = 1024 * (1024 / pdg->pdg_secsize); 673 pdg->pdg_ncylinders = cs->sc_dksc.sc_size / pdg->pdg_nsectors; 674 675 bail: 676 if (ret && cs->sc_tpath) 677 free(cs->sc_tpath, M_DEVBUF); 678 return ret; 679 } 680 681 /* 682 * Our generic cipher entry point. This takes care of the 683 * IV mode and passes off the work to the specific cipher. 684 * We implement here the IV method ``encrypted block 685 * number''. 686 * 687 * For the encryption case, we accomplish this by setting 688 * up a struct uio where the first iovec of the source is 689 * the blocknumber and the first iovec of the dest is a 690 * sink. We then call the cipher with an IV of zero, and 691 * the right thing happens. 692 * 693 * For the decryption case, we use the same basic mechanism 694 * for symmetry, but we encrypt the block number in the 695 * first iovec. 696 * 697 * We mainly do this to avoid requiring the definition of 698 * an ECB mode. 699 * 700 * XXXrcd: for now we rely on our own crypto framework defined 701 * in dev/cgd_crypto.c. This will change when we 702 * get a generic kernel crypto framework. 703 */ 704 705 static void 706 blkno2blkno_buf(char *sbuf, daddr_t blkno) 707 { 708 int i; 709 710 /* Set up the blkno in blkno_buf, here we do not care much 711 * about the final layout of the information as long as we 712 * can guarantee that each sector will have a different IV 713 * and that the endianness of the machine will not affect 714 * the representation that we have chosen. 715 * 716 * We choose this representation, because it does not rely 717 * on the size of buf (which is the blocksize of the cipher), 718 * but allows daddr_t to grow without breaking existing 719 * disks. 720 * 721 * Note that blkno2blkno_buf does not take a size as input, 722 * and hence must be called on a pre-zeroed buffer of length 723 * greater than or equal to sizeof(daddr_t). 724 */ 725 for (i=0; i < sizeof(daddr_t); i++) { 726 *sbuf++ = blkno & 0xff; 727 blkno >>= 8; 728 } 729 } 730 731 static void 732 cgd_cipher(struct cgd_softc *cs, caddr_t dst, caddr_t src, 733 size_t len, daddr_t blkno, size_t secsize, int dir) 734 { 735 cfunc_cipher *cipher = cs->sc_cfuncs->cf_cipher; 736 struct uio dstuio; 737 struct uio srcuio; 738 struct iovec dstiov[2]; 739 struct iovec srciov[2]; 740 int blocksize = cs->sc_cdata.cf_blocksize; 741 char sink[blocksize]; 742 char zero_iv[blocksize]; 743 char blkno_buf[blocksize]; 744 745 DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n", dir)); 746 747 DIAGCONDPANIC(len % blocksize != 0, 748 ("cgd_cipher: len %% blocksize != 0")); 749 750 /* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */ 751 DIAGCONDPANIC(sizeof(daddr_t) > blocksize, 752 ("cgd_cipher: sizeof(daddr_t) > blocksize")); 753 754 memset(zero_iv, 0x0, sizeof(zero_iv)); 755 756 dstuio.uio_iov = dstiov; 757 dstuio.uio_iovcnt = 2; 758 759 srcuio.uio_iov = srciov; 760 srcuio.uio_iovcnt = 2; 761 762 dstiov[0].iov_base = sink; 763 dstiov[0].iov_len = blocksize; 764 srciov[0].iov_base = blkno_buf; 765 srciov[0].iov_len = blocksize; 766 dstiov[1].iov_len = secsize; 767 srciov[1].iov_len = secsize; 768 769 for (; len > 0; len -= secsize) { 770 dstiov[1].iov_base = dst; 771 srciov[1].iov_base = src; 772 773 memset(blkno_buf, 0x0, sizeof(blkno_buf)); 774 blkno2blkno_buf(blkno_buf, blkno); 775 if (dir == CGD_CIPHER_DECRYPT) { 776 dstuio.uio_iovcnt = 1; 777 srcuio.uio_iovcnt = 1; 778 IFDEBUG(CGDB_CRYPTO, hexprint("step 0: blkno_buf", 779 blkno_buf, sizeof(blkno_buf))); 780 cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, 781 zero_iv, CGD_CIPHER_ENCRYPT); 782 memcpy(blkno_buf, sink, blocksize); 783 dstuio.uio_iovcnt = 2; 784 srcuio.uio_iovcnt = 2; 785 } 786 787 IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf", 788 blkno_buf, sizeof(blkno_buf))); 789 cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, zero_iv, dir); 790 IFDEBUG(CGDB_CRYPTO, hexprint("step 2: sink", 791 sink, sizeof(sink))); 792 793 dst += secsize; 794 src += secsize; 795 blkno++; 796 } 797 } 798 799 #ifdef DEBUG 800 static void 801 hexprint(const char *start, void *buf, int len) 802 { 803 char *c = buf; 804 805 DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0")); 806 printf("%s: len=%06d 0x", start, len); 807 while (len--) 808 printf("%02x", (unsigned) *c++); 809 } 810 #endif 811