LCOV - code coverage report
Current view: top level - dev - vnd.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 313 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 15 0.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13