diff options
author | Felix Kronlage <fkr@cvs.openbsd.org> | 2007-09-29 07:08:03 +0000 |
---|---|---|
committer | Felix Kronlage <fkr@cvs.openbsd.org> | 2007-09-29 07:08:03 +0000 |
commit | dabaa12e47d07a394e2007159360348b324b957b (patch) | |
tree | 12f589a446bd58ff10c3f0e23260a836be58d95b /sys/dev/vnd.c | |
parent | 4cd98ce9820d1d28700d87970c57f22e9c8b6009 (diff) |
make safe vnds work on block devices.
from Piotr Durlej, tested by henning@, krw@, thib@ and myself
ok thib@, grunk@, krw@
Diffstat (limited to 'sys/dev/vnd.c')
-rw-r--r-- | sys/dev/vnd.c | 59 |
1 files changed, 53 insertions, 6 deletions
diff --git a/sys/dev/vnd.c b/sys/dev/vnd.c index 7e7549df0b0..f79f85b719b 100644 --- a/sys/dev/vnd.c +++ b/sys/dev/vnd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vnd.c,v 1.82 2007/09/12 18:45:14 mk Exp $ */ +/* $OpenBSD: vnd.c,v 1.83 2007/09/29 07:08:02 fkr Exp $ */ /* $NetBSD: vnd.c,v 1.26 1996/03/30 23:06:11 christos Exp $ */ /* @@ -162,6 +162,7 @@ void vndiodone(struct buf *); void vndshutdown(void); void vndgetdisklabel(dev_t, struct vnd_softc *); void vndencrypt(struct vnd_softc *, caddr_t, size_t, daddr64_t, int); +size_t vndbdevsize(struct vnode *, struct proc *); #define vndlock(sc) rw_enter(&sc->sc_rwlock, RW_WRITE|RW_INTR) #define vndunlock(sc) rw_exit_write(&sc->sc_rwlock) @@ -230,6 +231,12 @@ vndopen(dev_t dev, int flags, int mode, struct proc *p) if ((error = vndlock(sc)) != 0) return (error); + if (!vndsimple(dev) && sc->sc_vp != NULL && + (sc->sc_vp->v_type != VREG || sc->sc_keyctx != NULL)) { + error = EINVAL; + goto bad; + } + if ((flags & FWRITE) && (sc->sc_flags & VNF_READONLY)) { error = EROFS; goto bad; @@ -492,6 +499,15 @@ vndstrategy(struct buf *bp) } } + if (vnd->sc_vp->v_type != VREG || vnd->sc_keyctx != NULL) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + s = splbio(); + biodone(bp); + splx(s); + return; + } + /* The old-style buffercache bypassing method. */ bn += DL_GETPOFFSET(&vnd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]); bn = dbtob(bn); @@ -691,6 +707,26 @@ vndwrite(dev_t dev, struct uio *uio, int flags) return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio)); } +size_t +vndbdevsize(struct vnode *vp, struct proc *p) +{ + struct partinfo pi; + struct bdevsw *bsw; + long sscale; + dev_t dev; + + dev = vp->v_rdev; + bsw = bdevsw_lookup(dev); + if (bsw->d_ioctl == NULL) + return (0); + if (bsw->d_ioctl(dev, DIOCGPART, (caddr_t)&pi, FREAD, p)) + return (0); + sscale = pi.disklab->d_secsize / DEV_BSIZE; + DNPRINTF(VDB_INIT, "vndbdevsize: size %li secsize %li sscale %li\n", + (long)pi.part->p_size,(long)pi.disklab->d_secsize,sscale); + return (pi.part->p_size * sscale); +} + /* ARGSUSED */ int vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) @@ -756,16 +792,27 @@ vndioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) return (error); } - error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); - if (error) { + if (nd.ni_vp->v_type != VREG && !vndsimple(dev)) { VOP_UNLOCK(nd.ni_vp, 0, p); - (void) vn_close(nd.ni_vp, VNDRW(vnd), p->p_ucred, p); + vn_close(nd.ni_vp, VNDRW(vnd), p->p_ucred, p); vndunlock(vnd); - return (error); + return (EINVAL); + } + + if (nd.ni_vp->v_type == VBLK) + vnd->sc_size = vndbdevsize(nd.ni_vp, p); + else { + error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p); + if (error) { + VOP_UNLOCK(nd.ni_vp, 0, p); + vn_close(nd.ni_vp, VNDRW(vnd), p->p_ucred, p); + vndunlock(vnd); + return (error); + } + vnd->sc_size = btodb(vattr.va_size); /* note truncation */ } VOP_UNLOCK(nd.ni_vp, 0, p); vnd->sc_vp = nd.ni_vp; - vnd->sc_size = btodb(vattr.va_size); /* note truncation */ if ((error = vndsetcred(vnd, p->p_ucred)) != 0) { (void) vn_close(nd.ni_vp, VNDRW(vnd), p->p_ucred, p); vndunlock(vnd); |