1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 Ian Lepore <ian@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <stand.h> 31 #include <stdarg.h> 32 #include <uuid.h> 33 #include <sys/disk.h> 34 #include "disk.h" 35 #include "geliboot.h" 36 #include "geliboot_internal.h" 37 38 static int geli_dev_init(void); 39 static int geli_dev_strategy(void *, int, daddr_t, size_t, char *, size_t *); 40 static int geli_dev_open(struct open_file *f, ...); 41 static int geli_dev_close(struct open_file *f); 42 static int geli_dev_ioctl(struct open_file *, u_long, void *); 43 static int geli_dev_print(int); 44 static void geli_dev_cleanup(void); 45 46 /* 47 * geli_devsw is static because it never appears in any arch's global devsw 48 * array. Instead, when devopen() opens a DEVT_DISK device, it then calls 49 * geli_probe_and_attach(), and if we find that the disk_devdesc describes a 50 * geli-encrypted partition, we create a geli_devdesc which references this 51 * devsw and has a pointer to the original disk_devdesc of the underlying host 52 * disk. Then we manipulate the open_file struct to reference the new 53 * geli_devdesc, effectively routing all IO operations through our code. 54 */ 55 static struct devsw geli_devsw = { 56 .dv_name = "disk", 57 .dv_type = DEVT_DISK, 58 .dv_init = geli_dev_init, 59 .dv_strategy = geli_dev_strategy, 60 .dv_open = geli_dev_open, 61 .dv_close = geli_dev_close, 62 .dv_ioctl = geli_dev_ioctl, 63 .dv_print = geli_dev_print, 64 .dv_cleanup = geli_dev_cleanup, 65 .dv_fmtdev = disk_fmtdev, 66 .dv_parsedev = disk_parsedev, 67 }; 68 69 /* 70 * geli_devdesc instances replace the disk_devdesc in an open_file struct when 71 * the partition is encrypted. We keep a reference to the original host 72 * disk_devdesc so that we can read the raw encrypted data using it. 73 */ 74 struct geli_devdesc { 75 struct disk_devdesc ddd; /* Must be first. */ 76 struct disk_devdesc *hdesc; /* disk/slice/part hosting geli vol */ 77 struct geli_dev *gdev; /* geli_dev entry */ 78 }; 79 80 81 /* 82 * A geli_readfunc that reads via a disk_devdesc passed in readpriv. This is 83 * used to read the underlying host disk data when probing/tasting to see if the 84 * host provider is geli-encrypted. 85 */ 86 static int 87 diskdev_read(void *vdev, void *readpriv, off_t offbytes, 88 void *buf, size_t sizebytes) 89 { 90 struct disk_devdesc *ddev; 91 92 ddev = (struct disk_devdesc *)readpriv; 93 94 return (ddev->dd.d_dev->dv_strategy(ddev, F_READ, offbytes / DEV_BSIZE, 95 sizebytes, buf, NULL)); 96 } 97 98 static int 99 geli_dev_init(void) 100 { 101 102 /* 103 * Since geli_devsw never gets referenced in any arch's global devsw 104 * table, this function should never get called. 105 */ 106 panic("%s: should never be called", __func__); 107 return (ENXIO); 108 } 109 110 static int 111 geli_dev_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf, 112 size_t *rsize) 113 { 114 struct geli_devdesc *gdesc; 115 off_t alnend, alnstart, reqend, reqstart; 116 size_t alnsize; 117 char *iobuf; 118 int rc; 119 120 gdesc = (struct geli_devdesc *)devdata; 121 122 /* 123 * We can only decrypt full geli blocks. The blk arg is expressed in 124 * units of DEV_BSIZE blocks, while size is in bytes. Convert 125 * everything to bytes, and calculate the geli-blocksize-aligned start 126 * and end points. 127 * 128 * Note: md_sectorsize must be cast to a signed type for the round2 129 * macros to work correctly (otherwise they get zero-extended to 64 bits 130 * and mask off the high order 32 bits of the requested start/end). 131 */ 132 133 reqstart = blk * DEV_BSIZE; 134 reqend = reqstart + size; 135 alnstart = rounddown2(reqstart, (int)gdesc->gdev->md.md_sectorsize); 136 alnend = roundup2(reqend, (int)gdesc->gdev->md.md_sectorsize); 137 alnsize = alnend - alnstart; 138 139 /* 140 * If alignment requires us to read/write more than the size of the 141 * provided buffer, allocate a temporary buffer. 142 * The writes will always get temporary buffer because of encryption. 143 */ 144 if (alnsize <= size && (rw & F_MASK) == F_READ) 145 iobuf = buf; 146 else if ((iobuf = malloc(alnsize)) == NULL) 147 return (ENOMEM); 148 149 switch (rw & F_MASK) { 150 case F_READ: 151 /* 152 * Read the encrypted data using the host provider, 153 * then decrypt it. 154 */ 155 rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, rw, 156 alnstart / DEV_BSIZE, alnsize, iobuf, NULL); 157 if (rc != 0) 158 goto out; 159 rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf, 160 alnsize); 161 if (rc != 0) 162 goto out; 163 164 /* 165 * If we had to use a temporary buffer, copy the requested 166 * part of the data to the caller's buffer. 167 */ 168 if (iobuf != buf) 169 memcpy(buf, iobuf + (reqstart - alnstart), size); 170 171 if (rsize != NULL) 172 *rsize = size; 173 break; 174 case F_WRITE: 175 if (iobuf != buf) { 176 /* Read, decrypt, then modify. */ 177 rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, 178 F_READ, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); 179 if (rc != 0) 180 goto out; 181 rc = geli_io(gdesc->gdev, GELI_DECRYPT, alnstart, iobuf, 182 alnsize); 183 if (rc != 0) 184 goto out; 185 /* Copy data to iobuf */ 186 memcpy(iobuf + (reqstart - alnstart), buf, size); 187 } 188 189 /* Encrypt and write it. */ 190 rc = geli_io(gdesc->gdev, GELI_ENCRYPT, alnstart, iobuf, 191 alnsize); 192 if (rc != 0) 193 goto out; 194 rc = gdesc->hdesc->dd.d_dev->dv_strategy(gdesc->hdesc, 195 rw, alnstart / DEV_BSIZE, alnsize, iobuf, NULL); 196 } 197 out: 198 if (iobuf != buf) 199 free(iobuf); 200 201 return (rc); 202 } 203 204 static int 205 geli_dev_open(struct open_file *f, ...) 206 { 207 208 /* 209 * Since geli_devsw never gets referenced in any arch's global devsw 210 * table, this function should never get called. 211 */ 212 panic("%s: should never be called", __func__); 213 return (ENXIO); 214 } 215 216 static int 217 geli_dev_close(struct open_file *f) 218 { 219 struct geli_devdesc *gdesc; 220 221 /* 222 * Detach the geli_devdesc from the open_file and reattach the 223 * underlying host provider's disk_devdesc; this undoes the work done at 224 * the end of geli_probe_and_attach(). Call the host provider's 225 * dv_close() (because that's what our caller thought it was doing). 226 */ 227 gdesc = (struct geli_devdesc *)f->f_devdata; 228 f->f_devdata = gdesc->hdesc; 229 f->f_dev = gdesc->hdesc->dd.d_dev; 230 free(gdesc); 231 f->f_dev->dv_close(f); 232 return (0); 233 } 234 235 static int 236 geli_dev_ioctl(struct open_file *f, u_long cmd, void *data) 237 { 238 struct geli_devdesc *gdesc; 239 struct g_eli_metadata *md; 240 241 gdesc = (struct geli_devdesc *)f->f_devdata; 242 md = &gdesc->gdev->md; 243 244 switch (cmd) { 245 case DIOCGSECTORSIZE: 246 *(u_int *)data = md->md_sectorsize; 247 break; 248 case DIOCGMEDIASIZE: 249 *(uint64_t *)data = md->md_provsize; 250 break; 251 default: 252 return (ENOTTY); 253 } 254 255 return (0); 256 } 257 258 static int 259 geli_dev_print(int verbose) 260 { 261 262 /* 263 * Since geli_devsw never gets referenced in any arch's global devsw 264 * table, this function should never get called. 265 */ 266 panic("%s: should never be called", __func__); 267 return (ENXIO); 268 } 269 270 static void 271 geli_dev_cleanup(void) 272 { 273 274 /* 275 * Since geli_devsw never gets referenced in any arch's global devsw 276 * table, this function should never get called. 277 */ 278 panic("%s: should never be called", __func__); 279 } 280 281 282 /* 283 * geli_probe_and_attach() is called from devopen() after it successfully calls 284 * the dv_open() method of a DEVT_DISK device. We taste the partition described 285 * by the disk_devdesc, and if it's geli-encrypted and we can decrypt it, we 286 * create a geli_devdesc and store it into the open_file struct in place of the 287 * underlying provider's disk_devdesc, effectively attaching our code to all IO 288 * processing for the partition. Not quite the elegant stacking provided by 289 * geom in the kernel, but it gets the job done. 290 */ 291 void 292 geli_probe_and_attach(struct open_file *f) 293 { 294 static char gelipw[GELI_PW_MAXLEN]; 295 const char *envpw; 296 struct geli_dev *gdev; 297 struct geli_devdesc *gdesc; 298 struct disk_devdesc *hdesc; 299 uint64_t hmediasize; 300 daddr_t hlastblk; 301 int rc; 302 303 hdesc = (struct disk_devdesc *)(f->f_devdata); 304 305 /* We only work on DEVT_DISKs */ 306 if (hdesc->dd.d_dev->dv_type != DEVT_DISK) 307 return; 308 /* Get the last block number for the host provider. */ 309 if (hdesc->dd.d_dev->dv_ioctl(f, DIOCGMEDIASIZE, &hmediasize) != 0) 310 return; 311 hlastblk = (hmediasize / DEV_BSIZE) - 1; 312 313 /* Taste the host provider. If it's not geli-encrypted just return. */ 314 gdev = geli_taste(diskdev_read, hdesc, hlastblk, devformat(&hdesc->dd)); 315 if (gdev == NULL) 316 return; 317 318 /* 319 * It's geli, try to decrypt it with existing keys, or prompt for a 320 * passphrase if we don't yet have a cached key for it. 321 */ 322 if ((rc = geli_havekey(gdev)) != 0) { 323 envpw = getenv("kern.geom.eli.passphrase"); 324 if (envpw != NULL) { 325 /* Use the cached passphrase */ 326 bcopy(envpw, &gelipw, GELI_PW_MAXLEN); 327 } 328 if ((rc = geli_passphrase(gdev, gelipw)) == 0) { 329 /* Passphrase is good, cache it. */ 330 setenv("kern.geom.eli.passphrase", gelipw, 1); 331 } 332 explicit_bzero(gelipw, sizeof(gelipw)); 333 if (rc != 0) 334 return; 335 } 336 337 /* 338 * It's geli-encrypted and we can decrypt it. Create a geli_devdesc, 339 * store a reference to the underlying provider's disk_devdesc in it, 340 * then attach it to the openfile struct in place of the host provider. 341 */ 342 if ((gdesc = malloc(sizeof(*gdesc))) == NULL) 343 return; 344 gdesc->ddd.dd.d_dev = &geli_devsw; 345 gdesc->ddd.dd.d_opendata = NULL; 346 gdesc->ddd.dd.d_unit = hdesc->dd.d_unit; 347 gdesc->ddd.d_offset = hdesc->d_offset; 348 gdesc->ddd.d_partition = hdesc->d_partition; 349 gdesc->ddd.d_slice = hdesc->d_slice; 350 gdesc->hdesc = hdesc; 351 gdesc->gdev = gdev; 352 f->f_dev = gdesc->ddd.dd.d_dev; 353 f->f_devdata = gdesc; 354 } 355