Currently physio() sets "bp->b_blkno = btodb(uio->uio_offset)", which
can silently truncate the offset if the read or write starts
misaligned (e.g., due to lseek(2) or using pread(2)/pwrite(2)).  This
means that pread(fd, buf, 512, 0) and pread(fd, buf, 512, 42) return
the same sector.

Diff below changes physio() so that misaligned reads and writes fail
with EINVAL instead.  (I'm not sure this is the best errno to return,
but it's consistent with what the xxstrategy() already returns if the
block number isn't sector aligned.)

ok?

Index: kern/kern_physio.c
===================================================================
RCS file: /home/mdempsky/anoncvs/cvs/src/sys/kern/kern_physio.c,v
retrieving revision 1.33
diff -u -p -r1.33 kern_physio.c
--- kern/kern_physio.c  8 May 2011 09:07:06 -0000       1.33
+++ kern/kern_physio.c  5 Jul 2011 08:03:38 -0000
@@ -69,6 +69,9 @@ physio(void (*strategy)(struct buf *), d
        int error, done, i, s, todo;
        struct buf *bp;
 
+       if ((uio->uio_offset % DEV_BSIZE) != 0)
+               return (EINVAL);
+
        error = 0;
        flags &= B_READ | B_WRITE;
 
@@ -199,6 +202,8 @@ after_unlock:
                                panic("done < 0; strategy broken");
                        if (done > todo)
                                panic("done > todo; strategy broken");
+                       if ((done % DEV_BSIZE) != 0)
+                               panic("(done % DEV_BSIZE) != 0; strategy 
broken");
 #endif
                        iovp->iov_len -= done;
                        iovp->iov_base = (caddr_t)iovp->iov_base + done;

Reply via email to