Line data Source code
1 : /* $OpenBSD: vnd.c,v 1.168 2018/04/28 03:13:04 visa Exp $ */
2 : /* $NetBSD: vnd.c,v 1.26 1996/03/30 23:06:11 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1988 University of Utah.
6 : * Copyright (c) 1990, 1993
7 : * The Regents of the University of California. All rights reserved.
8 : *
9 : * This code is derived from software contributed to Berkeley by
10 : * the Systems Programming Group of the University of Utah Computer
11 : * Science Department.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : */
37 :
38 : /*
39 : * There is a security issue involved with this driver.
40 : *
41 : * Once mounted all access to the contents of the "mapped" file via
42 : * the special file is controlled by the permissions on the special
43 : * file, the protection of the mapped file is ignored (effectively,
44 : * by using root credentials in all transactions).
45 : *
46 : */
47 :
48 : #include <sys/param.h>
49 : #include <sys/systm.h>
50 : #include <sys/namei.h>
51 : #include <sys/proc.h>
52 : #include <sys/errno.h>
53 : #include <sys/limits.h>
54 : #include <sys/buf.h>
55 : #include <sys/malloc.h>
56 : #include <sys/ioctl.h>
57 : #include <sys/disklabel.h>
58 : #include <sys/device.h>
59 : #include <sys/disk.h>
60 : #include <sys/stat.h>
61 : #include <sys/vnode.h>
62 : #include <sys/fcntl.h>
63 : #include <sys/uio.h>
64 : #include <sys/conf.h>
65 : #include <sys/dkio.h>
66 : #include <sys/specdev.h>
67 :
68 : #include <crypto/blf.h>
69 :
70 : #include <dev/vndioctl.h>
71 :
72 : #ifdef VNDDEBUG
73 : int vnddebug = 0x00;
74 : #define VDB_FOLLOW 0x01
75 : #define VDB_INIT 0x02
76 : #define VDB_IO 0x04
77 : #define DNPRINTF(f, p...) do { if ((f) & vnddebug) printf(p); } while (0)
78 : #else
79 : #define DNPRINTF(f, p...) /* nothing */
80 : #endif /* VNDDEBUG */
81 :
82 : struct vnd_softc {
83 : struct device sc_dev;
84 : struct disk sc_dk;
85 :
86 : char sc_file[VNDNLEN]; /* file we're covering */
87 : int sc_flags; /* flags */
88 : size_t sc_size; /* size of vnd in sectors */
89 : size_t sc_secsize; /* sector size in bytes */
90 : size_t sc_nsectors; /* # of sectors per track */
91 : size_t sc_ntracks; /* # of tracks per cylinder */
92 : struct vnode *sc_vp; /* vnode */
93 : struct ucred *sc_cred; /* credentials */
94 : blf_ctx *sc_keyctx; /* key context */
95 : };
96 :
97 : /* sc_flags */
98 : #define VNF_INITED 0x0001
99 : #define VNF_HAVELABEL 0x0002
100 : #define VNF_READONLY 0x0004
101 :
102 : #define VNDRW(v) ((v)->sc_flags & VNF_READONLY ? FREAD : FREAD|FWRITE)
103 :
104 : struct vnd_softc *vnd_softc;
105 : int numvnd = 0;
106 :
107 : /* called by main() at boot time */
108 : void vndattach(int);
109 :
110 : void vndclear(struct vnd_softc *);
111 : int vndsetcred(struct vnd_softc *, struct ucred *);
112 : int vndgetdisklabel(dev_t, struct vnd_softc *, struct disklabel *, int);
113 : void vndencrypt(struct vnd_softc *, caddr_t, size_t, daddr_t, int);
114 : void vndencryptbuf(struct vnd_softc *, struct buf *, int);
115 : size_t vndbdevsize(struct vnode *, struct proc *);
116 :
117 : void
118 0 : vndencrypt(struct vnd_softc *sc, caddr_t addr, size_t size, daddr_t off,
119 : int encrypt)
120 : {
121 : int i, bsize;
122 0 : u_char iv[8];
123 :
124 : bsize = dbtob(1);
125 0 : for (i = 0; i < size/bsize; i++) {
126 0 : memset(iv, 0, sizeof(iv));
127 0 : memcpy(iv, &off, sizeof(off));
128 0 : blf_ecb_encrypt(sc->sc_keyctx, iv, sizeof(iv));
129 0 : if (encrypt)
130 0 : blf_cbc_encrypt(sc->sc_keyctx, iv, addr, bsize);
131 : else
132 0 : blf_cbc_decrypt(sc->sc_keyctx, iv, addr, bsize);
133 :
134 0 : addr += bsize;
135 0 : off++;
136 : }
137 0 : }
138 :
139 : void
140 0 : vndencryptbuf(struct vnd_softc *sc, struct buf *bp, int encrypt)
141 : {
142 0 : vndencrypt(sc, bp->b_data, bp->b_bcount, bp->b_blkno, encrypt);
143 0 : }
144 :
145 : void
146 0 : vndattach(int num)
147 : {
148 : char *mem;
149 : int i;
150 :
151 0 : if (num <= 0)
152 0 : return;
153 0 : mem = mallocarray(num, sizeof(struct vnd_softc), M_DEVBUF,
154 : M_NOWAIT | M_ZERO);
155 0 : if (mem == NULL) {
156 0 : printf("WARNING: no memory for vnode disks\n");
157 0 : return;
158 : }
159 0 : vnd_softc = (struct vnd_softc *)mem;
160 0 : for (i = 0; i < num; i++) {
161 0 : struct vnd_softc *sc = &vnd_softc[i];
162 :
163 0 : sc->sc_dev.dv_unit = i;
164 0 : snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname),
165 : "vnd%d", i);
166 0 : disk_construct(&sc->sc_dk);
167 0 : device_ref(&sc->sc_dev);
168 : }
169 0 : numvnd = num;
170 0 : }
171 :
172 : int
173 0 : vndopen(dev_t dev, int flags, int mode, struct proc *p)
174 : {
175 0 : int unit = DISKUNIT(dev);
176 : struct vnd_softc *sc;
177 : int error = 0, part;
178 :
179 : DNPRINTF(VDB_FOLLOW, "vndopen(%x, %x, %x, %p)\n", dev, flags, mode, p);
180 :
181 0 : if (unit >= numvnd)
182 0 : return (ENXIO);
183 0 : sc = &vnd_softc[unit];
184 :
185 0 : if ((error = disk_lock(&sc->sc_dk)) != 0)
186 0 : return (error);
187 :
188 0 : if ((flags & FWRITE) && (sc->sc_flags & VNF_READONLY)) {
189 : error = EROFS;
190 0 : goto bad;
191 : }
192 :
193 0 : if ((sc->sc_flags & VNF_INITED) &&
194 0 : (sc->sc_flags & VNF_HAVELABEL) == 0 &&
195 0 : sc->sc_dk.dk_openmask == 0) {
196 0 : sc->sc_flags |= VNF_HAVELABEL;
197 0 : vndgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
198 0 : }
199 :
200 0 : part = DISKPART(dev);
201 0 : error = disk_openpart(&sc->sc_dk, part, mode,
202 0 : (sc->sc_flags & VNF_HAVELABEL) != 0);
203 :
204 : bad:
205 0 : disk_unlock(&sc->sc_dk);
206 0 : return (error);
207 0 : }
208 :
209 : /*
210 : * Load the label information on the named device
211 : */
212 : int
213 0 : vndgetdisklabel(dev_t dev, struct vnd_softc *sc, struct disklabel *lp,
214 : int spoofonly)
215 : {
216 0 : memset(lp, 0, sizeof(struct disklabel));
217 :
218 0 : lp->d_secsize = sc->sc_secsize;
219 0 : lp->d_nsectors = sc->sc_nsectors;
220 0 : lp->d_ntracks = sc->sc_ntracks;
221 0 : lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
222 0 : if (lp->d_secpercyl)
223 0 : lp->d_ncylinders = sc->sc_size / lp->d_secpercyl;
224 :
225 0 : strncpy(lp->d_typename, "vnd device", sizeof(lp->d_typename));
226 0 : lp->d_type = DTYPE_VND;
227 0 : strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
228 0 : DL_SETDSIZE(lp, sc->sc_size);
229 0 : lp->d_flags = 0;
230 0 : lp->d_version = 1;
231 :
232 0 : lp->d_magic = DISKMAGIC;
233 0 : lp->d_magic2 = DISKMAGIC;
234 0 : lp->d_checksum = dkcksum(lp);
235 :
236 : /* Call the generic disklabel extraction routine */
237 0 : return readdisklabel(DISKLABELDEV(dev), vndstrategy, lp, spoofonly);
238 : }
239 :
240 : int
241 0 : vndclose(dev_t dev, int flags, int mode, struct proc *p)
242 : {
243 0 : int unit = DISKUNIT(dev);
244 : struct vnd_softc *sc;
245 : int part;
246 :
247 : DNPRINTF(VDB_FOLLOW, "vndclose(%x, %x, %x, %p)\n", dev, flags, mode, p);
248 :
249 0 : if (unit >= numvnd)
250 0 : return (ENXIO);
251 0 : sc = &vnd_softc[unit];
252 :
253 0 : disk_lock_nointr(&sc->sc_dk);
254 :
255 0 : part = DISKPART(dev);
256 :
257 0 : disk_closepart(&sc->sc_dk, part, mode);
258 :
259 : #if 0
260 : if (sc->sc_dk.dk_openmask == 0)
261 : sc->sc_flags &= ~VNF_HAVELABEL;
262 : #endif
263 :
264 0 : disk_unlock(&sc->sc_dk);
265 0 : return (0);
266 0 : }
267 :
268 : void
269 0 : vndstrategy(struct buf *bp)
270 : {
271 0 : int unit = DISKUNIT(bp->b_dev);
272 : struct vnd_softc *sc;
273 : struct partition *p;
274 : off_t off;
275 : long origbcount;
276 : int s;
277 :
278 : DNPRINTF(VDB_FOLLOW, "vndstrategy(%p): unit %d\n", bp, unit);
279 :
280 0 : if (unit >= numvnd) {
281 0 : bp->b_error = ENXIO;
282 0 : goto bad;
283 : }
284 0 : sc = &vnd_softc[unit];
285 :
286 0 : if ((sc->sc_flags & VNF_HAVELABEL) == 0) {
287 0 : bp->b_error = ENXIO;
288 0 : goto bad;
289 : }
290 :
291 : /*
292 : * Many of the distrib scripts assume they can issue arbitrary
293 : * sized requests to raw vnd devices irrespective of the
294 : * emulated disk geometry.
295 : *
296 : * To continue supporting this, round the block count up to a
297 : * multiple of d_secsize for bounds_check_with_label(), and
298 : * then restore afterwards.
299 : *
300 : * We only do this for non-encrypted vnd, because encryption
301 : * requires operating on blocks at a time.
302 : */
303 0 : origbcount = bp->b_bcount;
304 0 : if (sc->sc_keyctx == NULL) {
305 0 : u_int32_t secsize = sc->sc_dk.dk_label->d_secsize;
306 0 : bp->b_bcount = ((origbcount + secsize - 1) & ~(secsize - 1));
307 : #ifdef DIAGNOSTIC
308 0 : if (bp->b_bcount != origbcount) {
309 0 : struct process *curpr = curproc->p_p;
310 0 : printf("%s: sloppy %s from proc %d (%s): "
311 0 : "blkno %lld bcount %ld\n", sc->sc_dev.dv_xname,
312 0 : (bp->b_flags & B_READ) ? "read" : "write",
313 0 : curpr->ps_pid, curpr->ps_comm,
314 0 : (long long)bp->b_blkno, origbcount);
315 0 : }
316 : #endif
317 0 : }
318 :
319 0 : if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) {
320 0 : bp->b_resid = bp->b_bcount = origbcount;
321 0 : goto done;
322 : }
323 :
324 0 : if (origbcount < bp->b_bcount)
325 0 : bp->b_bcount = origbcount;
326 :
327 0 : p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
328 0 : off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize +
329 0 : (u_int64_t)bp->b_blkno * DEV_BSIZE;
330 :
331 0 : if (sc->sc_keyctx && !(bp->b_flags & B_READ))
332 0 : vndencryptbuf(sc, bp, 1);
333 :
334 : /*
335 : * Use IO_NOLIMIT because upper layer has already checked I/O
336 : * for limits, so there is no need to do it again.
337 : */
338 0 : bp->b_error = vn_rdwr((bp->b_flags & B_READ) ? UIO_READ : UIO_WRITE,
339 0 : sc->sc_vp, bp->b_data, bp->b_bcount, off, UIO_SYSSPACE, IO_NOLIMIT,
340 0 : sc->sc_cred, &bp->b_resid, curproc);
341 0 : if (bp->b_error)
342 0 : bp->b_flags |= B_ERROR;
343 :
344 : /* Data in buffer cache needs to be in clear */
345 0 : if (sc->sc_keyctx)
346 0 : vndencryptbuf(sc, bp, 0);
347 :
348 : goto done;
349 :
350 : bad:
351 0 : bp->b_flags |= B_ERROR;
352 0 : bp->b_resid = bp->b_bcount;
353 : done:
354 0 : s = splbio();
355 0 : biodone(bp);
356 0 : splx(s);
357 0 : }
358 :
359 : /* ARGSUSED */
360 : int
361 0 : vndread(dev_t dev, struct uio *uio, int flags)
362 : {
363 0 : return (physio(vndstrategy, dev, B_READ, minphys, uio));
364 : }
365 :
366 : /* ARGSUSED */
367 : int
368 0 : vndwrite(dev_t dev, struct uio *uio, int flags)
369 : {
370 0 : return (physio(vndstrategy, dev, B_WRITE, minphys, uio));
371 : }
372 :
373 : size_t
374 0 : vndbdevsize(struct vnode *vp, struct proc *p)
375 : {
376 0 : struct partinfo pi;
377 : struct bdevsw *bsw;
378 : dev_t dev;
379 :
380 0 : dev = vp->v_rdev;
381 0 : bsw = bdevsw_lookup(dev);
382 0 : if (bsw->d_ioctl == NULL)
383 0 : return (0);
384 0 : if (bsw->d_ioctl(dev, DIOCGPART, (caddr_t)&pi, FREAD, p))
385 0 : return (0);
386 : DNPRINTF(VDB_INIT, "vndbdevsize: size %llu secsize %u\n",
387 : DL_GETPSIZE(pi.part), pi.disklab->d_secsize);
388 0 : return (DL_GETPSIZE(pi.part));
389 0 : }
390 :
391 : /* ARGSUSED */
392 : int
393 0 : vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
394 : {
395 0 : int unit = DISKUNIT(dev);
396 : struct disklabel *lp;
397 : struct vnd_softc *sc;
398 : struct vnd_ioctl *vio;
399 : struct vnd_user *vnu;
400 0 : struct vattr vattr;
401 0 : struct nameidata nd;
402 : int error, part, pmask;
403 :
404 : DNPRINTF(VDB_FOLLOW, "vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
405 : dev, cmd, addr, flag, p, unit);
406 :
407 0 : error = suser(p);
408 0 : if (error)
409 0 : return (error);
410 0 : if (unit >= numvnd)
411 0 : return (ENXIO);
412 :
413 0 : sc = &vnd_softc[unit];
414 0 : vio = (struct vnd_ioctl *)addr;
415 0 : switch (cmd) {
416 :
417 : case VNDIOCSET:
418 0 : if (sc->sc_flags & VNF_INITED)
419 0 : return (EBUSY);
420 :
421 : /* Geometry eventually has to fit into label fields */
422 0 : if (vio->vnd_secsize > UINT_MAX ||
423 0 : vio->vnd_secsize == 0 ||
424 0 : vio->vnd_ntracks > UINT_MAX ||
425 0 : vio->vnd_nsectors > UINT_MAX)
426 0 : return (EINVAL);
427 :
428 0 : if ((error = disk_lock(&sc->sc_dk)) != 0)
429 0 : return (error);
430 :
431 0 : if ((error = copyinstr(vio->vnd_file, sc->sc_file,
432 : sizeof(sc->sc_file), NULL))) {
433 0 : disk_unlock(&sc->sc_dk);
434 0 : return (error);
435 : }
436 :
437 : /* Set geometry for device. */
438 0 : sc->sc_secsize = vio->vnd_secsize;
439 0 : sc->sc_ntracks = vio->vnd_ntracks;
440 0 : sc->sc_nsectors = vio->vnd_nsectors;
441 :
442 : /*
443 : * Open for read and write first. This lets vn_open() weed out
444 : * directories, sockets, etc. so we don't have to worry about
445 : * them.
446 : */
447 0 : NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
448 0 : sc->sc_flags &= ~VNF_READONLY;
449 0 : error = vn_open(&nd, FREAD|FWRITE, 0);
450 0 : if (error == EROFS) {
451 0 : sc->sc_flags |= VNF_READONLY;
452 0 : error = vn_open(&nd, FREAD, 0);
453 0 : }
454 0 : if (error) {
455 0 : disk_unlock(&sc->sc_dk);
456 0 : return (error);
457 : }
458 :
459 0 : if (nd.ni_vp->v_type == VBLK)
460 0 : sc->sc_size = vndbdevsize(nd.ni_vp, p);
461 : else {
462 0 : error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
463 0 : if (error) {
464 0 : VOP_UNLOCK(nd.ni_vp);
465 0 : vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p);
466 0 : disk_unlock(&sc->sc_dk);
467 0 : return (error);
468 : }
469 0 : sc->sc_size = vattr.va_size / sc->sc_secsize;
470 : }
471 0 : VOP_UNLOCK(nd.ni_vp);
472 0 : sc->sc_vp = nd.ni_vp;
473 0 : if ((error = vndsetcred(sc, p->p_ucred)) != 0) {
474 0 : (void) vn_close(nd.ni_vp, VNDRW(sc), p->p_ucred, p);
475 0 : disk_unlock(&sc->sc_dk);
476 0 : return (error);
477 : }
478 :
479 0 : if (vio->vnd_keylen > 0) {
480 0 : char key[BLF_MAXUTILIZED];
481 :
482 0 : if (vio->vnd_keylen > sizeof(key))
483 0 : vio->vnd_keylen = sizeof(key);
484 :
485 0 : if ((error = copyin(vio->vnd_key, key,
486 0 : vio->vnd_keylen)) != 0) {
487 0 : (void) vn_close(nd.ni_vp, VNDRW(sc),
488 0 : p->p_ucred, p);
489 0 : disk_unlock(&sc->sc_dk);
490 0 : return (error);
491 : }
492 :
493 0 : sc->sc_keyctx = malloc(sizeof(*sc->sc_keyctx), M_DEVBUF,
494 : M_WAITOK);
495 0 : blf_key(sc->sc_keyctx, key, vio->vnd_keylen);
496 0 : explicit_bzero(key, vio->vnd_keylen);
497 0 : } else
498 0 : sc->sc_keyctx = NULL;
499 :
500 0 : vio->vnd_size = sc->sc_size * sc->sc_secsize;
501 0 : sc->sc_flags |= VNF_INITED;
502 :
503 : DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n",
504 : sc->sc_vp, (unsigned long long)sc->sc_size);
505 :
506 : /* Attach the disk. */
507 0 : sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
508 0 : disk_attach(&sc->sc_dev, &sc->sc_dk);
509 :
510 0 : disk_unlock(&sc->sc_dk);
511 :
512 0 : break;
513 :
514 : case VNDIOCCLR:
515 0 : if ((sc->sc_flags & VNF_INITED) == 0)
516 0 : return (ENXIO);
517 :
518 0 : if ((error = disk_lock(&sc->sc_dk)) != 0)
519 0 : return (error);
520 :
521 : /*
522 : * Don't unconfigure if any other partitions are open
523 : * or if both the character and block flavors of this
524 : * partition are open.
525 : */
526 0 : part = DISKPART(dev);
527 0 : pmask = (1 << part);
528 0 : if ((sc->sc_dk.dk_openmask & ~pmask) ||
529 0 : ((sc->sc_dk.dk_bopenmask & pmask) &&
530 0 : (sc->sc_dk.dk_copenmask & pmask))) {
531 0 : disk_unlock(&sc->sc_dk);
532 0 : return (EBUSY);
533 : }
534 :
535 0 : vndclear(sc);
536 : DNPRINTF(VDB_INIT, "vndioctl: CLRed\n");
537 :
538 : /* Free crypto key */
539 0 : if (sc->sc_keyctx) {
540 0 : explicit_bzero(sc->sc_keyctx, sizeof(*sc->sc_keyctx));
541 0 : free(sc->sc_keyctx, M_DEVBUF, sizeof(*sc->sc_keyctx));
542 0 : }
543 :
544 : /* Detach the disk. */
545 0 : disk_detach(&sc->sc_dk);
546 0 : disk_unlock(&sc->sc_dk);
547 0 : break;
548 :
549 : case VNDIOCGET:
550 0 : vnu = (struct vnd_user *)addr;
551 :
552 0 : if (vnu->vnu_unit == -1)
553 0 : vnu->vnu_unit = unit;
554 0 : if (vnu->vnu_unit >= numvnd)
555 0 : return (ENXIO);
556 0 : if (vnu->vnu_unit < 0)
557 0 : return (EINVAL);
558 :
559 0 : sc = &vnd_softc[vnu->vnu_unit];
560 :
561 0 : if (sc->sc_flags & VNF_INITED) {
562 0 : error = VOP_GETATTR(sc->sc_vp, &vattr, p->p_ucred, p);
563 0 : if (error)
564 0 : return (error);
565 :
566 0 : strlcpy(vnu->vnu_file, sc->sc_file,
567 : sizeof(vnu->vnu_file));
568 0 : vnu->vnu_dev = vattr.va_fsid;
569 0 : vnu->vnu_ino = vattr.va_fileid;
570 0 : } else {
571 0 : vnu->vnu_dev = 0;
572 0 : vnu->vnu_ino = 0;
573 : }
574 :
575 : break;
576 :
577 : case DIOCRLDINFO:
578 0 : if ((sc->sc_flags & VNF_HAVELABEL) == 0)
579 0 : return (ENOTTY);
580 0 : lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
581 0 : vndgetdisklabel(dev, sc, lp, 0);
582 0 : *(sc->sc_dk.dk_label) = *lp;
583 0 : free(lp, M_TEMP, sizeof(*lp));
584 0 : return (0);
585 :
586 : case DIOCGPDINFO:
587 0 : if ((sc->sc_flags & VNF_HAVELABEL) == 0)
588 0 : return (ENOTTY);
589 0 : vndgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
590 0 : return (0);
591 :
592 : case DIOCGDINFO:
593 0 : if ((sc->sc_flags & VNF_HAVELABEL) == 0)
594 0 : return (ENOTTY);
595 0 : *(struct disklabel *)addr = *(sc->sc_dk.dk_label);
596 0 : return (0);
597 :
598 : case DIOCGPART:
599 0 : if ((sc->sc_flags & VNF_HAVELABEL) == 0)
600 0 : return (ENOTTY);
601 0 : ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
602 0 : ((struct partinfo *)addr)->part =
603 0 : &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
604 0 : return (0);
605 :
606 : case DIOCWDINFO:
607 : case DIOCSDINFO:
608 0 : if ((sc->sc_flags & VNF_HAVELABEL) == 0)
609 0 : return (ENOTTY);
610 0 : if ((flag & FWRITE) == 0)
611 0 : return (EBADF);
612 :
613 0 : if ((error = disk_lock(&sc->sc_dk)) != 0)
614 0 : return (error);
615 :
616 0 : error = setdisklabel(sc->sc_dk.dk_label,
617 0 : (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0);
618 0 : if (error == 0) {
619 0 : if (cmd == DIOCWDINFO)
620 0 : error = writedisklabel(DISKLABELDEV(dev),
621 0 : vndstrategy, sc->sc_dk.dk_label);
622 : }
623 :
624 0 : disk_unlock(&sc->sc_dk);
625 0 : return (error);
626 :
627 : default:
628 0 : return (ENOTTY);
629 : }
630 :
631 0 : return (0);
632 0 : }
633 :
634 : /*
635 : * Duplicate the current processes' credentials. Since we are called only
636 : * as the result of a SET ioctl and only root can do that, any future access
637 : * to this "disk" is essentially as root. Note that credentials may change
638 : * if some other uid can write directly to the mapped file (NFS).
639 : */
640 : int
641 0 : vndsetcred(struct vnd_softc *sc, struct ucred *cred)
642 : {
643 : void *buf;
644 : size_t size;
645 : int error;
646 :
647 0 : sc->sc_cred = crdup(cred);
648 0 : buf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
649 0 : size = MIN(DEV_BSIZE, sc->sc_size * sc->sc_secsize);
650 :
651 : /* XXX: Horrible kludge to establish credentials for NFS */
652 0 : error = vn_rdwr(UIO_READ, sc->sc_vp, buf, size, 0, UIO_SYSSPACE, 0,
653 0 : sc->sc_cred, NULL, curproc);
654 :
655 0 : free(buf, M_TEMP, DEV_BSIZE);
656 0 : return (error);
657 : }
658 :
659 : void
660 0 : vndclear(struct vnd_softc *sc)
661 : {
662 0 : struct vnode *vp = sc->sc_vp;
663 0 : struct proc *p = curproc; /* XXX */
664 :
665 : DNPRINTF(VDB_FOLLOW, "vndclear(%p): vp %p\n", sc, vp);
666 :
667 0 : if (vp == NULL)
668 0 : panic("vndioctl: null vp");
669 0 : (void) vn_close(vp, VNDRW(sc), sc->sc_cred, p);
670 0 : crfree(sc->sc_cred);
671 0 : sc->sc_flags = 0;
672 0 : sc->sc_vp = NULL;
673 0 : sc->sc_cred = NULL;
674 0 : sc->sc_size = 0;
675 0 : memset(sc->sc_file, 0, sizeof(sc->sc_file));
676 0 : }
677 :
678 : daddr_t
679 0 : vndsize(dev_t dev)
680 : {
681 : /* We don't support swapping to vnd anymore. */
682 0 : return (-1);
683 : }
684 :
685 : int
686 0 : vnddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
687 : {
688 : /* Not implemented. */
689 0 : return (ENXIO);
690 : }
|