Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add corruptD.test, a container for testing the "cell overflow" problem. Also shuffle a small amount of code in BtreeInitPage() to check that the page header pointer to the start of the cell offset array is set to a sane value. (CVS 6710) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
7fa5d3cb0fa05f7d901bcc139c2c037c |
User & Date: | danielk1977 2009-06-03 17:26:18.000 |
Context
2009-06-03
| ||
21:04 | Change the pcache1.c implementation so that the "header" occurs at the end of page buffer, not at the beginning. This insures that the 20 bytes immediately following the page buffer are mapped if a read of the page buffer overruns due to a malformed cell. (CVS 6711) (check-in: c54de1f540 user: drh tags: trunk) | |
17:26 | Add corruptD.test, a container for testing the "cell overflow" problem. Also shuffle a small amount of code in BtreeInitPage() to check that the page header pointer to the start of the cell offset array is set to a sane value. (CVS 6710) (check-in: 7fa5d3cb0f user: danielk1977 tags: trunk) | |
11:25 | Define a set of constants to use as the "index" argument to sqlite3BtreeGetMeta and UpdateMeta. This makes some parts of the code easier to follow. (CVS 6709) (check-in: 6dbf4eca00 user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.611 2009/06/03 17:26:18 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
1141 1142 1143 1144 1145 1146 1147 | if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_BKPT; } /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); | | | > > > > > > > | < > | 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 | if( pPage->nCell>MX_CELL(pBt) ){ /* To many cells for a single page. The page must be corrupt */ return SQLITE_CORRUPT_BKPT; } /* Compute the total free space on the page */ pc = get2byte(&data[hdr+1]); nFree = data[hdr+7] + top; while( pc>0 ){ u16 next, size; if( pc>usableSize-4 ){ /* Free block is off the page */ return SQLITE_CORRUPT_BKPT; } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); if( next>0 && next<=pc+size+3 ){ /* Free blocks must be in accending order */ return SQLITE_CORRUPT_BKPT; } nFree += size; pc = next; } /* At this point, nFree contains the sum of the offset to the start ** of the cell-content area plus the number of free bytes within ** the cell-content area. If this is greater than the usable-size ** of the page, then the page must be corrupted. This check also ** serves to verify that the offset to the start of the cell-content ** area, according to the page header, lies within the page. */ if( nFree>usableSize ){ return SQLITE_CORRUPT_BKPT; } pPage->nFree = nFree - (cellOffset + 2*pPage->nCell); #if 0 /* Check that all the offsets in the cell offset array are within range. ** ** Omitting this consistency check and using the pPage->maskPage mask ** to prevent overrunning the page buffer in findCell() results in a ** 2.5% performance gain. |
︙ | ︙ |
Added test/corruptD.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | # 2009 June 3 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: corruptD.test,v 1.1 2009/06/03 17:26:20 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl #-------------------------------------------------------------------------- # OVERVIEW # # This test file attempts to verify that SQLite does not read past the # end of any in-memory buffers as a result of corrupted database page # images. Usually this happens because a field within a database page # that contains an offset to some other structure within the same page # is set to too large a value. A database page contains the following # such fields: # # 1. The page header field that contains the offset to the first # free block of space. # # 2. The first two bytes of all but the last free block on the free-block # list (the offset to the next free block). # # 3. The page header field containing the number of cells on the page # (implicitly defines the offset to the final element in the cell offset # array, which could potentially be off the end of the page). # # 4. The page header field containing the offset to the start of the cell # content area. # # 5. The contents of the cell offset array. # # 6. The first few bytes of each cell determine the size of the cell # stored within the page, and hence the offset to the final byte of # the cell. # # If any of the above fields are set to too large a value, then a buffer # overread may occur. This test script creates and operates on various # strategically corrupted database files to attempt to provoke such buffer # overreads. # # Very often, a buffer overread passes unnoticed, particularly in workstation # environments. For this reason, this test script should be run using valgrind # (or similar) in order to verify that no overreads occur. # # TEST PLAN # # Test cases corruptD-1.* are white-box tests. They attempt to corrupt # one of the above fields, then exercise each part of the code in btree.c # that uses said field. # # Offset variables 1, 2, 3 and 4 are all checked to make sure they # will not result in buffer overruns as part of page initialization in # sqlite3BtreeInitPage(). Offsets 5 and 6 cannot be tested as part of # page initialization, as trying to do so causes a performance hit. # do_test corruptD-1.0 { execsql { PRAGMA auto_vacuum = 0; PRAGMA page_size = 1024; CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a, b); } for {set ii 1} {$ii < 50} {incr ii} { execsql { INSERT INTO t1 VALUES($ii, $ii * $ii) } } execsql { DELETE FROM t1 WHERE a = 10; DELETE FROM t1 WHERE a = 20; DELETE FROM t1 WHERE a = 30; DELETE FROM t1 WHERE a = 40; } copy_file test.db test.bu } {} proc incr_change_counter {} { hexio_write test.db 24 [ hexio_render_int32 [expr [hexio_get_int [hexio_read test.db 24 4]] + 1] ] } proc restore_file {} { db close copy_file test.bu test.db sqlite3 db test.db } #------------------------------------------------------------------------- # The following tests, corruptD-1.1.*, focus on the page header field # containing the offset of the first free block in a page. # do_test corruptD-1.1.1 { incr_change_counter hexio_write test.db [expr 1024+1] FFFF catchsql { SELECT * FROM t1 } } {1 {database disk image is malformed}} do_test corruptD-1.1.2 { incr_change_counter hexio_write test.db [expr 1024+1] [hexio_render_int32 1021] catchsql { SELECT * FROM t1 } } {1 {database disk image is malformed}} #------------------------------------------------------------------------- # The following tests, corruptD-1.2.*, focus on the offsets contained # in the first 2 byte of each free-block on the free-list. # do_test corruptD-1.2.1 { restore_file } {} do_test corruptD-1.2.2 { } {} #------------------------------------------------------------------------- # The following tests, corruptD-1.4.*, ... # #------------------------------------------------------------------------- # The following tests, corruptD-1.5.*, focus on the offsets contained # in the cell offset array. # # defragmentPage # finish_test |