diff options
author | Matthew Dempsky <matthew@cvs.openbsd.org> | 2011-07-05 04:05:05 +0000 |
---|---|---|
committer | Matthew Dempsky <matthew@cvs.openbsd.org> | 2011-07-05 04:05:05 +0000 |
commit | 6b1ab9bb0f8fa2b5240fe3d6e595ffe1a8fdd1f8 (patch) | |
tree | a07f18509a64432e30a5dacac69d23e3b41968fb | |
parent | 29978210e6a94f6b696fce5f1a7003eff3793a7b (diff) |
Add checks for sector-alignment and whole number of sectors to
bounds_check_with_label() and generally cleanup the code while here.
ok krw@ ("I like this a *lot*"); "i like it" tedu@
-rw-r--r-- | sys/kern/subr_disk.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c index dd6f19b826d..ff3765eeacf 100644 --- a/sys/kern/subr_disk.c +++ b/sys/kern/subr_disk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_disk.c,v 1.127 2011/06/30 16:28:05 matthew Exp $ */ +/* $OpenBSD: subr_disk.c,v 1.128 2011/07/05 04:05:04 matthew Exp $ */ /* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */ /* @@ -687,25 +687,30 @@ int bounds_check_with_label(struct buf *bp, struct disklabel *lp) { struct partition *p = &lp->d_partitions[DISKPART(bp->b_dev)]; - daddr64_t sz = howmany(bp->b_bcount, DEV_BSIZE); + daddr64_t partblocks, sz; - /* Avoid division by zero, negative offsets and negative sizes. */ - if (lp->d_secpercyl == 0 || bp->b_blkno < 0 || sz < 0) + /* Avoid division by zero, negative offsets, and negative sizes. */ + if (lp->d_secpercyl == 0 || bp->b_blkno < 0 || bp->b_bcount < 0) goto bad; - /* beyond partition? */ - if (bp->b_blkno + sz > DL_SECTOBLK(lp, DL_GETPSIZE(p))) { - sz = DL_SECTOBLK(lp, DL_GETPSIZE(p)) - bp->b_blkno; - if (sz == 0) { - /* If exactly at end of disk, return EOF. */ - bp->b_resid = bp->b_bcount; - return (-1); - } - if (sz < 0) - /* If past end of disk, return EINVAL. */ - goto bad; + /* Ensure transfer is a whole number of aligned sectors. */ + if ((bp->b_blkno % DL_BLKSPERSEC(lp)) != 0 || + (bp->b_bcount % lp->d_secsize) != 0) + goto bad; + + /* Ensure transfer starts within partition boundary. */ + partblocks = DL_SECTOBLK(lp, DL_GETPSIZE(p)); + if (bp->b_blkno > partblocks) + goto bad; + + /* If exactly at end of partition or null transfer, return EOF. */ + if (bp->b_blkno == partblocks || bp->b_bcount == 0) + goto done; - /* Otherwise, truncate request. */ + /* Truncate request if it exceeds past the end of the partition. */ + sz = bp->b_bcount >> DEV_BSHIFT; + if (sz > partblocks - bp->b_blkno) { + sz = partblocks - bp->b_blkno; bp->b_bcount = sz << DEV_BSHIFT; } @@ -714,9 +719,11 @@ bounds_check_with_label(struct buf *bp, struct disklabel *lp) DL_SECTOBLK(lp, lp->d_secpercyl); return (1); -bad: + bad: bp->b_error = EINVAL; bp->b_flags |= B_ERROR; + done: + bp->b_resid = bp->b_bcount; return (-1); } |