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