Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/ufs/lfs Fix a buffer overflow bug in the LFS_UBC case th...



details:   https://anonhg.NetBSD.org/src/rev/12325cae9bb4
branches:  trunk
changeset: 543311:12325cae9bb4
user:      perseant <perseant%NetBSD.org@localhost>
date:      Sun Feb 23 00:22:33 2003 +0000

description:
Fix a buffer overflow bug in the LFS_UBC case that manifested itself
either as a mysterious UVM error or as "panic: dirty bufs".  Verify
maximum size in lfs_malloc.

Teach lfs_updatemeta and lfs_shellsort about oversized cluster blocks from
lfs_gop_write.

When unwiring pages in lfs_gop_write, deactivate them, under the theory
that the pagedaemon wanted to free them last we knew.

diffstat:

 sys/ufs/lfs/TODO          |  12 ++++----
 sys/ufs/lfs/lfs.h         |   7 ++--
 sys/ufs/lfs/lfs_extern.h  |   6 ++--
 sys/ufs/lfs/lfs_segment.c |  70 ++++++++++++++++++++++++++++++----------------
 sys/ufs/lfs/lfs_subr.c    |  42 +++++++++++++++++----------
 sys/ufs/lfs/lfs_vfsops.c  |  37 +++++++++++-------------
 sys/ufs/lfs/lfs_vnops.c   |  51 +++++++++++++++------------------
 7 files changed, 125 insertions(+), 100 deletions(-)

diffs (truncated from 573 to 300 lines):

diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/TODO
--- a/sys/ufs/lfs/TODO  Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/TODO  Sun Feb 23 00:22:33 2003 +0000
@@ -1,4 +1,4 @@
-#   $NetBSD: TODO,v 1.6 2003/02/17 23:48:16 perseant Exp $
+#   $NetBSD: TODO,v 1.7 2003/02/23 00:22:33 perseant Exp $
 
 - Lock audit.  Need to check locking for multiprocessor case in particular.
 
@@ -38,13 +38,13 @@
   and possibly perform additional tasks:
 
   - Backups.  At a minimum, turn the cleaner off and on to allow
-       effective live backups.  More aggressively, the cleaner itself could
-       be the backup agent, and dump_lfs would merely be a controller.
+    effective live backups.  More aggressively, the cleaner itself could
+    be the backup agent, and dump_lfs would merely be a controller.
 
   - Cleaning time policies.  Be able to tweak the cleaner's thresholds
-       to allow more thorough cleaning during policy-determined idle
-       periods (regardless of actual idleness) or put off until later
-       during short, intensive write periods.
+    to allow more thorough cleaning during policy-determined idle
+    periods (regardless of actual idleness) or put off until later
+    during short, intensive write periods.
 
   - File coalescing and placement.  During periods we expect to be idle,
     coalesce fragmented files into one place on disk for better read
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs.h Sun Feb 23 00:22:33 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs.h,v 1.49 2003/02/20 04:27:23 perseant Exp $        */
+/*     $NetBSD: lfs.h,v 1.50 2003/02/23 00:22:33 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -130,6 +130,7 @@
 typedef struct lfs_res_blk {
        void *p;
        LIST_ENTRY(lfs_res_blk) res;
+       int size;
        char inuse;
 } res_t;
 
@@ -834,8 +835,8 @@
        struct vnode     *vp;           /* vnode being gathered */
        void     *segsum;               /* segment summary info */
        u_int32_t ninodes;              /* number of inodes in this segment */
-       u_int32_t seg_bytes_left;       /* bytes left in segment */
-       u_int32_t sum_bytes_left;       /* bytes left in summary block */
+       int32_t seg_bytes_left;         /* bytes left in segment */
+       int32_t sum_bytes_left;         /* bytes left in summary block */
        u_int32_t seg_number;           /* number of this segment */
        /* XXX ondisk32 */
        int32_t *start_lbp;             /* beginning lbn for this set */
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs_extern.h
--- a/sys/ufs/lfs/lfs_extern.h  Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs_extern.h  Sun Feb 23 00:22:33 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_extern.h,v 1.41 2003/02/20 04:27:24 perseant Exp $ */
+/*     $NetBSD: lfs_extern.h,v 1.42 2003/02/23 00:22:34 perseant Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -162,7 +162,7 @@
 int lfs_writeinode(struct lfs *, struct segment *, struct inode *);
 int lfs_gatherblock(struct segment *, struct buf *, int *);
 int lfs_gather(struct lfs *, struct segment *, struct vnode *, int (*match )(struct lfs *, struct buf *));
-void lfs_update_single(struct lfs *, struct segment *, daddr_t, int32_t, int, int);
+void lfs_update_single(struct lfs *, struct segment *, daddr_t, int32_t, int);
 void lfs_updatemeta(struct segment *);
 int lfs_initseg(struct lfs *);
 void lfs_newseg(struct lfs *);
@@ -175,7 +175,7 @@
 void lfs_callback(struct buf *);
 void lfs_supercallback(struct buf *);
 /* XXX ondisk32 */
-void lfs_shellsort(struct buf **, int32_t *, int);
+void lfs_shellsort(struct buf **, int32_t *, int, int);
 int lfs_vref(struct vnode *);
 void lfs_vunref(struct vnode *);
 void lfs_vunref_head(struct vnode *);
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs_segment.c
--- a/sys/ufs/lfs/lfs_segment.c Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs_segment.c Sun Feb 23 00:22:33 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_segment.c,v 1.103 2003/02/20 04:27:24 perseant Exp $       */
+/*     $NetBSD: lfs_segment.c,v 1.104 2003/02/23 00:22:34 perseant Exp $       */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -71,7 +71,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.103 2003/02/20 04:27:24 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.104 2003/02/23 00:22:34 perseant Exp $");
 
 #define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str))
 
@@ -137,7 +137,7 @@
 int     lfs_match_tindir(struct lfs *, struct buf *);
 void    lfs_newseg(struct lfs *);
 /* XXX ondisk32 */
-void    lfs_shellsort(struct buf **, int32_t *, int);
+void    lfs_shellsort(struct buf **, int32_t *, int, int);
 void    lfs_supercallback(struct buf *);
 void    lfs_updatemeta(struct segment *);
 int     lfs_vref(struct vnode *);
@@ -1114,10 +1114,9 @@
 
        *sp->cbpp++ = bp;
        for (j = 0; j < blksinblk; j++)
-               sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno +
-                       (j << fs->lfs_fbshift);
+               sp->fip->fi_blocks[sp->fip->fi_nblocks++] = bp->b_lblkno + j;
        
-       sp->sum_bytes_left -= sizeof(int32_t);
+       sp->sum_bytes_left -= sizeof(int32_t) * blksinblk;
        sp->seg_bytes_left -= bp->b_bcount;
        return (0);
 }
@@ -1218,7 +1217,7 @@
  */
 void
 lfs_update_single(struct lfs *fs, struct segment *sp, daddr_t lbn,
-                 int32_t ndaddr, int size, int num)
+                 int32_t ndaddr, int size)
 {
        SEGUSE *sup;
        struct buf *bp;
@@ -1226,7 +1225,7 @@
        struct inode *ip;
        struct vnode *vp;
        daddr_t daddr, ooff;
-       int error;
+       int num, error;
        int bb, osize, obb;
        
        vp = sp->vp;
@@ -1347,6 +1346,21 @@
        KASSERT(nblocks >= 0);
        if (vp == NULL || nblocks == 0)
                return;
+
+       /*
+        * This count may be high due to oversize blocks from lfs_gop_write.
+        * Correct for this. (XXX we should be able to keep track of these.)
+        */
+       fs = sp->fs;
+       for (i = 0; i < nblocks; i++) {
+               if (sp->start_bpp[i] == NULL) {
+                       printf("nblocks = %d, not %d\n", i, nblocks);
+                       nblocks = i;
+                       break;
+               }
+               num = howmany(sp->start_bpp[i]->b_bcount, fs->lfs_bsize);
+               nblocks -= num - 1;
+       }
        
        /*
         * Sort the blocks.
@@ -1356,7 +1370,7 @@
         * same inode...and if we don't sort, and there are fragments
         * present, blocks may be written in the wrong place.
         */
-       lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks);
+       lfs_shellsort(sp->start_bpp, sp->start_lbp, nblocks, fs->lfs_bsize);
        
        /*
         * Record the length of the last block in case it's a fragment.
@@ -1369,7 +1383,6 @@
         * XXX true until lfs_markv is fixed to do everything with
         * XXX fake blocks (including fake inodes and fake indirect blocks).
         */
-       fs = sp->fs;
        sp->fip->fi_lastlength = ((sp->start_bpp[nblocks - 1]->b_bcount - 1) &
                fs->lfs_bmask) + 1;
        
@@ -1379,7 +1392,8 @@
         */
        for (i = nblocks; i--; ++sp->start_bpp) {
                sbp = *sp->start_bpp;
-               lbn = *sp->start_lbp++;
+               lbn = *sp->start_lbp;
+
                sbp->b_blkno = fsbtodb(fs, fs->lfs_offset);
 
                /*
@@ -1401,10 +1415,9 @@
                     bytesleft -= fs->lfs_bsize) {
                        size = MIN(bytesleft, fs->lfs_bsize);
                        bb = fragstofsb(fs, numfrags(fs, size));
-                       lfs_update_single(fs, sp, lbn, fs->lfs_offset,
-                                         size, num);
+                       lbn = *sp->start_lbp++;
+                       lfs_update_single(fs, sp, lbn, fs->lfs_offset, size);
                        fs->lfs_offset += bb;
-                       ++lbn;
                }
 
        }
@@ -1499,7 +1512,7 @@
        
        sp->seg_bytes_left -= fs->lfs_sumsize;
        sp->sum_bytes_left = fs->lfs_sumsize - SEGSUM_SIZE(fs);
-       
+
 #ifndef LFS_MALLOC_SUMMARY
        LFS_LOCK_BUF(sbp);
        brelse(sbp);
@@ -1599,8 +1612,6 @@
 #define        binshash(bp, dp)        LIST_INSERT_HEAD(dp, bp, b_hash)
 #define        bremhash(bp)            LIST_REMOVE(bp, b_hash)
 
-extern int maxbpp;
-
 static struct buf *
 lfs_newclusterbuf(struct lfs *fs, struct vnode *vp, daddr_t addr, int n)
 {
@@ -1993,6 +2004,13 @@
                        cbp->b_data = lfs_malloc(fs, CHUNKSIZE, LFS_NB_CLUSTER);
                }
 #if defined(DEBUG) && defined(DIAGNOSTIC)
+               if (bpp - sp->bpp > (fs->lfs_sumsize - SEGSUM_SIZE(fs))
+                   / sizeof(int32_t)) {
+                       panic("lfs_writeseg: real bpp overwrite");
+               }
+               if (bpp - sp->bpp > fs->lfs_ssize / fs->lfs_fsize) {
+                       panic("lfs_writeseg: theoretical bpp overwrite");
+               }
                if(dtosn(fs, dbtofsb(fs, (*bpp)->b_blkno + btodb((*bpp)->b_bcount - 1))) !=
                   dtosn(fs, dbtofsb(fs, cbp->b_blkno))) {
                        printf("block at %" PRId64 " (%" PRIu32 "), "
@@ -2459,27 +2477,31 @@
  */
 
 void
-lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb)
+lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb, int size)
 {
        static int __rsshell_increments[] = { 4, 1, 0 };
        int incr, *incrp, t1, t2;
        struct buf *bp_temp;
-       u_int32_t lbt, *lba;
 
-       lba = (u_int32_t *)lb_array;
        for (incrp = __rsshell_increments; (incr = *incrp++) != 0;)
                for (t1 = incr; t1 < nmemb; ++t1)
                        for (t2 = t1 - incr; t2 >= 0;)
-                               if (lba[t2] > lba[t2 + incr]) {
-                                       lbt = lba[t2];
-                                       lba[t2] = lba[t2 + incr];
-                                       lba[t2 + incr] = lbt;
+                               if ((u_int32_t)bp_array[t2]->b_lblkno >
+                                   (u_int32_t)bp_array[t2 + incr]->b_lblkno) {
                                        bp_temp = bp_array[t2];
                                        bp_array[t2] = bp_array[t2 + incr];
                                        bp_array[t2 + incr] = bp_temp;
                                        t2 -= incr;
                                } else
                                        break;
+
+       /* Reform the list of logical blocks */
+       incr = 0;
+       for (t1 = 0; t1 < nmemb; t1++) {
+               for (t2 = 0; t2 * size < bp_array[t1]->b_bcount; t2++) {
+                       lb_array[incr++] = bp_array[t1]->b_lblkno + t2;
+               }
+       }
 }
 
 /*
diff -r 3efbd539618d -r 12325cae9bb4 sys/ufs/lfs/lfs_subr.c
--- a/sys/ufs/lfs/lfs_subr.c    Sat Feb 22 23:46:46 2003 +0000
+++ b/sys/ufs/lfs/lfs_subr.c    Sun Feb 23 00:22:33 2003 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_subr.c,v 1.33 2003/02/20 04:27:24 perseant Exp $   */
+/*     $NetBSD: lfs_subr.c,v 1.34 2003/02/23 00:22:34 perseant Exp $   */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -71,7 +71,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.33 2003/02/20 04:27:24 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.34 2003/02/23 00:22:34 perseant Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -162,28 +162,32 @@
         * so we can't use the pool subsystem for them.
         */
        for (i = 0, j = 0; j < LFS_N_SUMMARIES; j++, i++)
-               fs->lfs_resblk[i].p = malloc(fs->lfs_sumsize, M_SEGMENT,
-                                           M_WAITOK);
+               fs->lfs_resblk[i].size = fs->lfs_sumsize;
        for (j = 0; j < LFS_N_SBLOCKS; j++, i++)



Home | Main Index | Thread Index | Old Index