The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/vnd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $OpenBSD: vnd.c,v 1.179 2022/10/23 14:39:19 krw 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 proc *p, struct vnode *, struct vnd_ioctl *,
  112             struct ucred **);
  113 int     vndgetdisklabel(dev_t, struct vnd_softc *, struct disklabel *, int);
  114 void    vndencrypt(struct vnd_softc *, caddr_t, size_t, daddr_t, int);
  115 void    vndencryptbuf(struct vnd_softc *, struct buf *, int);
  116 size_t  vndbdevsize(struct vnode *, struct proc *);
  117 
  118 void
  119 vndencrypt(struct vnd_softc *sc, caddr_t addr, size_t size, daddr_t off,
  120     int encrypt)
  121 {
  122         int i, bsize;
  123         u_char iv[8];
  124 
  125         bsize = dbtob(1);
  126         for (i = 0; i < size/bsize; i++) {
  127                 memset(iv, 0, sizeof(iv));
  128                 memcpy(iv, &off, sizeof(off));
  129                 blf_ecb_encrypt(sc->sc_keyctx, iv, sizeof(iv));
  130                 if (encrypt)
  131                         blf_cbc_encrypt(sc->sc_keyctx, iv, addr, bsize);
  132                 else
  133                         blf_cbc_decrypt(sc->sc_keyctx, iv, addr, bsize);
  134 
  135                 addr += bsize;
  136                 off++;
  137         }
  138 }
  139 
  140 void
  141 vndencryptbuf(struct vnd_softc *sc, struct buf *bp, int encrypt)
  142 {
  143         vndencrypt(sc, bp->b_data, bp->b_bcount, bp->b_blkno, encrypt);
  144 }
  145 
  146 void
  147 vndattach(int num)
  148 {
  149         char *mem;
  150         int i;
  151 
  152         if (num <= 0)
  153                 return;
  154         mem = mallocarray(num, sizeof(struct vnd_softc), M_DEVBUF,
  155             M_NOWAIT | M_ZERO);
  156         if (mem == NULL) {
  157                 printf("WARNING: no memory for vnode disks\n");
  158                 return;
  159         }
  160         vnd_softc = (struct vnd_softc *)mem;
  161         for (i = 0; i < num; i++) {
  162                 struct vnd_softc *sc = &vnd_softc[i];
  163 
  164                 sc->sc_dev.dv_unit = i;
  165                 snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname),
  166                     "vnd%d", i);
  167                 disk_construct(&sc->sc_dk);
  168                 device_ref(&sc->sc_dev);
  169         }
  170         numvnd = num;
  171 }
  172 
  173 int
  174 vndopen(dev_t dev, int flags, int mode, struct proc *p)
  175 {
  176         int unit = DISKUNIT(dev);
  177         struct vnd_softc *sc;
  178         int error = 0, part;
  179 
  180         DNPRINTF(VDB_FOLLOW, "vndopen(%x, %x, %x, %p)\n", dev, flags, mode, p);
  181 
  182         if (unit >= numvnd)
  183                 return (ENXIO);
  184         sc = &vnd_softc[unit];
  185 
  186         if ((error = disk_lock(&sc->sc_dk)) != 0)
  187                 return (error);
  188 
  189         if ((flags & FWRITE) && (sc->sc_flags & VNF_READONLY)) {
  190                 error = EROFS;
  191                 goto bad;
  192         }
  193 
  194         if ((sc->sc_flags & VNF_INITED) &&
  195             (sc->sc_flags & VNF_HAVELABEL) == 0 &&
  196             sc->sc_dk.dk_openmask == 0) {
  197                 sc->sc_flags |= VNF_HAVELABEL;
  198                 vndgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0);
  199         }
  200 
  201         part = DISKPART(dev);
  202         error = disk_openpart(&sc->sc_dk, part, mode,
  203             (sc->sc_flags & VNF_HAVELABEL) != 0);
  204 
  205 bad:
  206         disk_unlock(&sc->sc_dk);
  207         return (error);
  208 }
  209 
  210 /*
  211  * Load the label information on the named device
  212  */
  213 int
  214 vndgetdisklabel(dev_t dev, struct vnd_softc *sc, struct disklabel *lp,
  215     int spoofonly)
  216 {
  217         memset(lp, 0, sizeof(struct disklabel));
  218 
  219         lp->d_secsize = sc->sc_secsize;
  220         lp->d_nsectors = sc->sc_nsectors;
  221         lp->d_ntracks = sc->sc_ntracks;
  222         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
  223         if (lp->d_secpercyl)
  224                 lp->d_ncylinders = sc->sc_size / lp->d_secpercyl;
  225 
  226         strncpy(lp->d_typename, "vnd device", sizeof(lp->d_typename));
  227         lp->d_type = DTYPE_VND;
  228         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
  229         DL_SETDSIZE(lp, sc->sc_size);
  230         lp->d_version = 1;
  231 
  232         lp->d_magic = DISKMAGIC;
  233         lp->d_magic2 = DISKMAGIC;
  234         lp->d_checksum = dkcksum(lp);
  235 
  236         /* Call the generic disklabel extraction routine */
  237         return readdisklabel(DISKLABELDEV(dev), vndstrategy, lp, spoofonly);
  238 }
  239 
  240 int
  241 vndclose(dev_t dev, int flags, int mode, struct proc *p)
  242 {
  243         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         if (unit >= numvnd)
  250                 return (ENXIO);
  251         sc = &vnd_softc[unit];
  252 
  253         disk_lock_nointr(&sc->sc_dk);
  254 
  255         part = DISKPART(dev);
  256 
  257         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         disk_unlock(&sc->sc_dk);
  265         return (0);
  266 }
  267 
  268 void
  269 vndstrategy(struct buf *bp)
  270 {
  271         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         if (unit >= numvnd) {
  281                 bp->b_error = ENXIO;
  282                 goto bad;
  283         }
  284         sc = &vnd_softc[unit];
  285 
  286         if ((sc->sc_flags & VNF_HAVELABEL) == 0) {
  287                 bp->b_error = ENXIO;
  288                 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         origbcount = bp->b_bcount;
  304         if (sc->sc_keyctx == NULL) {
  305                 u_int32_t secsize = sc->sc_dk.dk_label->d_secsize;
  306                 bp->b_bcount = ((origbcount + secsize - 1) & ~(secsize - 1));
  307 #ifdef DIAGNOSTIC
  308                 if (bp->b_bcount != origbcount) {
  309                         struct process *curpr = curproc->p_p;
  310                         printf("%s: sloppy %s from proc %d (%s): "
  311                             "blkno %lld bcount %ld\n", sc->sc_dev.dv_xname,
  312                             (bp->b_flags & B_READ) ? "read" : "write",
  313                             curpr->ps_pid, curpr->ps_comm,
  314                             (long long)bp->b_blkno, origbcount);
  315                 }
  316 #endif
  317         }
  318 
  319         if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) {
  320                 bp->b_resid = bp->b_bcount = origbcount;
  321                 goto done;
  322         }
  323 
  324         if (origbcount < bp->b_bcount)
  325                 bp->b_bcount = origbcount;
  326 
  327         p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
  328         off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize +
  329             (u_int64_t)bp->b_blkno * DEV_BSIZE;
  330 
  331         if (sc->sc_keyctx && !(bp->b_flags & B_READ))
  332                 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          * We use IO_NOCACHE because this data should be cached at the
  339          * upper layer, so there is no need to cache it again.
  340          */
  341         bp->b_error = vn_rdwr((bp->b_flags & B_READ) ? UIO_READ : UIO_WRITE,
  342             sc->sc_vp, bp->b_data, bp->b_bcount, off, UIO_SYSSPACE,
  343             IO_NOCACHE | IO_SYNC | IO_NOLIMIT, sc->sc_cred, &bp->b_resid, curproc);
  344         if (bp->b_error)
  345                 bp->b_flags |= B_ERROR;
  346 
  347         /* Data in buffer cache needs to be in clear */
  348         if (sc->sc_keyctx)
  349                 vndencryptbuf(sc, bp, 0);
  350 
  351         goto done;
  352 
  353  bad:
  354         bp->b_flags |= B_ERROR;
  355         bp->b_resid = bp->b_bcount;
  356  done:
  357         s = splbio();
  358         biodone(bp);
  359         splx(s);
  360 }
  361 
  362 /* ARGSUSED */
  363 int
  364 vndread(dev_t dev, struct uio *uio, int flags)
  365 {
  366         return (physio(vndstrategy, dev, B_READ, minphys, uio));
  367 }
  368 
  369 /* ARGSUSED */
  370 int
  371 vndwrite(dev_t dev, struct uio *uio, int flags)
  372 {
  373         return (physio(vndstrategy, dev, B_WRITE, minphys, uio));
  374 }
  375 
  376 size_t
  377 vndbdevsize(struct vnode *vp, struct proc *p)
  378 {
  379         struct partinfo pi;
  380         struct bdevsw *bsw;
  381         dev_t dev;
  382 
  383         dev = vp->v_rdev;
  384         bsw = bdevsw_lookup(dev);
  385         if (bsw->d_ioctl == NULL)
  386                 return (0);
  387         if (bsw->d_ioctl(dev, DIOCGPART, (caddr_t)&pi, FREAD, p))
  388                 return (0);
  389         DNPRINTF(VDB_INIT, "vndbdevsize: size %llu secsize %u\n",
  390             DL_GETPSIZE(pi.part), pi.disklab->d_secsize);
  391         return (DL_GETPSIZE(pi.part));
  392 }
  393 
  394 /* ARGSUSED */
  395 int
  396 vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
  397 {
  398         int unit = DISKUNIT(dev);
  399         struct disklabel *lp;
  400         struct vnd_softc *sc;
  401         struct vnd_ioctl *vio;
  402         struct vnd_user *vnu;
  403         struct vattr vattr;
  404         int error, part, pmask;
  405 
  406         DNPRINTF(VDB_FOLLOW, "vndioctl(%x, %lx, %p, %x, %p): unit %d\n",
  407             dev, cmd, addr, flag, p, unit);
  408 
  409         error = suser(p);
  410         if (error)
  411                 return (error);
  412         if (unit >= numvnd)
  413                 return (ENXIO);
  414 
  415         sc = &vnd_softc[unit];
  416         vio = (struct vnd_ioctl *)addr;
  417         switch (cmd) {
  418 
  419         case VNDIOCSET:
  420             {
  421                 char name[VNDNLEN], key[BLF_MAXUTILIZED];
  422                 struct nameidata nd;
  423                 struct ucred *cred = NULL;
  424                 size_t size;
  425                 int vplocked;
  426                 int rw;
  427 
  428                 if (sc->sc_flags & VNF_INITED)
  429                         return (EBUSY);
  430 
  431                 /* Geometry eventually has to fit into label fields */
  432                 if (vio->vnd_secsize > UINT_MAX ||
  433                     vio->vnd_secsize == 0 ||
  434                     vio->vnd_ntracks > UINT_MAX ||
  435                     vio->vnd_nsectors > UINT_MAX)
  436                         return (EINVAL);
  437 
  438                 if ((error = copyinstr(vio->vnd_file, name,
  439                     sizeof(name), NULL)))
  440                         return (error);
  441 
  442                 if (vio->vnd_keylen > 0) {
  443                         if (vio->vnd_keylen > sizeof(key))
  444                                 vio->vnd_keylen = sizeof(key);
  445 
  446                         if ((error = copyin(vio->vnd_key, key,
  447                             vio->vnd_keylen)) != 0)
  448                                 return (error);
  449                 }
  450 
  451                 /*
  452                  * Open for read and write first. This lets vn_open() weed out
  453                  * directories, sockets, etc. so we don't have to worry about
  454                  * them.
  455                  */
  456                 NDINIT(&nd, 0, 0, UIO_SYSSPACE, name, p);
  457                 nd.ni_unveil = UNVEIL_READ | UNVEIL_WRITE;
  458                 rw = FREAD|FWRITE;
  459                 error = vn_open(&nd, FREAD|FWRITE, 0);
  460                 if (error == EROFS) {
  461                         NDINIT(&nd, 0, 0, UIO_SYSSPACE, name, p);
  462                         nd.ni_unveil = UNVEIL_READ | UNVEIL_WRITE;
  463                         rw = FREAD;
  464                         error = vn_open(&nd, FREAD, 0);
  465                 }
  466                 if (error)
  467                         return (error);
  468                 vplocked = 1;
  469 
  470                 error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
  471                 if (error) {
  472 fail:
  473                         if (vplocked)
  474                                 VOP_UNLOCK(nd.ni_vp);
  475                         vn_close(nd.ni_vp, rw, p->p_ucred, p);
  476                         if (cred != NULL)
  477                                 crfree(cred);
  478                         return (error);
  479                 }
  480 
  481                 /* Cannot put a vnd on top of a vnd */
  482                 if (major(vattr.va_fsid) == major(dev)) {
  483                         error = EINVAL;
  484                         goto fail;
  485                 }
  486 
  487                 if ((error = vndsetcred(p, nd.ni_vp, vio, &cred)) != 0)
  488                         goto fail;
  489 
  490                 VOP_UNLOCK(nd.ni_vp);
  491                 vplocked = 0;
  492 
  493                 if (nd.ni_vp->v_type == VBLK) {
  494                         size = vndbdevsize(nd.ni_vp, p);
  495                         /* XXX is size 0 ok? */
  496                 } else
  497                         size = vattr.va_size / vio->vnd_secsize;
  498 
  499                 if ((error = disk_lock(&sc->sc_dk)) != 0)
  500                         goto fail;
  501                 if (sc->sc_flags & VNF_INITED) {
  502                         disk_unlock(&sc->sc_dk);
  503                         error = EBUSY;
  504                         goto fail;
  505                 }
  506 
  507                 /* Set geometry for device. */
  508                 sc->sc_secsize = vio->vnd_secsize;
  509                 sc->sc_ntracks = vio->vnd_ntracks;
  510                 sc->sc_nsectors = vio->vnd_nsectors;
  511                 sc->sc_size = size;
  512 
  513                 if (rw == FREAD)
  514                         sc->sc_flags |= VNF_READONLY;
  515                 else
  516                         sc->sc_flags &= ~VNF_READONLY;
  517 
  518                 memcpy(sc->sc_file, name, sizeof(sc->sc_file));
  519 
  520                 if (vio->vnd_keylen > 0) {
  521                         sc->sc_keyctx = malloc(sizeof(*sc->sc_keyctx), M_DEVBUF,
  522                             M_WAITOK);
  523                         blf_key(sc->sc_keyctx, key, vio->vnd_keylen);
  524                         explicit_bzero(key, vio->vnd_keylen);
  525                 } else
  526                         sc->sc_keyctx = NULL;
  527 
  528                 sc->sc_vp = nd.ni_vp;
  529                 sc->sc_cred = cred;
  530                 vio->vnd_size = sc->sc_size * sc->sc_secsize;
  531                 sc->sc_flags |= VNF_INITED;
  532 
  533                 DNPRINTF(VDB_INIT, "vndioctl: SET vp %p size %llx\n",
  534                     sc->sc_vp, (unsigned long long)sc->sc_size);
  535 
  536                 /* Attach the disk. */
  537                 sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
  538                 disk_attach(&sc->sc_dev, &sc->sc_dk);
  539 
  540                 disk_unlock(&sc->sc_dk);
  541 
  542                 break;
  543             }
  544         case VNDIOCCLR:
  545                 if ((error = disk_lock(&sc->sc_dk)) != 0)
  546                         return (error);
  547                 if ((sc->sc_flags & VNF_INITED) == 0) {
  548                         disk_unlock(&sc->sc_dk);
  549                         return (ENXIO);
  550                 }
  551 
  552                 /*
  553                  * Don't unconfigure if any other partitions are open
  554                  * or if both the character and block flavors of this
  555                  * partition are open.
  556                  */
  557                 part = DISKPART(dev);
  558                 pmask = (1 << part);
  559                 if ((sc->sc_dk.dk_openmask & ~pmask) ||
  560                     ((sc->sc_dk.dk_bopenmask & pmask) &&
  561                     (sc->sc_dk.dk_copenmask & pmask))) {
  562                         disk_unlock(&sc->sc_dk);
  563                         return (EBUSY);
  564                 }
  565 
  566                 vndclear(sc);
  567                 DNPRINTF(VDB_INIT, "vndioctl: CLRed\n");
  568 
  569                 /* Free crypto key */
  570                 if (sc->sc_keyctx) {
  571                         explicit_bzero(sc->sc_keyctx, sizeof(*sc->sc_keyctx));
  572                         free(sc->sc_keyctx, M_DEVBUF, sizeof(*sc->sc_keyctx));
  573                 }
  574 
  575                 /* Detach the disk. */
  576                 disk_detach(&sc->sc_dk);
  577                 disk_unlock(&sc->sc_dk);
  578                 break;
  579 
  580         case VNDIOCGET:
  581                 vnu = (struct vnd_user *)addr;
  582 
  583                 if (vnu->vnu_unit == -1)
  584                         vnu->vnu_unit = unit;
  585                 if (vnu->vnu_unit >= numvnd)
  586                         return (ENXIO);
  587                 if (vnu->vnu_unit < 0)
  588                         return (EINVAL);
  589 
  590                 sc = &vnd_softc[vnu->vnu_unit];
  591 
  592                 if (sc->sc_flags & VNF_INITED) {
  593                         error = VOP_GETATTR(sc->sc_vp, &vattr, p->p_ucred, p);
  594                         if (error)
  595                                 return (error);
  596 
  597                         strlcpy(vnu->vnu_file, sc->sc_file,
  598                             sizeof(vnu->vnu_file));
  599                         vnu->vnu_dev = vattr.va_fsid;
  600                         vnu->vnu_ino = vattr.va_fileid;
  601                 } else {
  602                         vnu->vnu_dev = 0;
  603                         vnu->vnu_ino = 0;
  604                 }
  605 
  606                 break;
  607 
  608         case DIOCRLDINFO:
  609                 if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  610                         return (ENOTTY);
  611                 lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
  612                 vndgetdisklabel(dev, sc, lp, 0);
  613                 *(sc->sc_dk.dk_label) = *lp;
  614                 free(lp, M_TEMP, sizeof(*lp));
  615                 return (0);
  616 
  617         case DIOCGPDINFO:
  618                 if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  619                         return (ENOTTY);
  620                 vndgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
  621                 return (0);
  622 
  623         case DIOCGDINFO:
  624                 if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  625                         return (ENOTTY);
  626                 *(struct disklabel *)addr = *(sc->sc_dk.dk_label);
  627                 return (0);
  628 
  629         case DIOCGPART:
  630                 if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  631                         return (ENOTTY);
  632                 ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
  633                 ((struct partinfo *)addr)->part =
  634                     &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
  635                 return (0);
  636 
  637         case DIOCWDINFO:
  638         case DIOCSDINFO:
  639                 if ((sc->sc_flags & VNF_HAVELABEL) == 0)
  640                         return (ENOTTY);
  641                 if ((flag & FWRITE) == 0)
  642                         return (EBADF);
  643 
  644                 if ((error = disk_lock(&sc->sc_dk)) != 0)
  645                         return (error);
  646 
  647                 error = setdisklabel(sc->sc_dk.dk_label,
  648                     (struct disklabel *)addr, /* sc->sc_dk.dk_openmask */ 0);
  649                 if (error == 0) {
  650                         if (cmd == DIOCWDINFO)
  651                                 error = writedisklabel(DISKLABELDEV(dev),
  652                                     vndstrategy, sc->sc_dk.dk_label);
  653                 }
  654 
  655                 disk_unlock(&sc->sc_dk);
  656                 return (error);
  657 
  658         default:
  659                 return (ENOTTY);
  660         }
  661 
  662         return (0);
  663 }
  664 
  665 /*
  666  * Duplicate the current processes' credentials.  Since we are called only
  667  * as the result of a SET ioctl and only root can do that, any future access
  668  * to this "disk" is essentially as root.  Note that credentials may change
  669  * if some other uid can write directly to the mapped file (NFS).
  670  */
  671 int
  672 vndsetcred(struct proc *p, struct vnode *vp, struct vnd_ioctl *vio,
  673     struct ucred **newcredp)
  674 {
  675         void *buf;
  676         size_t size;
  677         struct ucred *new;
  678         int error;
  679 
  680         new = crdup(p->p_ucred);
  681         buf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
  682         size = DEV_BSIZE;
  683 
  684         /* XXX: Horrible kludge to establish credentials for NFS */
  685         error = vn_rdwr(UIO_READ, vp, buf, size, 0, UIO_SYSSPACE, 0,
  686             new, NULL, curproc);
  687 
  688         free(buf, M_TEMP, DEV_BSIZE);
  689         if (error == 0)
  690                 *newcredp = new;
  691         else
  692                 crfree(new);
  693         return (error);
  694 }
  695 
  696 void
  697 vndclear(struct vnd_softc *sc)
  698 {
  699         struct vnode *vp = sc->sc_vp;
  700         struct proc *p = curproc;               /* XXX */
  701 
  702         DNPRINTF(VDB_FOLLOW, "vndclear(%p): vp %p\n", sc, vp);
  703 
  704         if (vp == NULL)
  705                 panic("vndioctl: null vp");
  706         (void) vn_close(vp, VNDRW(sc), sc->sc_cred, p);
  707         crfree(sc->sc_cred);
  708         sc->sc_flags = 0;
  709         sc->sc_vp = NULL;
  710         sc->sc_cred = NULL;
  711         sc->sc_size = 0;
  712         memset(sc->sc_file, 0, sizeof(sc->sc_file));
  713 }
  714 
  715 daddr_t
  716 vndsize(dev_t dev)
  717 {
  718         /* We don't support swapping to vnd anymore. */
  719         return (-1);
  720 }
  721 
  722 int
  723 vnddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  724 {
  725         /* Not implemented. */
  726         return (ENXIO);
  727 }

Cache object: 0fa2527cb2b5566974a880e66467a131


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.