summaryrefslogtreecommitdiff
path: root/chromium/third_party/sqlite/patches/0015-Fix-fts3-integer-overflows.patch
blob: 21fb72d1ad11eb720b929a855195154c902c2d1e (plain)
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Darwin Huang <huangdarwin@chromium.org>
Date: Mon, 16 Dec 2019 16:01:06 -0800
Subject: [PATCH 15/25] Fix fts3 integer overflows

Backports https://www.sqlite.org/src/info/3b873029ef1903f7

Bug: 1029002, 1030709
---
 third_party/sqlite/patched/ext/fts3/fts3.c    | 43 ++++++++-----------
 third_party/sqlite/patched/ext/fts3/fts3Int.h |  4 ++
 .../sqlite/patched/ext/fts3/fts3_write.c      | 29 +++++++------
 .../sqlite/patched/test/fts3corrupt4.test     | 32 +++++++++++++-
 4 files changed, 68 insertions(+), 40 deletions(-)

diff --git a/third_party/sqlite/patched/ext/fts3/fts3.c b/third_party/sqlite/patched/ext/fts3/fts3.c
index 26aee1788429..5cef6aa2370f 100644
--- a/third_party/sqlite/patched/ext/fts3/fts3.c
+++ b/third_party/sqlite/patched/ext/fts3/fts3.c
@@ -308,18 +308,6 @@
   SQLITE_EXTENSION_INIT1
 #endif
 
-/*
-** The following are copied from sqliteInt.h.
-**
-** Constants for the largest and smallest possible 64-bit signed integers.
-** These macros are designed to work correctly on both 32-bit and 64-bit
-** compilers.
-*/
-#ifndef SQLITE_AMALGAMATION
-# define LARGEST_INT64  (0xffffffff|(((sqlite3_int64)0x7fffffff)<<32))
-# define SMALLEST_INT64 (((sqlite3_int64)-1) - LARGEST_INT64)
-#endif
-
 static int fts3EvalNext(Fts3Cursor *pCsr);
 static int fts3EvalStart(Fts3Cursor *pCsr);
 static int fts3TermSegReaderCursor(
@@ -364,12 +352,7 @@ int sqlite3Fts3PutVarint(char *p, sqlite_int64 v){
   v = (*ptr++);                                               \
   if( (v & mask2)==0 ){ var = v; return ret; }
 
-/*
-** Read a 64-bit variable-length integer from memory starting at p[0].
-** Return the number of bytes read, or 0 on error.
-** The value is stored in *v.
-*/
-int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+int sqlite3Fts3GetVarintU(const char *pBuf, sqlite_uint64 *v){
   const unsigned char *p = (const unsigned char*)pBuf;
   const unsigned char *pStart = p;
   u32 a;
@@ -391,6 +374,15 @@ int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
   return (int)(p - pStart);
 }
 
+/*
+** Read a 64-bit variable-length integer from memory starting at p[0].
+** Return the number of bytes read, or 0 on error.
+** The value is stored in *v.
+*/
+int sqlite3Fts3GetVarint(const char *pBuf, sqlite_int64 *v){
+  return sqlite3Fts3GetVarintU(pBuf, (sqlite3_uint64*)v);
+}
+
 /*
 ** Read a 64-bit variable-length integer from memory starting at p[0] and
 ** not extending past pEnd[-1].
@@ -2484,12 +2476,12 @@ static void fts3GetDeltaVarint3(
   if( *pp>=pEnd ){
     *pp = 0;
   }else{
-    sqlite3_int64 iVal;
-    *pp += sqlite3Fts3GetVarint(*pp, &iVal);
+    u64 iVal;
+    *pp += sqlite3Fts3GetVarintU(*pp, &iVal);
     if( bDescIdx ){
-      *pVal -= iVal;
+      *pVal = (i64)((u64)*pVal - iVal);
     }else{
-      *pVal += iVal;
+      *pVal = (i64)((u64)*pVal + iVal);
     }
   }
 }
@@ -2518,9 +2510,9 @@ static void fts3PutDeltaVarint3(
 ){
   sqlite3_int64 iWrite;
   if( bDescIdx==0 || *pbFirst==0 ){
-    iWrite = iVal - *piPrev;
+    iWrite = (u64)iVal - (u64)*piPrev;
   }else{
-    iWrite = *piPrev - iVal;
+    iWrite = (u64)*piPrev - (u64)iVal;
   }
   assert( *pbFirst || *piPrev==0 );
   assert_fts3_nc( *pbFirst==0 || iWrite>0 );
@@ -2540,7 +2532,8 @@ static void fts3PutDeltaVarint3(
 ** Using this makes it easier to write code that can merge doclists that are
 ** sorted in either ascending or descending order.
 */
-#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1-i2))
+// #define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i64)((u64)i1-i2))
+#define DOCID_CMP(i1, i2) ((bDescDoclist?-1:1) * (i1>i2?1:((i1==i2)?0:-1)))
 
 /*
 ** This function does an "OR" merge of two doclists (output contains all
diff --git a/third_party/sqlite/patched/ext/fts3/fts3Int.h b/third_party/sqlite/patched/ext/fts3/fts3Int.h
index 5cafa1fe9b91..44bf78ef8f17 100644
--- a/third_party/sqlite/patched/ext/fts3/fts3Int.h
+++ b/third_party/sqlite/patched/ext/fts3/fts3Int.h
@@ -196,6 +196,9 @@ typedef sqlite3_int64 i64;        /* 8-byte signed integer */
 # define TESTONLY(X)
 #endif
 
+#define LARGEST_INT64  (0xffffffff|(((i64)0x7fffffff)<<32))
+#define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
+
 #endif /* SQLITE_AMALGAMATION */
 
 #ifdef SQLITE_DEBUG
@@ -577,6 +580,7 @@ int sqlite3Fts3Incrmerge(Fts3Table*,int,int);
 void sqlite3Fts3ErrMsg(char**,const char*,...);
 int sqlite3Fts3PutVarint(char *, sqlite3_int64);
 int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
+int sqlite3Fts3GetVarintU(const char *, sqlite_uint64 *);
 int sqlite3Fts3GetVarintBounded(const char*,const char*,sqlite3_int64*);
 int sqlite3Fts3GetVarint32(const char *, int *);
 int sqlite3Fts3VarintLen(sqlite3_uint64);
diff --git a/third_party/sqlite/patched/ext/fts3/fts3_write.c b/third_party/sqlite/patched/ext/fts3/fts3_write.c
index 47692c52c882..8b6b729987c3 100644
--- a/third_party/sqlite/patched/ext/fts3/fts3_write.c
+++ b/third_party/sqlite/patched/ext/fts3/fts3_write.c
@@ -696,7 +696,7 @@ static int fts3PendingListAppend(
   assert( !p || p->iLastDocid<=iDocid );
 
   if( !p || p->iLastDocid!=iDocid ){
-    sqlite3_int64 iDelta = iDocid - (p ? p->iLastDocid : 0);
+    u64 iDelta = (u64)iDocid - (u64)(p ? p->iLastDocid : 0);
     if( p ){
       assert( p->nData<p->nSpace );
       assert( p->aData[p->nData]==0 );
@@ -1529,18 +1529,18 @@ static int fts3SegReaderNextDocid(
     }else{
       rc = fts3SegReaderRequire(pReader, p, FTS3_VARINT_MAX);
       if( rc==SQLITE_OK ){
-        sqlite3_int64 iDelta;
-        pReader->pOffsetList = p + sqlite3Fts3GetVarint(p, &iDelta);
+        u64 iDelta;
+        pReader->pOffsetList = p + sqlite3Fts3GetVarintU(p, &iDelta);
         if( pTab->bDescIdx ){
-          pReader->iDocid -= iDelta;
+          pReader->iDocid = (i64)((u64)pReader->iDocid - iDelta);
         }else{
-          pReader->iDocid += iDelta;
+          pReader->iDocid = (i64)((u64)pReader->iDocid + iDelta);
         }
       }
     }
   }
 
-  return SQLITE_OK;
+  return rc;
 }
 
 
@@ -2279,6 +2279,7 @@ static int fts3SegWriterAdd(
     int rc;
 
     /* The current leaf node is full. Write it out to the database. */
+    if( pWriter->iFree==LARGEST_INT64 ) return FTS_CORRUPT_VTAB;
     rc = fts3WriteSegment(p, pWriter->iFree++, pWriter->aData, nData);
     if( rc!=SQLITE_OK ) return rc;
     p->nLeafAdd++;
@@ -2975,9 +2976,9 @@ int sqlite3Fts3SegReaderStep(
           ** doclist. */
           sqlite3_int64 iDelta;
           if( p->bDescIdx && nDoclist>0 ){
-            iDelta = iPrev - iDocid;
+            iDelta = (i64)((u64)iPrev - (u64)iDocid);
           }else{
-            iDelta = iDocid - iPrev;
+            iDelta = (i64)((u64)iDocid - (u64)iPrev);
           }
           if( iDelta<=0 && (nDoclist>0 || iDelta!=iDocid) ){
             return FTS_CORRUPT_VTAB;
@@ -3264,7 +3265,7 @@ static int fts3SegmentMerge(
         csr.zTerm, csr.nTerm, csr.aDoclist, csr.nDoclist);
   }
   if( rc!=SQLITE_OK ) goto finished;
-  assert( pWriter || bIgnoreEmpty );
+  assert_fts3_nc( pWriter || bIgnoreEmpty );
 
   if( iLevel!=FTS3_SEGCURSOR_PENDING ){
     rc = fts3DeleteSegdir(
@@ -5175,12 +5176,12 @@ static u64 fts3ChecksumIndex(
 
       i64 iDocid = 0;
       i64 iCol = 0;
-      i64 iPos = 0;
+      u64 iPos = 0;
 
       pCsr += sqlite3Fts3GetVarint(pCsr, &iDocid);
       while( pCsr<pEnd ){
-        i64 iVal = 0;
-        pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
+        u64 iVal = 0;
+        pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
         if( pCsr<pEnd ){
           if( iVal==0 || iVal==1 ){
             iCol = 0;
@@ -5188,8 +5189,8 @@ static u64 fts3ChecksumIndex(
             if( iVal ){
               pCsr += sqlite3Fts3GetVarint(pCsr, &iCol);
             }else{
-              pCsr += sqlite3Fts3GetVarint(pCsr, &iVal);
-              iDocid += iVal;
+              pCsr += sqlite3Fts3GetVarintU(pCsr, &iVal);
+              iDocid = (i64)((u64)iDocid + iVal);
             }
           }else{
             iPos += (iVal - 2);
diff --git a/third_party/sqlite/patched/test/fts3corrupt4.test b/third_party/sqlite/patched/test/fts3corrupt4.test
index b5d9c138a5ea..45dd52fff29e 100644
--- a/third_party/sqlite/patched/test/fts3corrupt4.test
+++ b/third_party/sqlite/patched/test/fts3corrupt4.test
@@ -5549,7 +5549,7 @@ do_catchsql_test 30.2 {
 #-------------------------------------------------------------------------
 #
 reset_db
-do_catchsql_test 32.0 {
+do_catchsql_test 33.0 {
   CREATE VIRTUAL TABLE f USING fts3(a,b,tokenize=icu);
   CREATE TABLE 'f_docsize'(docid INTEGER PRIMARY KEY, size BLOB);
   CREATE TABLE 'f_stat'(id INTEGER PRIMARY KEY, value BLOB);
@@ -5558,5 +5558,35 @@ do_catchsql_test 32.0 {
   INSERT INTO f(f) VALUES ('merge=198,49');
 } {1 {database disk image is malformed}}
 
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 34.0 {
+  CREATE VIRTUAL TABLE f USING fts3(a,b);
+  INSERT INTO f VALUES (1, '1234');
+  INSERT INTO f_segdir VALUES (1,255,0,0,'1 255',x'00');
+  UPDATE f_segdir SET level = 0 WHERE level IN (
+    SELECT level FROM f_segdir LIMIT 1 OFFSET 1
+  );
+  INSERT INTO f_segdir VALUES (255,249,0,121,'0 0',x'00');
+  INSERT INTO f_content VALUES (255,0,x'ff');
+  INSERT INTO f_segdir VALUES (1,255,16,0,'1 255',x'00');
+}
+
+do_catchsql_test 34.1 {
+  UPDATE f SET b = x'00' WHERE b IN (SELECT b FROM f LIMIT 1 OFFSET 0);
+} {1 {database disk image is malformed}}
+
+#-------------------------------------------------------------------------
+#
+reset_db
+do_execsql_test 35.0 {
+  CREATE VIRTUAL TABLE f USING fts3(a,b);
+  INSERT INTO f_segdir VALUES (1,255,0,0,'1 255',x'0001ff000001ff000001ff000001ff000001ff00c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5bec5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5');
+}
+
+do_catchsql_test 35.1 {
+  INSERT INTO f(f) VALUES ('integrity-check');
+} {1 {database disk image is malformed}}
 
 finish_test
-- 
2.25.0.rc1.283.g88dfdc4193-goog