From ec2409b34e42389034ecf6ae616a85de97c0fd8c Mon Sep 17 00:00:00 2001 From: Dan Kennedy Date: Tue, 22 Jan 2019 21:17:40 +0000 Subject: [PATCH 0820/1009] Fix a buffer overrun that could occur in fts5 if a prefix query is made on a corrupt database. https://github.com/mackyle/sqlite/commit/ec2409b34e42389034ecf6ae616a85de97c0fd8c --- ext/fts5/fts5.h | 8 +- ext/fts5/fts5Int.h | 2 +- ext/fts5/fts5_index.c | 2 +- ext/fts5/fts5_main.c | 5 + ext/fts5/test/fts5corrupt3.test | 217 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+), 8 deletions(-) diff --git a/ext/fts5/fts5.h b/ext/fts5/fts5.h index 8273785..f0b7d55 100644 --- a/ext/fts5/fts5.h +++ b/ext/fts5/fts5.h @@ -120,12 +120,8 @@ struct Fts5PhraseIter { ** ** Usually, output parameter *piPhrase is set to the phrase number, *piCol ** to the column in which it occurs and *piOff the token offset of the -** first token of the phrase. The exception is if the table was created -** with the offsets=0 option specified. In this case *piOff is always -** set to -1. -** -** Returns SQLITE_OK if successful, or an error code (i.e. SQLITE_NOMEM) -** if an error occurs. +** first token of the phrase. Returns SQLITE_OK if successful, or an error +** code (i.e. SQLITE_NOMEM) if an error occurs. ** ** This API can be quite slow if used with an FTS5 table created with the ** "detail=none" or "detail=column" option. diff --git a/ext/fts5/fts5Int.h b/ext/fts5/fts5Int.h index 4855abe..629bcf0 100644 --- a/ext/fts5/fts5Int.h +++ b/ext/fts5/fts5Int.h @@ -274,7 +274,7 @@ void sqlite3Fts5Put32(u8*, int); int sqlite3Fts5Get32(const u8*); #define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) -#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0xFFFFFFFF) +#define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) typedef struct Fts5PoslistReader Fts5PoslistReader; struct Fts5PoslistReader { diff --git a/ext/fts5/fts5_index.c b/ext/fts5/fts5_index.c index 66ab9be..165d094 100644 --- a/ext/fts5/fts5_index.c +++ b/ext/fts5/fts5_index.c @@ -5122,7 +5122,7 @@ static void fts5SetupPrefixIter( } fts5MultiIterFree(p1); - pData = fts5IdxMalloc(p, sizeof(Fts5Data) + doclist.n); + pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING); if( pData ){ pData->p = (u8*)&pData[1]; pData->nn = pData->szLeaf = doclist.n; diff --git a/ext/fts5/fts5_main.c b/ext/fts5/fts5_main.c index bb34234..c98df4f 100644 --- a/ext/fts5/fts5_main.c +++ b/ext/fts5/fts5_main.c @@ -1777,6 +1777,7 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ int rc = SQLITE_OK; Fts5PoslistReader *aIter; /* One iterator for each phrase */ int nIter; /* Number of iterators/phrases */ + int nCol = ((Fts5Table*)pCsr->base.pVtab)->pConfig->nCol; nIter = sqlite3Fts5ExprPhraseCount(pCsr->pExpr); if( pCsr->aInstIter==0 ){ @@ -1830,6 +1831,10 @@ static int fts5CacheInstArray(Fts5Cursor *pCsr){ aInst[0] = iBest; aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); + if( aInst[1]<0 || aInst[1]>=nCol ){ + rc = FTS5_CORRUPT; + break; + } sqlite3Fts5PoslistReaderNext(&aIter[iBest]); } } -- 1.8.3.1