diff --git a/stand/common/disk.c b/stand/common/disk.c index 3ad147da0e5b..15daf7e358c6 100644 --- a/stand/common/disk.c +++ b/stand/common/disk.c @@ -1,476 +1,479 @@ /*- * Copyright (c) 1998 Michael Smith * Copyright (c) 2012 Andrey V. Elsukov * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include +#include #include "disk.h" #ifdef DISK_DEBUG # define DPRINTF(fmt, args...) printf("%s: " fmt "\n" , __func__ , ## args) #else # define DPRINTF(fmt, args...) ((void)0) #endif struct open_disk { struct ptable *table; uint64_t mediasize; uint64_t entrysize; u_int sectorsize; }; struct print_args { struct disk_devdesc *dev; const char *prefix; int verbose; }; /* Convert size to a human-readable number. */ static char * display_size(uint64_t size, u_int sectorsize) { static char buf[80]; char unit; size = size * sectorsize / 1024; unit = 'K'; if (size >= 10485760000LL) { size /= 1073741824; unit = 'T'; } else if (size >= 10240000) { size /= 1048576; unit = 'G'; } else if (size >= 10000) { size /= 1024; unit = 'M'; } snprintf(buf, sizeof(buf), "%4ld%cB", (long)size, unit); return (buf); } int ptblread(void *d, void *buf, size_t blocks, uint64_t offset) { struct disk_devdesc *dev; struct open_disk *od; dev = (struct disk_devdesc *)d; od = (struct open_disk *)dev->dd.d_opendata; /* * The strategy function assumes the offset is in units of 512 byte * sectors. For larger sector sizes, we need to adjust the offset to * match the actual sector size. */ offset *= (od->sectorsize / 512); /* * As the GPT backup partition is located at the end of the disk, * to avoid reading past disk end, flag bcache not to use RA. */ return (dev->dd.d_dev->dv_strategy(dev, F_READ | F_NORA, offset, blocks * od->sectorsize, (char *)buf, NULL)); } static int ptable_print(void *arg, const char *pname, const struct ptable_entry *part) { struct disk_devdesc dev; struct print_args *pa, bsd; struct open_disk *od; struct ptable *table; char line[80]; int res; u_int sectsize; uint64_t partsize; pa = (struct print_args *)arg; od = (struct open_disk *)pa->dev->dd.d_opendata; sectsize = od->sectorsize; partsize = part->end - part->start + 1; snprintf(line, sizeof(line), " %s%s: %s", pa->prefix, pname, parttype2str(part->type)); if (pager_output(line)) return (1); if (pa->verbose) { /* Emit extra tab when the line is shorter than 3 tab stops */ if (strlen(line) < 24) (void) pager_output("\t"); snprintf(line, sizeof(line), "\t%s", display_size(partsize, sectsize)); if (pager_output(line)) return (1); } if (pager_output("\n")) return (1); res = 0; if (part->type == PART_FREEBSD) { /* Open slice with BSD label */ dev.dd.d_dev = pa->dev->dd.d_dev; dev.dd.d_unit = pa->dev->dd.d_unit; dev.d_slice = part->index; dev.d_partition = D_PARTNONE; if (disk_open(&dev, partsize, sectsize) == 0) { table = ptable_open(&dev, partsize, sectsize, ptblread); if (table != NULL) { snprintf(line, sizeof(line), " %s%s", pa->prefix, pname); bsd.dev = pa->dev; bsd.prefix = line; bsd.verbose = pa->verbose; res = ptable_iterate(table, &bsd, ptable_print); ptable_close(table); } disk_close(&dev); } } return (res); } int disk_print(struct disk_devdesc *dev, char *prefix, int verbose) { struct open_disk *od; struct print_args pa; /* Disk should be opened */ od = (struct open_disk *)dev->dd.d_opendata; pa.dev = dev; pa.prefix = prefix; pa.verbose = verbose; return (ptable_iterate(od->table, &pa, ptable_print)); } int disk_read(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) { struct open_disk *od; int ret; od = (struct open_disk *)dev->dd.d_opendata; ret = dev->dd.d_dev->dv_strategy(dev, F_READ, dev->d_offset + offset, blocks * od->sectorsize, buf, NULL); return (ret); } int disk_write(struct disk_devdesc *dev, void *buf, uint64_t offset, u_int blocks) { struct open_disk *od; int ret; od = (struct open_disk *)dev->dd.d_opendata; ret = dev->dd.d_dev->dv_strategy(dev, F_WRITE, dev->d_offset + offset, blocks * od->sectorsize, buf, NULL); return (ret); } int disk_ioctl(struct disk_devdesc *dev, u_long cmd, void *data) { struct open_disk *od = dev->dd.d_opendata; if (od == NULL) return (ENOTTY); switch (cmd) { case DIOCGSECTORSIZE: *(u_int *)data = od->sectorsize; break; case DIOCGMEDIASIZE: if (dev->d_offset == 0) *(uint64_t *)data = od->mediasize; else *(uint64_t *)data = od->entrysize * od->sectorsize; break; default: return (ENOTTY); } return (0); } int disk_open(struct disk_devdesc *dev, uint64_t mediasize, u_int sectorsize) { struct disk_devdesc partdev; struct open_disk *od; struct ptable *table; struct ptable_entry part; int rc, slice, partition; if (sectorsize == 0) { DPRINTF("unknown sector size"); return (ENXIO); } rc = 0; od = (struct open_disk *)malloc(sizeof(struct open_disk)); if (od == NULL) { DPRINTF("no memory"); return (ENOMEM); } dev->dd.d_opendata = od; od->entrysize = 0; od->mediasize = mediasize; od->sectorsize = sectorsize; /* * While we are reading disk metadata, make sure we do it relative * to the start of the disk */ memcpy(&partdev, dev, sizeof(partdev)); partdev.d_offset = 0; partdev.d_slice = D_SLICENONE; partdev.d_partition = D_PARTNONE; dev->d_offset = 0; table = NULL; slice = dev->d_slice; partition = dev->d_partition; DPRINTF("%s unit %d, slice %d, partition %d => %p", disk_fmtdev(dev), dev->dd.d_unit, dev->d_slice, dev->d_partition, od); /* Determine disk layout. */ od->table = ptable_open(&partdev, mediasize / sectorsize, sectorsize, ptblread); if (od->table == NULL) { DPRINTF("Can't read partition table"); rc = ENXIO; goto out; } if (ptable_getsize(od->table, &mediasize) != 0) { rc = ENXIO; goto out; } od->mediasize = mediasize; if (ptable_gettype(od->table) == PTABLE_BSD && partition >= 0) { /* It doesn't matter what value has d_slice */ rc = ptable_getpart(od->table, &part, partition); if (rc == 0) { dev->d_offset = part.start; od->entrysize = part.end - part.start + 1; } } else if (ptable_gettype(od->table) == PTABLE_ISO9660) { dev->d_offset = 0; od->entrysize = mediasize; } else if (slice >= 0) { /* Try to get information about partition */ if (slice == 0) rc = ptable_getbestpart(od->table, &part); else rc = ptable_getpart(od->table, &part, slice); if (rc != 0) /* Partition doesn't exist */ goto out; dev->d_offset = part.start; od->entrysize = part.end - part.start + 1; slice = part.index; if (ptable_gettype(od->table) == PTABLE_GPT) { partition = D_PARTISGPT; goto out; /* Nothing more to do */ } else if (partition == D_PARTISGPT) { /* * When we try to open GPT partition, but partition * table isn't GPT, reset partition value to * D_PARTWILD and try to autodetect appropriate value. */ partition = D_PARTWILD; } /* * If partition is D_PARTNONE, then disk_open() was called * to open raw MBR slice. */ if (partition == D_PARTNONE) goto out; /* * If partition is D_PARTWILD and we are looking at a BSD slice, * then try to read BSD label, otherwise return the * whole MBR slice. */ if (partition == D_PARTWILD && part.type != PART_FREEBSD) goto out; /* Try to read BSD label */ table = ptable_open(dev, part.end - part.start + 1, od->sectorsize, ptblread); if (table == NULL) { DPRINTF("Can't read BSD label"); rc = ENXIO; goto out; } /* * If slice contains BSD label and partition < 0, then * assume the 'a' partition. Otherwise just return the * whole MBR slice, because it can contain ZFS. */ if (partition < 0) { if (ptable_gettype(table) != PTABLE_BSD) goto out; partition = 0; } rc = ptable_getpart(table, &part, partition); if (rc != 0) goto out; dev->d_offset += part.start; od->entrysize = part.end - part.start + 1; } out: if (table != NULL) ptable_close(table); if (rc != 0) { if (od->table != NULL) ptable_close(od->table); free(od); DPRINTF("%s could not open", disk_fmtdev(dev)); } else { /* Save the slice and partition number to the dev */ dev->d_slice = slice; dev->d_partition = partition; DPRINTF("%s offset %lld => %p", disk_fmtdev(dev), (long long)dev->d_offset, od); } return (rc); } int disk_close(struct disk_devdesc *dev) { struct open_disk *od; od = (struct open_disk *)dev->dd.d_opendata; DPRINTF("%s closed => %p", disk_fmtdev(dev), od); ptable_close(od->table); free(od); return (0); } char * -disk_fmtdev(struct disk_devdesc *dev) +disk_fmtdev(struct devdesc *vdev) { + struct disk_devdesc *dev = (struct disk_devdesc *)vdev; static char buf[128]; char *cp; + assert(vdev->d_dev->dv_type == DEVT_DISK); cp = buf + sprintf(buf, "%s%d", dev->dd.d_dev->dv_name, dev->dd.d_unit); if (dev->d_slice > D_SLICENONE) { #ifdef LOADER_GPT_SUPPORT if (dev->d_partition == D_PARTISGPT) { sprintf(cp, "p%d:", dev->d_slice); return (buf); } else #endif #ifdef LOADER_MBR_SUPPORT cp += sprintf(cp, "s%d", dev->d_slice); #endif } if (dev->d_partition > D_PARTNONE) cp += sprintf(cp, "%c", dev->d_partition + 'a'); strcat(cp, ":"); return (buf); } int disk_parsedev(struct disk_devdesc *dev, const char *devspec, const char **path) { int unit, slice, partition; const char *np; char *cp; np = devspec; unit = -1; /* * If there is path/file info after the device info, then any missing * slice or partition info should be considered a request to search for * an appropriate partition. Otherwise we want to open the raw device * itself and not try to fill in missing info by searching. */ if ((cp = strchr(np, ':')) != NULL && cp[1] != '\0') { slice = D_SLICEWILD; partition = D_PARTWILD; } else { slice = D_SLICENONE; partition = D_PARTNONE; } if (*np != '\0' && *np != ':') { unit = strtol(np, &cp, 10); if (cp == np) return (EUNIT); #ifdef LOADER_GPT_SUPPORT if (*cp == 'p') { np = cp + 1; slice = strtol(np, &cp, 10); if (np == cp) return (ESLICE); /* we don't support nested partitions on GPT */ if (*cp != '\0' && *cp != ':') return (EINVAL); partition = D_PARTISGPT; } else #endif #ifdef LOADER_MBR_SUPPORT if (*cp == 's') { np = cp + 1; slice = strtol(np, &cp, 10); if (np == cp) return (ESLICE); } #endif if (*cp != '\0' && *cp != ':') { partition = *cp - 'a'; if (partition < 0) return (EPART); cp++; } } else return (EINVAL); if (*cp != '\0' && *cp != ':') return (EINVAL); dev->dd.d_unit = unit; dev->d_slice = slice; dev->d_partition = partition; if (path != NULL) *path = (*cp == '\0') ? cp: cp + 1; return (0); } diff --git a/stand/common/disk.h b/stand/common/disk.h index 83109981e0a8..806673349cb8 100644 --- a/stand/common/disk.h +++ b/stand/common/disk.h @@ -1,122 +1,123 @@ /*- * Copyright (c) 2011 Google, Inc. * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. * * $FreeBSD$ */ /* * Device descriptor for partitioned disks. To use, set the * d_slice and d_partition variables as follows: * * Whole disk access: * * d_slice = D_SLICENONE * d_partition = * * Whole MBR slice: * * d_slice = MBR slice number (typically 1..4) * d_partition = D_PARTNONE * * BSD disklabel partition within an MBR slice: * * d_slice = MBR slice number (typically 1..4) * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) * * BSD disklabel partition on the true dedicated disk: * * d_slice = D_SLICENONE * d_partition = disklabel partition (typically 0..19 or D_PARTWILD) * * GPT partition: * * d_slice = GPT partition number (typically 1..N) * d_partition = D_PARTISGPT * * For MBR, setting d_partition to D_PARTWILD will automatically use the first * partition within the slice. * * For both MBR and GPT, to automatically find the 'best' slice and partition, * set d_slice to D_SLICEWILD. This uses the partition type to decide which * partition to use according to the following list of preferences: * * FreeBSD (active) * FreeBSD (inactive) * Linux (active) * Linux (inactive) * DOS/Windows (active) * DOS/Windows (inactive) * * Active MBR slices (marked as bootable) are preferred over inactive. GPT * doesn't have the concept of active/inactive partitions. In both MBR and GPT, * if there are multiple slices/partitions of a given type, the first one * is chosen. * * The low-level disk device will typically call disk_open() from its open * method to interpret the disk partition tables according to the rules above. * This will initialize d_offset to the block offset of the start of the * selected partition - this offset should be added to the offset passed to * the device's strategy method. */ #ifndef _DISK_H #define _DISK_H #define D_SLICENONE -1 #define D_SLICEWILD 0 #define D_PARTNONE -1 #define D_PARTWILD -2 #define D_PARTISGPT 255 struct disk_devdesc { struct devdesc dd; /* Must be first. */ int d_slice; int d_partition; uint64_t d_offset; }; enum disk_ioctl { IOCTL_GET_BLOCKS, IOCTL_GET_BLOCK_SIZE }; /* * Parse disk metadata and initialise dev->d_offset. */ extern int disk_open(struct disk_devdesc *, uint64_t, u_int); extern int disk_close(struct disk_devdesc *); extern int disk_ioctl(struct disk_devdesc *, u_long, void *); extern int disk_read(struct disk_devdesc *, void *, uint64_t, u_int); extern int disk_write(struct disk_devdesc *, void *, uint64_t, u_int); extern int ptblread(void *, void *, size_t, uint64_t); /* * Print information about slices on a disk. */ extern int disk_print(struct disk_devdesc *, char *, int); -extern char* disk_fmtdev(struct disk_devdesc *); extern int disk_parsedev(struct disk_devdesc *, const char *, const char **); +char *disk_fmtdev(struct devdesc *vdev); + #endif /* _DISK_H */ diff --git a/stand/libsa/geli/gelidev.c b/stand/libsa/geli/gelidev.c index d312d7b17e0e..5dd122a4a681 100644 --- a/stand/libsa/geli/gelidev.c +++ b/stand/libsa/geli/gelidev.c @@ -1,348 +1,348 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Ian Lepore * * 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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. * * $FreeBSD$ */ #include #include #include #include #include "disk.h" #include "geliboot.h" #include "geliboot_internal.h" static int geli_dev_init(void); static int geli_dev_strategy(void *, int, daddr_t, size_t, char *, size_t *); static int geli_dev_open(struct open_file *f, ...); static int geli_dev_close(struct open_file *f); static int geli_dev_ioctl(struct open_file *, u_long, void *); static int geli_dev_print(int); static void geli_dev_cleanup(void); /* * geli_devsw is static because it never appears in any arch's global devsw * array. Instead, when devopen() opens a DEVT_DISK device, it then calls * geli_probe_and_attach(), and if we find that the disk_devdesc describes a * geli-encrypted partition, we create a geli_devdesc which references this * devsw and has a pointer to the original disk_devdesc of the underlying host * disk. Then we manipulate the open_file struct to reference the new * geli_devdesc, effectively routing all IO operations through our code. */ static struct devsw geli_devsw = { .dv_name = "disk", .dv_type = DEVT_DISK, .dv_init = geli_dev_init, .dv_strategy = geli_dev_strategy, .dv_open = geli_dev_open, .dv_close = geli_dev_close, .dv_ioctl = geli_dev_ioctl, .dv_print = geli_dev_print, .dv_cleanup = geli_dev_cleanup, }; /* * geli_devdesc instances replace the disk_devdesc in an open_file struct when * the partition is encrypted. We keep a reference to the original host * disk_devdesc so that we can read the raw encrypted data using it. */ struct geli_devdesc { struct disk_devdesc ddd; /* Must be first. */ struct disk_devdesc *hdesc; /* disk/slice/part hosting geli vol */ struct geli_dev *gdev; /* geli_dev entry */ }; /* * A geli_readfunc that reads via a disk_devdesc passed in readpriv. This is * used to read the underlying host disk data when probing/tasting to see if the * host provider is geli-encrypted. */ static int diskdev_read(void *vdev, void *readpriv, off_t offbytes, void *buf, size_t sizebytes) { struct disk_devdesc *ddev; ddev = (struct disk_devdesc *)readpriv; return (ddev->dd.d_dev->dv_strategy(ddev, F_READ, offbytes / DEV_BSIZE, sizebytes, buf, NULL)); } static int geli_dev_init(void) { /* * Since geli_devsw never gets referenced in any arch's global devsw * table, this function should never get called. */ panic("%s: should never be called", __func__); return (ENXIO); } static int geli_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct geli_devdesc *gdesc; off_t alnend, alnstart, reqend, reqstart; size_t alnsize; char *iobuf; int rc; gdesc = (struct geli_devdesc *)devdata; /* * We can only decrypt full geli blocks. The blk arg is expressed in * units of DEV_BSIZE blocks, while size is in bytes. Convert * everything to bytes, and calculate the geli-blocksize-aligned start * and end points. * * Note: md_sectorsize must be cast to a signed type for the round2 * macros to work correctly (otherwise they get zero-extended to 64 bits * and mask off the high order 32 bits of the requested start/end). */ reqstart = blk * DEV_BSIZE; reqend = reqstart + size; alnstart = rounddown2(reqstart, (int)gdesc->gdev->md.md_sectorsize); alnend = roundup2(reqend, (int)gdesc->gdev->md.md_sectorsize); alnsize = alnend - alnstart; /* * If alignment requires us to read/write more than the size of the * provided buffer, allocate a temporary buffer. * The writes will always get temporary buffer because of encryption. */ if (alnsize <= size && (rw & F_MASK) == F_READ) iobuf = buf; else if ((iobuf = malloc(alnsize)) == NULL) return (ENOMEM); switch (rw & F_MASK) { case F_READ: /* * Read the encrypted data using the host provider, * then decrypt it. */ rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, rw, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); if (rc != 0) goto out; rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf, alnsize); if (rc != 0) goto out; /* * If we had to use a temporary buffer, copy the requested * part of the data to the caller's buffer. */ if (iobuf != buf) memcpy(buf, iobuf + (reqstart - alnstart), size); if (rsize != NULL) *rsize = size; break; case F_WRITE: if (iobuf != buf) { /* Read, decrypt, then modify. */ rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, F_READ, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); if (rc != 0) goto out; rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf, alnsize); if (rc != 0) goto out; /* Copy data to iobuf */ memcpy(iobuf + (reqstart - alnstart), buf, size); } /* Encrypt and write it. */ rc = geli_io(gdesc->gdev, GELI_ENCRYPT, alnstart, iobuf, alnsize); if (rc != 0) goto out; rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, rw, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); } out: if (iobuf != buf) free(iobuf); return (rc); } static int geli_dev_open(struct open_file *f, ...) { /* * Since geli_devsw never gets referenced in any arch's global devsw * table, this function should never get called. */ panic("%s: should never be called", __func__); return (ENXIO); } static int geli_dev_close(struct open_file *f) { struct geli_devdesc *gdesc; /* * Detach the geli_devdesc from the open_file and reattach the * underlying host provider's disk_devdesc; this undoes the work done at * the end of geli_probe_and_attach(). Call the host provider's * dv_close() (because that's what our caller thought it was doing). */ gdesc = (struct geli_devdesc *)f->f_devdata; f->f_devdata = gdesc->hdesc; f->f_dev = gdesc->hdesc->dd.d_dev; free(gdesc); f->f_dev->dv_close(f); return (0); } static int geli_dev_ioctl(struct open_file *f, u_long cmd, void *data) { struct geli_devdesc *gdesc; struct g_eli_metadata *md; gdesc = (struct geli_devdesc *)f->f_devdata; md = &gdesc->gdev->md; switch (cmd) { case DIOCGSECTORSIZE: *(u_int *)data = md->md_sectorsize; break; case DIOCGMEDIASIZE: *(uint64_t *)data = md->md_provsize; break; default: return (ENOTTY); } return (0); } static int geli_dev_print(int verbose) { /* * Since geli_devsw never gets referenced in any arch's global devsw * table, this function should never get called. */ panic("%s: should never be called", __func__); return (ENXIO); } static void geli_dev_cleanup(void) { /* * Since geli_devsw never gets referenced in any arch's global devsw * table, this function should never get called. */ panic("%s: should never be called", __func__); } /* * geli_probe_and_attach() is called from devopen() after it successfully calls * the dv_open() method of a DEVT_DISK device. We taste the partition described * by the disk_devdesc, and if it's geli-encrypted and we can decrypt it, we * create a geli_devdesc and store it into the open_file struct in place of the * underlying provider's disk_devdesc, effectively attaching our code to all IO * processing for the partition. Not quite the elegant stacking provided by * geom in the kernel, but it gets the job done. */ void geli_probe_and_attach(struct open_file *f) { static char gelipw[GELI_PW_MAXLEN]; const char *envpw; struct geli_dev *gdev; struct geli_devdesc *gdesc; struct disk_devdesc *hdesc; uint64_t hmediasize; daddr_t hlastblk; int rc; hdesc = (struct disk_devdesc *)(f->f_devdata); /* Get the last block number for the host provider. */ hdesc->dd.d_dev->dv_ioctl(f, DIOCGMEDIASIZE, &hmediasize); hlastblk = (hmediasize / DEV_BSIZE) - 1; /* Taste the host provider. If it's not geli-encrypted just return. */ - gdev = geli_taste(diskdev_read, hdesc, hlastblk, disk_fmtdev(hdesc)); + gdev = geli_taste(diskdev_read, hdesc, hlastblk, disk_fmtdev(&hdesc->dd)); if (gdev == NULL) return; /* * It's geli, try to decrypt it with existing keys, or prompt for a * passphrase if we don't yet have a cached key for it. */ if ((rc = geli_havekey(gdev)) != 0) { envpw = getenv("kern.geom.eli.passphrase"); if (envpw != NULL) { /* Use the cached passphrase */ bcopy(envpw, &gelipw, GELI_PW_MAXLEN); } if ((rc = geli_passphrase(gdev, gelipw)) == 0) { /* Passphrase is good, cache it. */ setenv("kern.geom.eli.passphrase", gelipw, 1); } explicit_bzero(gelipw, sizeof(gelipw)); if (rc != 0) return; } /* * It's geli-encrypted and we can decrypt it. Create a geli_devdesc, * store a reference to the underlying provider's disk_devdesc in it, * then attach it to the openfile struct in place of the host provider. */ if ((gdesc = malloc(sizeof(*gdesc))) == NULL) return; gdesc->ddd.dd.d_dev = &geli_devsw; gdesc->ddd.dd.d_opendata = NULL; gdesc->ddd.dd.d_unit = hdesc->dd.d_unit; gdesc->ddd.d_offset = hdesc->d_offset; gdesc->ddd.d_partition = hdesc->d_partition; gdesc->ddd.d_slice = hdesc->d_slice; gdesc->hdesc = hdesc; gdesc->gdev = gdev; f->f_dev = gdesc->ddd.dd.d_dev; f->f_devdata = gdesc; }