1 | /* $NetBSD: cgd.c,v 1.111 2016/09/14 23:16:30 mlelstv 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 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: cgd.c,v 1.111 2016/09/14 23:16:30 mlelstv Exp $" ); |
34 | |
35 | #include <sys/types.h> |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> |
38 | #include <sys/proc.h> |
39 | #include <sys/errno.h> |
40 | #include <sys/buf.h> |
41 | #include <sys/bufq.h> |
42 | #include <sys/malloc.h> |
43 | #include <sys/module.h> |
44 | #include <sys/pool.h> |
45 | #include <sys/ioctl.h> |
46 | #include <sys/device.h> |
47 | #include <sys/disk.h> |
48 | #include <sys/disklabel.h> |
49 | #include <sys/fcntl.h> |
50 | #include <sys/namei.h> /* for pathbuf */ |
51 | #include <sys/vnode.h> |
52 | #include <sys/conf.h> |
53 | #include <sys/syslog.h> |
54 | |
55 | #include <dev/dkvar.h> |
56 | #include <dev/cgdvar.h> |
57 | |
58 | #include <miscfs/specfs/specdev.h> /* for v_rdev */ |
59 | |
60 | #include "ioconf.h" |
61 | |
62 | /* Entry Point Functions */ |
63 | |
64 | static dev_type_open(cgdopen); |
65 | static dev_type_close(cgdclose); |
66 | static dev_type_read(cgdread); |
67 | static dev_type_write(cgdwrite); |
68 | static dev_type_ioctl(cgdioctl); |
69 | static dev_type_strategy(cgdstrategy); |
70 | static dev_type_dump(cgddump); |
71 | static dev_type_size(cgdsize); |
72 | |
73 | const struct bdevsw cgd_bdevsw = { |
74 | .d_open = cgdopen, |
75 | .d_close = cgdclose, |
76 | .d_strategy = cgdstrategy, |
77 | .d_ioctl = cgdioctl, |
78 | .d_dump = cgddump, |
79 | .d_psize = cgdsize, |
80 | .d_discard = nodiscard, |
81 | .d_flag = D_DISK |
82 | }; |
83 | |
84 | const struct cdevsw cgd_cdevsw = { |
85 | .d_open = cgdopen, |
86 | .d_close = cgdclose, |
87 | .d_read = cgdread, |
88 | .d_write = cgdwrite, |
89 | .d_ioctl = cgdioctl, |
90 | .d_stop = nostop, |
91 | .d_tty = notty, |
92 | .d_poll = nopoll, |
93 | .d_mmap = nommap, |
94 | .d_kqfilter = nokqfilter, |
95 | .d_discard = nodiscard, |
96 | .d_flag = D_DISK |
97 | }; |
98 | |
99 | static int cgd_match(device_t, cfdata_t, void *); |
100 | static void cgd_attach(device_t, device_t, void *); |
101 | static int cgd_detach(device_t, int); |
102 | static struct cgd_softc *cgd_spawn(int); |
103 | static int cgd_destroy(device_t); |
104 | |
105 | /* Internal Functions */ |
106 | |
107 | static int cgd_diskstart(device_t, struct buf *); |
108 | static void cgdiodone(struct buf *); |
109 | static int cgd_dumpblocks(device_t, void *, daddr_t, int); |
110 | |
111 | static int cgd_ioctl_set(struct cgd_softc *, void *, struct lwp *); |
112 | static int cgd_ioctl_clr(struct cgd_softc *, struct lwp *); |
113 | static int cgd_ioctl_get(dev_t, void *, struct lwp *); |
114 | static int cgdinit(struct cgd_softc *, const char *, struct vnode *, |
115 | struct lwp *); |
116 | static void cgd_cipher(struct cgd_softc *, void *, void *, |
117 | size_t, daddr_t, size_t, int); |
118 | |
119 | static struct dkdriver cgddkdriver = { |
120 | .d_minphys = minphys, |
121 | .d_open = cgdopen, |
122 | .d_close = cgdclose, |
123 | .d_strategy = cgdstrategy, |
124 | .d_iosize = NULL, |
125 | .d_diskstart = cgd_diskstart, |
126 | .d_dumpblocks = cgd_dumpblocks, |
127 | .d_lastclose = NULL |
128 | }; |
129 | |
130 | CFATTACH_DECL3_NEW(cgd, sizeof(struct cgd_softc), |
131 | cgd_match, cgd_attach, cgd_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); |
132 | extern struct cfdriver cgd_cd; |
133 | |
134 | /* DIAGNOSTIC and DEBUG definitions */ |
135 | |
136 | #if defined(CGDDEBUG) && !defined(DEBUG) |
137 | #define DEBUG |
138 | #endif |
139 | |
140 | #ifdef DEBUG |
141 | int cgddebug = 0; |
142 | |
143 | #define CGDB_FOLLOW 0x1 |
144 | #define CGDB_IO 0x2 |
145 | #define CGDB_CRYPTO 0x4 |
146 | |
147 | #define IFDEBUG(x,y) if (cgddebug & (x)) y |
148 | #define DPRINTF(x,y) IFDEBUG(x, printf y) |
149 | #define DPRINTF_FOLLOW(y) DPRINTF(CGDB_FOLLOW, y) |
150 | |
151 | static void hexprint(const char *, void *, int); |
152 | |
153 | #else |
154 | #define IFDEBUG(x,y) |
155 | #define DPRINTF(x,y) |
156 | #define DPRINTF_FOLLOW(y) |
157 | #endif |
158 | |
159 | #ifdef DIAGNOSTIC |
160 | #define DIAGPANIC(x) panic x |
161 | #define DIAGCONDPANIC(x,y) if (x) panic y |
162 | #else |
163 | #define DIAGPANIC(x) |
164 | #define DIAGCONDPANIC(x,y) |
165 | #endif |
166 | |
167 | /* Global variables */ |
168 | |
169 | /* Utility Functions */ |
170 | |
171 | #define CGDUNIT(x) DISKUNIT(x) |
172 | #define GETCGD_SOFTC(_cs, x) if (!((_cs) = getcgd_softc(x))) return ENXIO |
173 | |
174 | /* The code */ |
175 | |
176 | static struct cgd_softc * |
177 | getcgd_softc(dev_t dev) |
178 | { |
179 | int unit = CGDUNIT(dev); |
180 | struct cgd_softc *sc; |
181 | |
182 | DPRINTF_FOLLOW(("getcgd_softc(0x%" PRIx64"): unit = %d\n" , dev, unit)); |
183 | |
184 | sc = device_lookup_private(&cgd_cd, unit); |
185 | if (sc == NULL) |
186 | sc = cgd_spawn(unit); |
187 | return sc; |
188 | } |
189 | |
190 | static int |
191 | cgd_match(device_t self, cfdata_t cfdata, void *aux) |
192 | { |
193 | |
194 | return 1; |
195 | } |
196 | |
197 | static void |
198 | cgd_attach(device_t parent, device_t self, void *aux) |
199 | { |
200 | struct cgd_softc *sc = device_private(self); |
201 | |
202 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_BIO); |
203 | dk_init(&sc->sc_dksc, self, DKTYPE_CGD); |
204 | disk_init(&sc->sc_dksc.sc_dkdev, sc->sc_dksc.sc_xname, &cgddkdriver); |
205 | |
206 | if (!pmf_device_register(self, NULL, NULL)) |
207 | aprint_error_dev(self, |
208 | "unable to register power management hooks\n" ); |
209 | } |
210 | |
211 | |
212 | static int |
213 | cgd_detach(device_t self, int flags) |
214 | { |
215 | int ret; |
216 | const int pmask = 1 << RAW_PART; |
217 | struct cgd_softc *sc = device_private(self); |
218 | struct dk_softc *dksc = &sc->sc_dksc; |
219 | |
220 | if (DK_BUSY(dksc, pmask)) |
221 | return EBUSY; |
222 | |
223 | if (DK_ATTACHED(dksc) && |
224 | (ret = cgd_ioctl_clr(sc, curlwp)) != 0) |
225 | return ret; |
226 | |
227 | disk_destroy(&dksc->sc_dkdev); |
228 | mutex_destroy(&sc->sc_lock); |
229 | |
230 | return 0; |
231 | } |
232 | |
233 | void |
234 | cgdattach(int num) |
235 | { |
236 | int error; |
237 | |
238 | error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca); |
239 | if (error != 0) |
240 | aprint_error("%s: unable to register cfattach\n" , |
241 | cgd_cd.cd_name); |
242 | } |
243 | |
244 | static struct cgd_softc * |
245 | cgd_spawn(int unit) |
246 | { |
247 | cfdata_t cf; |
248 | |
249 | cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK); |
250 | cf->cf_name = cgd_cd.cd_name; |
251 | cf->cf_atname = cgd_cd.cd_name; |
252 | cf->cf_unit = unit; |
253 | cf->cf_fstate = FSTATE_STAR; |
254 | |
255 | return device_private(config_attach_pseudo(cf)); |
256 | } |
257 | |
258 | static int |
259 | cgd_destroy(device_t dev) |
260 | { |
261 | int error; |
262 | cfdata_t cf; |
263 | |
264 | cf = device_cfdata(dev); |
265 | error = config_detach(dev, DETACH_QUIET); |
266 | if (error) |
267 | return error; |
268 | free(cf, M_DEVBUF); |
269 | return 0; |
270 | } |
271 | |
272 | static int |
273 | cgdopen(dev_t dev, int flags, int fmt, struct lwp *l) |
274 | { |
275 | struct cgd_softc *cs; |
276 | |
277 | DPRINTF_FOLLOW(("cgdopen(0x%" PRIx64", %d)\n" , dev, flags)); |
278 | GETCGD_SOFTC(cs, dev); |
279 | return dk_open(&cs->sc_dksc, dev, flags, fmt, l); |
280 | } |
281 | |
282 | static int |
283 | cgdclose(dev_t dev, int flags, int fmt, struct lwp *l) |
284 | { |
285 | int error; |
286 | struct cgd_softc *cs; |
287 | struct dk_softc *dksc; |
288 | |
289 | DPRINTF_FOLLOW(("cgdclose(0x%" PRIx64", %d)\n" , dev, flags)); |
290 | GETCGD_SOFTC(cs, dev); |
291 | dksc = &cs->sc_dksc; |
292 | if ((error = dk_close(dksc, dev, flags, fmt, l)) != 0) |
293 | return error; |
294 | |
295 | if (!DK_ATTACHED(dksc)) { |
296 | if ((error = cgd_destroy(cs->sc_dksc.sc_dev)) != 0) { |
297 | aprint_error_dev(dksc->sc_dev, |
298 | "unable to detach instance\n" ); |
299 | return error; |
300 | } |
301 | } |
302 | return 0; |
303 | } |
304 | |
305 | static void |
306 | cgdstrategy(struct buf *bp) |
307 | { |
308 | struct cgd_softc *cs; |
309 | |
310 | DPRINTF_FOLLOW(("cgdstrategy(%p): b_bcount = %ld\n" , bp, |
311 | (long)bp->b_bcount)); |
312 | |
313 | cs = getcgd_softc(bp->b_dev); |
314 | if (!cs) { |
315 | bp->b_error = ENXIO; |
316 | goto bail; |
317 | } |
318 | |
319 | /* |
320 | * Reject unaligned writes. |
321 | */ |
322 | if (((uintptr_t)bp->b_data & 3) != 0) { |
323 | bp->b_error = EINVAL; |
324 | goto bail; |
325 | } |
326 | |
327 | dk_strategy(&cs->sc_dksc, bp); |
328 | return; |
329 | |
330 | bail: |
331 | bp->b_resid = bp->b_bcount; |
332 | biodone(bp); |
333 | return; |
334 | } |
335 | |
336 | static int |
337 | cgdsize(dev_t dev) |
338 | { |
339 | struct cgd_softc *cs = getcgd_softc(dev); |
340 | |
341 | DPRINTF_FOLLOW(("cgdsize(0x%" PRIx64")\n" , dev)); |
342 | if (!cs) |
343 | return -1; |
344 | return dk_size(&cs->sc_dksc, dev); |
345 | } |
346 | |
347 | /* |
348 | * cgd_{get,put}data are functions that deal with getting a buffer |
349 | * for the new encrypted data. We have a buffer per device so that |
350 | * we can ensure that we can always have a transaction in flight. |
351 | * We use this buffer first so that we have one less piece of |
352 | * malloc'ed data at any given point. |
353 | */ |
354 | |
355 | static void * |
356 | cgd_getdata(struct dk_softc *dksc, unsigned long size) |
357 | { |
358 | struct cgd_softc *cs = (struct cgd_softc *)dksc; |
359 | void * data = NULL; |
360 | |
361 | mutex_enter(&cs->sc_lock); |
362 | if (cs->sc_data_used == 0) { |
363 | cs->sc_data_used = 1; |
364 | data = cs->sc_data; |
365 | } |
366 | mutex_exit(&cs->sc_lock); |
367 | |
368 | if (data) |
369 | return data; |
370 | |
371 | return malloc(size, M_DEVBUF, M_NOWAIT); |
372 | } |
373 | |
374 | static void |
375 | cgd_putdata(struct dk_softc *dksc, void *data) |
376 | { |
377 | struct cgd_softc *cs = (struct cgd_softc *)dksc; |
378 | |
379 | if (data == cs->sc_data) { |
380 | mutex_enter(&cs->sc_lock); |
381 | cs->sc_data_used = 0; |
382 | mutex_exit(&cs->sc_lock); |
383 | } else { |
384 | free(data, M_DEVBUF); |
385 | } |
386 | } |
387 | |
388 | static int |
389 | cgd_diskstart(device_t dev, struct buf *bp) |
390 | { |
391 | struct cgd_softc *cs = device_private(dev); |
392 | struct dk_softc *dksc = &cs->sc_dksc; |
393 | struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; |
394 | struct buf *nbp; |
395 | void * addr; |
396 | void * newaddr; |
397 | daddr_t bn; |
398 | struct vnode *vp; |
399 | |
400 | DPRINTF_FOLLOW(("cgd_diskstart(%p, %p)\n" , dksc, bp)); |
401 | |
402 | bn = bp->b_rawblkno; |
403 | |
404 | /* |
405 | * We attempt to allocate all of our resources up front, so that |
406 | * we can fail quickly if they are unavailable. |
407 | */ |
408 | nbp = getiobuf(cs->sc_tvn, false); |
409 | if (nbp == NULL) |
410 | return EAGAIN; |
411 | |
412 | /* |
413 | * If we are writing, then we need to encrypt the outgoing |
414 | * block into a new block of memory. |
415 | */ |
416 | newaddr = addr = bp->b_data; |
417 | if ((bp->b_flags & B_READ) == 0) { |
418 | newaddr = cgd_getdata(dksc, bp->b_bcount); |
419 | if (!newaddr) { |
420 | putiobuf(nbp); |
421 | return EAGAIN; |
422 | } |
423 | cgd_cipher(cs, newaddr, addr, bp->b_bcount, bn, |
424 | dg->dg_secsize, CGD_CIPHER_ENCRYPT); |
425 | } |
426 | |
427 | nbp->b_data = newaddr; |
428 | nbp->b_flags = bp->b_flags; |
429 | nbp->b_oflags = bp->b_oflags; |
430 | nbp->b_cflags = bp->b_cflags; |
431 | nbp->b_iodone = cgdiodone; |
432 | nbp->b_proc = bp->b_proc; |
433 | nbp->b_blkno = btodb(bn * dg->dg_secsize); |
434 | nbp->b_bcount = bp->b_bcount; |
435 | nbp->b_private = bp; |
436 | |
437 | BIO_COPYPRIO(nbp, bp); |
438 | |
439 | if ((nbp->b_flags & B_READ) == 0) { |
440 | vp = nbp->b_vp; |
441 | mutex_enter(vp->v_interlock); |
442 | vp->v_numoutput++; |
443 | mutex_exit(vp->v_interlock); |
444 | } |
445 | VOP_STRATEGY(cs->sc_tvn, nbp); |
446 | |
447 | return 0; |
448 | } |
449 | |
450 | static void |
451 | cgdiodone(struct buf *nbp) |
452 | { |
453 | struct buf *obp = nbp->b_private; |
454 | struct cgd_softc *cs = getcgd_softc(obp->b_dev); |
455 | struct dk_softc *dksc = &cs->sc_dksc; |
456 | struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; |
457 | daddr_t bn; |
458 | |
459 | KDASSERT(cs); |
460 | |
461 | DPRINTF_FOLLOW(("cgdiodone(%p)\n" , nbp)); |
462 | DPRINTF(CGDB_IO, ("cgdiodone: bp %p bcount %d resid %d\n" , |
463 | obp, obp->b_bcount, obp->b_resid)); |
464 | DPRINTF(CGDB_IO, (" dev 0x%" PRIx64", nbp %p bn %" PRId64 |
465 | " addr %p bcnt %d\n" , nbp->b_dev, nbp, nbp->b_blkno, nbp->b_data, |
466 | nbp->b_bcount)); |
467 | if (nbp->b_error != 0) { |
468 | obp->b_error = nbp->b_error; |
469 | DPRINTF(CGDB_IO, ("%s: error %d\n" , dksc->sc_xname, |
470 | obp->b_error)); |
471 | } |
472 | |
473 | /* Perform the decryption if we are reading. |
474 | * |
475 | * Note: use the blocknumber from nbp, since it is what |
476 | * we used to encrypt the blocks. |
477 | */ |
478 | |
479 | if (nbp->b_flags & B_READ) { |
480 | bn = dbtob(nbp->b_blkno) / dg->dg_secsize; |
481 | cgd_cipher(cs, obp->b_data, obp->b_data, obp->b_bcount, |
482 | bn, dg->dg_secsize, CGD_CIPHER_DECRYPT); |
483 | } |
484 | |
485 | /* If we allocated memory, free it now... */ |
486 | if (nbp->b_data != obp->b_data) |
487 | cgd_putdata(dksc, nbp->b_data); |
488 | |
489 | putiobuf(nbp); |
490 | |
491 | /* Request is complete for whatever reason */ |
492 | obp->b_resid = 0; |
493 | if (obp->b_error != 0) |
494 | obp->b_resid = obp->b_bcount; |
495 | |
496 | dk_done(dksc, obp); |
497 | dk_start(dksc, NULL); |
498 | } |
499 | |
500 | static int |
501 | cgd_dumpblocks(device_t dev, void *va, daddr_t blkno, int nblk) |
502 | { |
503 | struct cgd_softc *sc = device_private(dev); |
504 | struct dk_softc *dksc = &sc->sc_dksc; |
505 | struct disk_geom *dg = &dksc->sc_dkdev.dk_geom; |
506 | size_t nbytes, blksize; |
507 | void *buf; |
508 | int error; |
509 | |
510 | /* |
511 | * dk_dump gives us units of disklabel sectors. Everything |
512 | * else in cgd uses units of diskgeom sectors. These had |
513 | * better agree; otherwise we need to figure out how to convert |
514 | * between them. |
515 | */ |
516 | KASSERTMSG((dg->dg_secsize == dksc->sc_dkdev.dk_label->d_secsize), |
517 | "diskgeom secsize %" PRIu32" != disklabel secsize %" PRIu32, |
518 | dg->dg_secsize, dksc->sc_dkdev.dk_label->d_secsize); |
519 | blksize = dg->dg_secsize; |
520 | |
521 | /* |
522 | * Compute the number of bytes in this request, which dk_dump |
523 | * has `helpfully' converted to a number of blocks for us. |
524 | */ |
525 | nbytes = nblk*blksize; |
526 | |
527 | /* Try to acquire a buffer to store the ciphertext. */ |
528 | buf = cgd_getdata(dksc, nbytes); |
529 | if (buf == NULL) |
530 | /* Out of memory: give up. */ |
531 | return ENOMEM; |
532 | |
533 | /* Encrypt the caller's data into the temporary buffer. */ |
534 | cgd_cipher(sc, buf, va, nbytes, blkno, blksize, CGD_CIPHER_ENCRYPT); |
535 | |
536 | /* Pass it on to the underlying disk device. */ |
537 | error = bdev_dump(sc->sc_tdev, blkno, buf, nbytes); |
538 | |
539 | /* Release the buffer. */ |
540 | cgd_putdata(dksc, buf); |
541 | |
542 | /* Return any error from the underlying disk device. */ |
543 | return error; |
544 | } |
545 | |
546 | /* XXX: we should probably put these into dksubr.c, mostly */ |
547 | static int |
548 | cgdread(dev_t dev, struct uio *uio, int flags) |
549 | { |
550 | struct cgd_softc *cs; |
551 | struct dk_softc *dksc; |
552 | |
553 | DPRINTF_FOLLOW(("cgdread(0x%llx, %p, %d)\n" , |
554 | (unsigned long long)dev, uio, flags)); |
555 | GETCGD_SOFTC(cs, dev); |
556 | dksc = &cs->sc_dksc; |
557 | if (!DK_ATTACHED(dksc)) |
558 | return ENXIO; |
559 | return physio(cgdstrategy, NULL, dev, B_READ, minphys, uio); |
560 | } |
561 | |
562 | /* XXX: we should probably put these into dksubr.c, mostly */ |
563 | static int |
564 | cgdwrite(dev_t dev, struct uio *uio, int flags) |
565 | { |
566 | struct cgd_softc *cs; |
567 | struct dk_softc *dksc; |
568 | |
569 | DPRINTF_FOLLOW(("cgdwrite(0x%" PRIx64", %p, %d)\n" , dev, uio, flags)); |
570 | GETCGD_SOFTC(cs, dev); |
571 | dksc = &cs->sc_dksc; |
572 | if (!DK_ATTACHED(dksc)) |
573 | return ENXIO; |
574 | return physio(cgdstrategy, NULL, dev, B_WRITE, minphys, uio); |
575 | } |
576 | |
577 | static int |
578 | cgdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) |
579 | { |
580 | struct cgd_softc *cs; |
581 | struct dk_softc *dksc; |
582 | int part = DISKPART(dev); |
583 | int pmask = 1 << part; |
584 | |
585 | DPRINTF_FOLLOW(("cgdioctl(0x%" PRIx64", %ld, %p, %d, %p)\n" , |
586 | dev, cmd, data, flag, l)); |
587 | |
588 | switch (cmd) { |
589 | case CGDIOCGET: |
590 | return cgd_ioctl_get(dev, data, l); |
591 | case CGDIOCSET: |
592 | case CGDIOCCLR: |
593 | if ((flag & FWRITE) == 0) |
594 | return EBADF; |
595 | /* FALLTHROUGH */ |
596 | default: |
597 | GETCGD_SOFTC(cs, dev); |
598 | dksc = &cs->sc_dksc; |
599 | break; |
600 | } |
601 | |
602 | switch (cmd) { |
603 | case CGDIOCSET: |
604 | if (DK_ATTACHED(dksc)) |
605 | return EBUSY; |
606 | return cgd_ioctl_set(cs, data, l); |
607 | case CGDIOCCLR: |
608 | if (DK_BUSY(&cs->sc_dksc, pmask)) |
609 | return EBUSY; |
610 | return cgd_ioctl_clr(cs, l); |
611 | case DIOCCACHESYNC: |
612 | /* |
613 | * XXX Do we really need to care about having a writable |
614 | * file descriptor here? |
615 | */ |
616 | if ((flag & FWRITE) == 0) |
617 | return (EBADF); |
618 | |
619 | /* |
620 | * We pass this call down to the underlying disk. |
621 | */ |
622 | return VOP_IOCTL(cs->sc_tvn, cmd, data, flag, l->l_cred); |
623 | case DIOCGSTRATEGY: |
624 | case DIOCSSTRATEGY: |
625 | if (!DK_ATTACHED(dksc)) |
626 | return ENOENT; |
627 | /*FALLTHROUGH*/ |
628 | default: |
629 | return dk_ioctl(dksc, dev, cmd, data, flag, l); |
630 | case CGDIOCGET: |
631 | KASSERT(0); |
632 | return EINVAL; |
633 | } |
634 | } |
635 | |
636 | static int |
637 | cgddump(dev_t dev, daddr_t blkno, void *va, size_t size) |
638 | { |
639 | struct cgd_softc *cs; |
640 | |
641 | DPRINTF_FOLLOW(("cgddump(0x%" PRIx64", %" PRId64 ", %p, %lu)\n" , |
642 | dev, blkno, va, (unsigned long)size)); |
643 | GETCGD_SOFTC(cs, dev); |
644 | return dk_dump(&cs->sc_dksc, dev, blkno, va, size); |
645 | } |
646 | |
647 | /* |
648 | * XXXrcd: |
649 | * for now we hardcode the maximum key length. |
650 | */ |
651 | #define MAX_KEYSIZE 1024 |
652 | |
653 | static const struct { |
654 | const char *n; |
655 | int v; |
656 | int d; |
657 | } encblkno[] = { |
658 | { "encblkno" , CGD_CIPHER_CBC_ENCBLKNO8, 1 }, |
659 | { "encblkno8" , CGD_CIPHER_CBC_ENCBLKNO8, 1 }, |
660 | { "encblkno1" , CGD_CIPHER_CBC_ENCBLKNO1, 8 }, |
661 | }; |
662 | |
663 | /* ARGSUSED */ |
664 | static int |
665 | cgd_ioctl_set(struct cgd_softc *cs, void *data, struct lwp *l) |
666 | { |
667 | struct cgd_ioctl *ci = data; |
668 | struct vnode *vp; |
669 | int ret; |
670 | size_t i; |
671 | size_t keybytes; /* key length in bytes */ |
672 | const char *cp; |
673 | struct pathbuf *pb; |
674 | char *inbuf; |
675 | struct dk_softc *dksc = &cs->sc_dksc; |
676 | |
677 | cp = ci->ci_disk; |
678 | |
679 | ret = pathbuf_copyin(ci->ci_disk, &pb); |
680 | if (ret != 0) { |
681 | return ret; |
682 | } |
683 | ret = dk_lookup(pb, l, &vp); |
684 | pathbuf_destroy(pb); |
685 | if (ret != 0) { |
686 | return ret; |
687 | } |
688 | |
689 | inbuf = malloc(MAX_KEYSIZE, M_TEMP, M_WAITOK); |
690 | |
691 | if ((ret = cgdinit(cs, cp, vp, l)) != 0) |
692 | goto bail; |
693 | |
694 | (void)memset(inbuf, 0, MAX_KEYSIZE); |
695 | ret = copyinstr(ci->ci_alg, inbuf, 256, NULL); |
696 | if (ret) |
697 | goto bail; |
698 | cs->sc_cfuncs = cryptfuncs_find(inbuf); |
699 | if (!cs->sc_cfuncs) { |
700 | ret = EINVAL; |
701 | goto bail; |
702 | } |
703 | |
704 | (void)memset(inbuf, 0, MAX_KEYSIZE); |
705 | ret = copyinstr(ci->ci_ivmethod, inbuf, MAX_KEYSIZE, NULL); |
706 | if (ret) |
707 | goto bail; |
708 | |
709 | for (i = 0; i < __arraycount(encblkno); i++) |
710 | if (strcmp(encblkno[i].n, inbuf) == 0) |
711 | break; |
712 | |
713 | if (i == __arraycount(encblkno)) { |
714 | ret = EINVAL; |
715 | goto bail; |
716 | } |
717 | |
718 | keybytes = ci->ci_keylen / 8 + 1; |
719 | if (keybytes > MAX_KEYSIZE) { |
720 | ret = EINVAL; |
721 | goto bail; |
722 | } |
723 | |
724 | (void)memset(inbuf, 0, MAX_KEYSIZE); |
725 | ret = copyin(ci->ci_key, inbuf, keybytes); |
726 | if (ret) |
727 | goto bail; |
728 | |
729 | cs->sc_cdata.cf_blocksize = ci->ci_blocksize; |
730 | cs->sc_cdata.cf_mode = encblkno[i].v; |
731 | cs->sc_cdata.cf_keylen = ci->ci_keylen; |
732 | cs->sc_cdata.cf_priv = cs->sc_cfuncs->cf_init(ci->ci_keylen, inbuf, |
733 | &cs->sc_cdata.cf_blocksize); |
734 | if (cs->sc_cdata.cf_blocksize > CGD_MAXBLOCKSIZE) { |
735 | log(LOG_WARNING, "cgd: Disallowed cipher with blocksize %zu > %u\n" , |
736 | cs->sc_cdata.cf_blocksize, CGD_MAXBLOCKSIZE); |
737 | cs->sc_cdata.cf_priv = NULL; |
738 | } |
739 | |
740 | /* |
741 | * The blocksize is supposed to be in bytes. Unfortunately originally |
742 | * it was expressed in bits. For compatibility we maintain encblkno |
743 | * and encblkno8. |
744 | */ |
745 | cs->sc_cdata.cf_blocksize /= encblkno[i].d; |
746 | (void)explicit_memset(inbuf, 0, MAX_KEYSIZE); |
747 | if (!cs->sc_cdata.cf_priv) { |
748 | ret = EINVAL; /* XXX is this the right error? */ |
749 | goto bail; |
750 | } |
751 | free(inbuf, M_TEMP); |
752 | |
753 | bufq_alloc(&dksc->sc_bufq, "fcfs" , 0); |
754 | |
755 | cs->sc_data = malloc(MAXPHYS, M_DEVBUF, M_WAITOK); |
756 | cs->sc_data_used = 0; |
757 | |
758 | /* Attach the disk. */ |
759 | dk_attach(dksc); |
760 | disk_attach(&dksc->sc_dkdev); |
761 | |
762 | disk_set_info(dksc->sc_dev, &dksc->sc_dkdev, NULL); |
763 | |
764 | /* Discover wedges on this disk. */ |
765 | dkwedge_discover(&dksc->sc_dkdev); |
766 | |
767 | return 0; |
768 | |
769 | bail: |
770 | free(inbuf, M_TEMP); |
771 | (void)vn_close(vp, FREAD|FWRITE, l->l_cred); |
772 | return ret; |
773 | } |
774 | |
775 | /* ARGSUSED */ |
776 | static int |
777 | cgd_ioctl_clr(struct cgd_softc *cs, struct lwp *l) |
778 | { |
779 | struct dk_softc *dksc = &cs->sc_dksc; |
780 | |
781 | if (!DK_ATTACHED(dksc)) |
782 | return ENXIO; |
783 | |
784 | /* Delete all of our wedges. */ |
785 | dkwedge_delall(&dksc->sc_dkdev); |
786 | |
787 | /* Kill off any queued buffers. */ |
788 | dk_drain(dksc); |
789 | bufq_free(dksc->sc_bufq); |
790 | |
791 | (void)vn_close(cs->sc_tvn, FREAD|FWRITE, l->l_cred); |
792 | cs->sc_cfuncs->cf_destroy(cs->sc_cdata.cf_priv); |
793 | free(cs->sc_tpath, M_DEVBUF); |
794 | free(cs->sc_data, M_DEVBUF); |
795 | cs->sc_data_used = 0; |
796 | dk_detach(dksc); |
797 | disk_detach(&dksc->sc_dkdev); |
798 | |
799 | return 0; |
800 | } |
801 | |
802 | static int |
803 | cgd_ioctl_get(dev_t dev, void *data, struct lwp *l) |
804 | { |
805 | struct cgd_softc *cs = getcgd_softc(dev); |
806 | struct cgd_user *cgu; |
807 | int unit; |
808 | struct dk_softc *dksc = &cs->sc_dksc; |
809 | |
810 | unit = CGDUNIT(dev); |
811 | cgu = (struct cgd_user *)data; |
812 | |
813 | DPRINTF_FOLLOW(("cgd_ioctl_get(0x%" PRIx64", %d, %p, %p)\n" , |
814 | dev, unit, data, l)); |
815 | |
816 | if (cgu->cgu_unit == -1) |
817 | cgu->cgu_unit = unit; |
818 | |
819 | if (cgu->cgu_unit < 0) |
820 | return EINVAL; /* XXX: should this be ENXIO? */ |
821 | |
822 | cs = device_lookup_private(&cgd_cd, unit); |
823 | if (cs == NULL || !DK_ATTACHED(dksc)) { |
824 | cgu->cgu_dev = 0; |
825 | cgu->cgu_alg[0] = '\0'; |
826 | cgu->cgu_blocksize = 0; |
827 | cgu->cgu_mode = 0; |
828 | cgu->cgu_keylen = 0; |
829 | } |
830 | else { |
831 | cgu->cgu_dev = cs->sc_tdev; |
832 | strlcpy(cgu->cgu_alg, cs->sc_cfuncs->cf_name, |
833 | sizeof(cgu->cgu_alg)); |
834 | cgu->cgu_blocksize = cs->sc_cdata.cf_blocksize; |
835 | cgu->cgu_mode = cs->sc_cdata.cf_mode; |
836 | cgu->cgu_keylen = cs->sc_cdata.cf_keylen; |
837 | } |
838 | return 0; |
839 | } |
840 | |
841 | static int |
842 | cgdinit(struct cgd_softc *cs, const char *cpath, struct vnode *vp, |
843 | struct lwp *l) |
844 | { |
845 | struct disk_geom *dg; |
846 | int ret; |
847 | char *tmppath; |
848 | uint64_t psize; |
849 | unsigned secsize; |
850 | struct dk_softc *dksc = &cs->sc_dksc; |
851 | |
852 | cs->sc_tvn = vp; |
853 | cs->sc_tpath = NULL; |
854 | |
855 | tmppath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
856 | ret = copyinstr(cpath, tmppath, MAXPATHLEN, &cs->sc_tpathlen); |
857 | if (ret) |
858 | goto bail; |
859 | cs->sc_tpath = malloc(cs->sc_tpathlen, M_DEVBUF, M_WAITOK); |
860 | memcpy(cs->sc_tpath, tmppath, cs->sc_tpathlen); |
861 | |
862 | cs->sc_tdev = vp->v_rdev; |
863 | |
864 | if ((ret = getdisksize(vp, &psize, &secsize)) != 0) |
865 | goto bail; |
866 | |
867 | if (psize == 0) { |
868 | ret = ENODEV; |
869 | goto bail; |
870 | } |
871 | |
872 | /* |
873 | * XXX here we should probe the underlying device. If we |
874 | * are accessing a partition of type RAW_PART, then |
875 | * we should populate our initial geometry with the |
876 | * geometry that we discover from the device. |
877 | */ |
878 | dg = &dksc->sc_dkdev.dk_geom; |
879 | memset(dg, 0, sizeof(*dg)); |
880 | dg->dg_secperunit = psize; |
881 | dg->dg_secsize = secsize; |
882 | dg->dg_ntracks = 1; |
883 | dg->dg_nsectors = 1024 * 1024 / dg->dg_secsize; |
884 | dg->dg_ncylinders = dg->dg_secperunit / dg->dg_nsectors; |
885 | |
886 | bail: |
887 | free(tmppath, M_TEMP); |
888 | if (ret && cs->sc_tpath) |
889 | free(cs->sc_tpath, M_DEVBUF); |
890 | return ret; |
891 | } |
892 | |
893 | /* |
894 | * Our generic cipher entry point. This takes care of the |
895 | * IV mode and passes off the work to the specific cipher. |
896 | * We implement here the IV method ``encrypted block |
897 | * number''. |
898 | * |
899 | * For the encryption case, we accomplish this by setting |
900 | * up a struct uio where the first iovec of the source is |
901 | * the blocknumber and the first iovec of the dest is a |
902 | * sink. We then call the cipher with an IV of zero, and |
903 | * the right thing happens. |
904 | * |
905 | * For the decryption case, we use the same basic mechanism |
906 | * for symmetry, but we encrypt the block number in the |
907 | * first iovec. |
908 | * |
909 | * We mainly do this to avoid requiring the definition of |
910 | * an ECB mode. |
911 | * |
912 | * XXXrcd: for now we rely on our own crypto framework defined |
913 | * in dev/cgd_crypto.c. This will change when we |
914 | * get a generic kernel crypto framework. |
915 | */ |
916 | |
917 | static void |
918 | blkno2blkno_buf(char *sbuf, daddr_t blkno) |
919 | { |
920 | int i; |
921 | |
922 | /* Set up the blkno in blkno_buf, here we do not care much |
923 | * about the final layout of the information as long as we |
924 | * can guarantee that each sector will have a different IV |
925 | * and that the endianness of the machine will not affect |
926 | * the representation that we have chosen. |
927 | * |
928 | * We choose this representation, because it does not rely |
929 | * on the size of buf (which is the blocksize of the cipher), |
930 | * but allows daddr_t to grow without breaking existing |
931 | * disks. |
932 | * |
933 | * Note that blkno2blkno_buf does not take a size as input, |
934 | * and hence must be called on a pre-zeroed buffer of length |
935 | * greater than or equal to sizeof(daddr_t). |
936 | */ |
937 | for (i=0; i < sizeof(daddr_t); i++) { |
938 | *sbuf++ = blkno & 0xff; |
939 | blkno >>= 8; |
940 | } |
941 | } |
942 | |
943 | static void |
944 | cgd_cipher(struct cgd_softc *cs, void *dstv, void *srcv, |
945 | size_t len, daddr_t blkno, size_t secsize, int dir) |
946 | { |
947 | char *dst = dstv; |
948 | char *src = srcv; |
949 | cfunc_cipher *cipher = cs->sc_cfuncs->cf_cipher; |
950 | struct uio dstuio; |
951 | struct uio srcuio; |
952 | struct iovec dstiov[2]; |
953 | struct iovec srciov[2]; |
954 | size_t blocksize = cs->sc_cdata.cf_blocksize; |
955 | size_t todo; |
956 | char sink[CGD_MAXBLOCKSIZE]; |
957 | char zero_iv[CGD_MAXBLOCKSIZE]; |
958 | char blkno_buf[CGD_MAXBLOCKSIZE]; |
959 | |
960 | DPRINTF_FOLLOW(("cgd_cipher() dir=%d\n" , dir)); |
961 | |
962 | DIAGCONDPANIC(len % blocksize != 0, |
963 | ("cgd_cipher: len %% blocksize != 0" )); |
964 | |
965 | /* ensure that sizeof(daddr_t) <= blocksize (for encblkno IVing) */ |
966 | DIAGCONDPANIC(sizeof(daddr_t) > blocksize, |
967 | ("cgd_cipher: sizeof(daddr_t) > blocksize" )); |
968 | |
969 | memset(zero_iv, 0x0, blocksize); |
970 | |
971 | dstuio.uio_iov = dstiov; |
972 | dstuio.uio_iovcnt = 2; |
973 | |
974 | srcuio.uio_iov = srciov; |
975 | srcuio.uio_iovcnt = 2; |
976 | |
977 | dstiov[0].iov_base = sink; |
978 | dstiov[0].iov_len = blocksize; |
979 | srciov[0].iov_base = blkno_buf; |
980 | srciov[0].iov_len = blocksize; |
981 | |
982 | for (; len > 0; len -= todo) { |
983 | todo = MIN(len, secsize); |
984 | |
985 | dstiov[1].iov_base = dst; |
986 | srciov[1].iov_base = src; |
987 | dstiov[1].iov_len = todo; |
988 | srciov[1].iov_len = todo; |
989 | |
990 | memset(blkno_buf, 0x0, blocksize); |
991 | blkno2blkno_buf(blkno_buf, blkno); |
992 | if (dir == CGD_CIPHER_DECRYPT) { |
993 | dstuio.uio_iovcnt = 1; |
994 | srcuio.uio_iovcnt = 1; |
995 | IFDEBUG(CGDB_CRYPTO, hexprint("step 0: blkno_buf" , |
996 | blkno_buf, blocksize)); |
997 | cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, |
998 | zero_iv, CGD_CIPHER_ENCRYPT); |
999 | memcpy(blkno_buf, sink, blocksize); |
1000 | dstuio.uio_iovcnt = 2; |
1001 | srcuio.uio_iovcnt = 2; |
1002 | } |
1003 | |
1004 | IFDEBUG(CGDB_CRYPTO, hexprint("step 1: blkno_buf" , |
1005 | blkno_buf, blocksize)); |
1006 | cipher(cs->sc_cdata.cf_priv, &dstuio, &srcuio, zero_iv, dir); |
1007 | IFDEBUG(CGDB_CRYPTO, hexprint("step 2: sink" , |
1008 | sink, blocksize)); |
1009 | |
1010 | dst += todo; |
1011 | src += todo; |
1012 | blkno++; |
1013 | } |
1014 | } |
1015 | |
1016 | #ifdef DEBUG |
1017 | static void |
1018 | hexprint(const char *start, void *buf, int len) |
1019 | { |
1020 | char *c = buf; |
1021 | |
1022 | DIAGCONDPANIC(len < 0, ("hexprint: called with len < 0" )); |
1023 | printf("%s: len=%06d 0x" , start, len); |
1024 | while (len--) |
1025 | printf("%02x" , (unsigned char) *c++); |
1026 | } |
1027 | #endif |
1028 | |
1029 | MODULE(MODULE_CLASS_DRIVER, cgd, "dk_subr" ); |
1030 | |
1031 | #ifdef _MODULE |
1032 | CFDRIVER_DECL(cgd, DV_DISK, NULL); |
1033 | |
1034 | devmajor_t cgd_bmajor = -1, cgd_cmajor = -1; |
1035 | #endif |
1036 | |
1037 | static int |
1038 | cgd_modcmd(modcmd_t cmd, void *arg) |
1039 | { |
1040 | int error = 0; |
1041 | |
1042 | switch (cmd) { |
1043 | case MODULE_CMD_INIT: |
1044 | #ifdef _MODULE |
1045 | error = config_cfdriver_attach(&cgd_cd); |
1046 | if (error) |
1047 | break; |
1048 | |
1049 | error = config_cfattach_attach(cgd_cd.cd_name, &cgd_ca); |
1050 | if (error) { |
1051 | config_cfdriver_detach(&cgd_cd); |
1052 | aprint_error("%s: unable to register cfattach for" |
1053 | "%s, error %d\n" , __func__, cgd_cd.cd_name, error); |
1054 | break; |
1055 | } |
1056 | /* |
1057 | * Attach the {b,c}devsw's |
1058 | */ |
1059 | error = devsw_attach("cgd" , &cgd_bdevsw, &cgd_bmajor, |
1060 | &cgd_cdevsw, &cgd_cmajor); |
1061 | |
1062 | /* |
1063 | * If devsw_attach fails, remove from autoconf database |
1064 | */ |
1065 | if (error) { |
1066 | config_cfattach_detach(cgd_cd.cd_name, &cgd_ca); |
1067 | config_cfdriver_detach(&cgd_cd); |
1068 | aprint_error("%s: unable to attach %s devsw, " |
1069 | "error %d" , __func__, cgd_cd.cd_name, error); |
1070 | break; |
1071 | } |
1072 | #endif |
1073 | break; |
1074 | |
1075 | case MODULE_CMD_FINI: |
1076 | #ifdef _MODULE |
1077 | /* |
1078 | * Remove {b,c}devsw's |
1079 | */ |
1080 | devsw_detach(&cgd_bdevsw, &cgd_cdevsw); |
1081 | |
1082 | /* |
1083 | * Now remove device from autoconf database |
1084 | */ |
1085 | error = config_cfattach_detach(cgd_cd.cd_name, &cgd_ca); |
1086 | if (error) { |
1087 | (void)devsw_attach("cgd" , &cgd_bdevsw, &cgd_bmajor, |
1088 | &cgd_cdevsw, &cgd_cmajor); |
1089 | aprint_error("%s: failed to detach %s cfattach, " |
1090 | "error %d\n" , __func__, cgd_cd.cd_name, error); |
1091 | break; |
1092 | } |
1093 | error = config_cfdriver_detach(&cgd_cd); |
1094 | if (error) { |
1095 | (void)config_cfattach_attach(cgd_cd.cd_name, &cgd_ca); |
1096 | (void)devsw_attach("cgd" , &cgd_bdevsw, &cgd_bmajor, |
1097 | &cgd_cdevsw, &cgd_cmajor); |
1098 | aprint_error("%s: failed to detach %s cfdriver, " |
1099 | "error %d\n" , __func__, cgd_cd.cd_name, error); |
1100 | break; |
1101 | } |
1102 | #endif |
1103 | break; |
1104 | |
1105 | case MODULE_CMD_STAT: |
1106 | error = ENOTTY; |
1107 | break; |
1108 | default: |
1109 | error = ENOTTY; |
1110 | break; |
1111 | } |
1112 | |
1113 | return error; |
1114 | } |
1115 | |