diff --git a/BUILD.gn b/BUILD.gn index aba0de39e3aee571ac91fb765cc82142cba2fd3e..18d9f048764d46e2e274ce4a3fdc8de4c250e2f8 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -63,6 +63,8 @@ ohos_shared_library("sqlite") { "SQLITE_CODEC_ATTACH_CHANGED", "SQLITE_ENABLE_DROPTABLE_CALLBACK", "OPENSSL_SUPPRESS_DEPRECATED", + "LOG_DUMP", + "FDSAN_ENABLE", ] cflags_c = [ "-fvisibility=hidden", @@ -123,6 +125,8 @@ ohos_executable("sqlite3") { "SQLITE_DIRECT_OVERFLOW_READ", "SQLITE_SHARED_BLOCK_OPTIMIZATION", "OPENSSL_SUPPRESS_DEPRECATED", + "LOG_DUMP", + "FDSAN_ENABLE", ] cflags = [ diff --git a/src/sqlite3.c b/src/sqlite3.c index 9988125638de38fb65a6969c6295dfe4761d82a2..a610bf7e85d621c9f6b1172d96ddd474780f5b3d 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -21179,6 +21179,10 @@ SQLITE_API extern int sqlite3_open_file_count; #define OpenCounter(X) #endif /* defined(SQLITE_TEST) */ +#ifdef FDSAN_ENABLE +#define SQLITE_FDSAN_TAG 5351 +#endif + #endif /* !defined(_OS_COMMON_H_) */ /************** End of os_common.h *******************************************/ @@ -37451,11 +37455,20 @@ static int robust_open(const char *z, int f, mode_t m){ if( errno==EINTR ) continue; break; } +#ifdef FDSAN_ENABLE + if( fdsan_get_owner_tag(fd)==0 ){ + fdsan_exchange_owner_tag(fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); + } +#endif if( fd>=SQLITE_MINIMUM_FILE_DESCRIPTOR ) break; if( (f & (O_EXCL|O_CREAT))==(O_EXCL|O_CREAT) ){ (void)osUnlink(z); } +#ifdef FDSAN_ENABLE + fdsan_close_with_tag(fd, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); +#else osClose(fd); +#endif sqlite3_log(SQLITE_WARNING, "attempt to open \"%s\" as file descriptor %d", z, fd); fd = -1; @@ -38054,7 +38067,13 @@ static int unixLogErrorAtLine( ** and move on. */ static void robust_close(unixFile *pFile, int h, int lineno){ - if( osClose(h) ){ + int rc; +#ifdef FDSAN_ENABLE + rc = fdsan_close_with_tag(h, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); +#else + rc = osClose(h); +#endif + if( rc ){ unixLogErrorAtLine(SQLITE_IOERR_CLOSE, "close", pFile ? pFile->zPath : 0, lineno); } @@ -38148,6 +38167,9 @@ static int findInodeInfo( storeLastErrno(pFile, errno); #if defined(EOVERFLOW) && defined(SQLITE_DISABLE_LFS) if( pFile->lastErrno==EOVERFLOW ) return SQLITE_NOLFS; +#endif +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR, "findInodeInfo-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); #endif return SQLITE_IOERR; } @@ -38167,11 +38189,17 @@ static int findInodeInfo( do{ rc = osWrite(fd, "S", 1); }while( rc<0 && errno==EINTR ); if( rc!=1 ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR, "findInodeInfo-osWrite, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); +#endif return SQLITE_IOERR; } rc = osFstat(fd, &statbuf); if( rc!=0 ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR, "findInodeInfo-msdos-osFstat, fd[%d], errno[%d], osFstat[%d]", fd, errno, rc); +#endif return SQLITE_IOERR; } } @@ -39333,6 +39361,9 @@ static int flockUnlock(sqlite3_file *id, int eFileLock) { #ifdef SQLITE_IGNORE_FLOCK_LOCK_ERRORS return SQLITE_OK; #endif /* SQLITE_IGNORE_FLOCK_LOCK_ERRORS */ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_UNLOCK, "IOERR_UNLOCK fd[%d], eFileLock[%d]", pFile->h, eFileLock); +#endif return SQLITE_IOERR_UNLOCK; }else{ pFile->eFileLock = NO_LOCK; @@ -40159,14 +40190,23 @@ static int unixRead( #endif #ifdef EDEVERR case EDEVERR: +#endif +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_CORRUPTFS, "unixRead-EDEVERR, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); #endif return SQLITE_IOERR_CORRUPTFS; } +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_READ, "unixRead-got<0, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); +#endif return SQLITE_IOERR_READ; }else{ storeLastErrno(pFile, 0); /* not a system error */ /* Unread parts of the buffer must be zero-filled */ memset(&((char*)pBuf)[got], 0, amt-got); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_SHORT_READ, "unixRead-got>=0, fd: [%d], amt[%d], got[%d], offset[%lld]", pFile->h, amt, got, offset); +#endif return SQLITE_IOERR_SHORT_READ; } } @@ -40303,9 +40343,27 @@ static int unixWrite( if( amt>wrote ){ if( wrote<0 && pFile->lastErrno!=ENOSPC ){ /* lastErrno set by seekAndWrite */ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "unixWrite, lastErrno set by seekAndWrite, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", + pFile->h, + offset, + wrote, + amt, + pFile->lastErrno); +#endif return SQLITE_IOERR_WRITE; }else{ storeLastErrno(pFile, 0); /* not a system error */ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "unixWrite, not a system error, fd[%d], offset[%lld], wrote[%d], amt[%d], lastErrno[%d]", + pFile->h, + offset, + wrote, + amt, + pFile->lastErrno); +#endif return SQLITE_FULL; } } @@ -40537,6 +40595,12 @@ static int unixSync(sqlite3_file *id, int flags){ HAVE_FULLFSYNC, isFullsync)); rc = osOpenDirectory(pFile->zPath, &dirfd); if( rc==SQLITE_OK ){ +#ifdef FDSAN_ENABLE + // FDSAN_OWNER_TYPE_FILE is used because files and directories are not distinguished. + if( fdsan_get_owner_tag(dirfd)==0 ){ + fdsan_exchange_owner_tag(dirfd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); + } +#endif full_fsync(dirfd, 0, 0); robust_close(pFile, dirfd, __LINE__); }else{ @@ -40659,7 +40723,17 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ do{ err = osFallocate(pFile->h, buf.st_size, nSize-buf.st_size); }while( err==EINTR ); - if( err && err!=EINVAL ) return SQLITE_IOERR_WRITE; + if( err && err!=EINVAL ){ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "fcntlSizeHint-fallocate, fd[%d], bufSize[%lld], nSize[%lld] err[%d]", + pFile->h, + buf.st_size, + nSize, + err); +#endif + return SQLITE_IOERR_WRITE; + } #else /* If the OS does not have posix_fallocate(), fake it. Write a ** single byte to the last byte in each block that falls entirely @@ -40678,7 +40752,18 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ for(/*no-op*/; iWrite=nSize ) iWrite = nSize - 1; nWrite = seekAndWrite(pFile, iWrite, "", 1); - if( nWrite!=1 ) return SQLITE_IOERR_WRITE; + if( nWrite!=1 ){ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_WRITE, + "fcntlSizeHint-seekAndWrite, fd[%d], nWrite[%d], nSize[%d], nBlk[%d], iWrite[%lld]", + pFile->h, + nWrite, + nSize, + nBlk, + iWrite); +#endif + return SQLITE_IOERR_WRITE; + } } #endif } @@ -40733,14 +40818,29 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ #if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE) case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE); +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_IOERR_BEGIN_ATOMIC, "unixFileControl-begin, fd[%d], op[%d]", pFile->h, op); + } +#endif return rc ? SQLITE_IOERR_BEGIN_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE); +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_IOERR_COMMIT_ATOMIC, "unixFileControl-commit, fd[%d], op[%d]", pFile->h, op); + } +#endif return rc ? SQLITE_IOERR_COMMIT_ATOMIC : SQLITE_OK; } case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: { int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE); +#ifdef LOG_DUMP + if( rc ){ + sqlite3_log(SQLITE_IOERR_ROLLBACK_ATOMIC, "unixFileControl-rollback, fd[%d], op[%d]", pFile->h, op); + } +#endif return rc ? SQLITE_IOERR_ROLLBACK_ATOMIC : SQLITE_OK; } #endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */ @@ -41686,9 +41786,19 @@ static int unixShmLock( int *aLock; p = pDbFd->pShm; - if( p==0 ) return SQLITE_IOERR_SHMLOCK; + if( p==0 ){ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShm, fd[%d], ofst[%d], n[%d], flags[%d]", ofst, n, flags); +#endif + return SQLITE_IOERR_SHMLOCK; + } pShmNode = p->pShmNode; - if( NEVER(pShmNode==0) ) return SQLITE_IOERR_SHMLOCK; + if( NEVER(pShmNode==0) ){ +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_SHMLOCK, "unixShmLock-pShmNode, fd[%d], ofst[%d], n[%d], flags[%d]", ofst, n, flags); +#endif + return SQLITE_IOERR_SHMLOCK; + } aLock = pShmNode->aLock; assert( pShmNode==pDbFd->pInode->pShmNode ); @@ -43060,6 +43170,9 @@ static int unixOpen( if( fstatfs(fd, &fsInfo) == -1 ){ storeLastErrno(p, errno); robust_close(p, fd, __LINE__); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_ACCESS, "unixOpen, fd[%d], flags[%d], errno[%d]", fd, errno, flags); +#endif return SQLITE_IOERR_ACCESS; } if (0 == strncmp("msdos", fsInfo.f_fstypename, 5)) { @@ -43153,6 +43266,12 @@ static int unixDelete( int fd; rc = osOpenDirectory(zPath, &fd); if( rc==SQLITE_OK ){ +#ifdef FDSAN_ENABLE + // FDSAN_OWNER_TYPE_FILE is used because files and directories are not distinguished. + if( fdsan_get_owner_tag(fd)==0 ){ + fdsan_exchange_owner_tag(fd, 0, fdsan_create_owner_tag(FDSAN_OWNER_TYPE_FILE, SQLITE_FDSAN_TAG)); + } +#endif if( full_fsync(fd,0,0) ){ rc = unixLogError(SQLITE_IOERR_DIR_FSYNC, "fsync", zPath); } @@ -43782,6 +43901,9 @@ static int proxyGetLockPath(const char *dbPath, char *lPath, size_t maxLen){ if( !confstr(_CS_DARWIN_USER_TEMP_DIR, lPath, maxLen) ){ OSTRACE(("GETLOCKPATH failed %s errno=%d pid=%d\n", lPath, errno, osGetpid(0))); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyGetLockPath len[%d], dbLen[%d], i[%d]", len, dbLen, i); +#endif return SQLITE_IOERR_LOCK; } len = strlcat(lPath, "sqliteplocks", maxLen); @@ -43900,6 +44022,7 @@ static int proxyCreateUnixFile( case EACCES: return SQLITE_PERM; case EIO: + sqlite3_log(SQLITE_IOERR_LOCK, "proxyCreateUnixFile-EIO, fd[%d]", fd); return SQLITE_IOERR_LOCK; /* even though it is the conch */ default: return SQLITE_CANTOPEN_BKPT; @@ -44068,6 +44191,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ struct stat buf; if( osFstat(conchFile->h, &buf) ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); +#endif return SQLITE_IOERR_LOCK; } @@ -44088,6 +44214,9 @@ static int proxyConchLock(unixFile *pFile, uuid_t myHostID, int lockType){ int len = osPread(conchFile->h, tBuf, PROXY_MAXCONCHLEN, 0); if( len<0 ){ storeLastErrno(pFile, errno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_LOCK, "proxyConchLock tries 2, pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, errno); +#endif return SQLITE_IOERR_LOCK; } if( len>PROXY_PATHINDEX && tBuf[0]==(char)PROXY_CONCHVERSION){ @@ -44162,6 +44291,9 @@ static int proxyTakeConch(unixFile *pFile){ if( readLen<0 ){ /* I/O error: lastErrno set by seekAndRead */ storeLastErrno(pFile, conchFile->lastErrno); +#ifdef LOG_DUMP + sqlite3_log(SQLITE_IOERR_READ, "proxyTakeConch fd:[%d], pFile fd[%d], conchFile fd[%d], lastErrno[%d]", pFile->h, conchFile->h, conchFile->lastErrno); +#endif rc = SQLITE_IOERR_READ; goto end_takeconch; }else if( readLen<=(PROXY_HEADERLEN+PROXY_HOSTIDLEN) || @@ -65214,7 +65346,9 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ for(i=2; iaReadMark[i] = READMARK_NOT_USED; assert( pInfo->aReadMark[0]==0 ); } +static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr); +static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf); /* ** Copy as much content as we can from the WAL back into the database file ** in response to an sqlite3_wal_checkpoint() request or the equivalent. @@ -65355,6 +65489,8 @@ static int walCheckpoint( if( rc!=SQLITE_OK ) break; iOffset = (iDbpage-1)*(i64)szPage; testcase( IS_BIG_INT(iOffset) ); + rc = checkDbHeaderValid(db, iDbpage, zBuf); + if( rc!=SQLITE_OK ) break; rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); if( rc!=SQLITE_OK ) break; } @@ -66749,6 +66885,10 @@ static int walWriteOneFrame( int rc; /* Result code from subfunctions */ void *pData; /* Data actually written */ u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ + if( pPage->pgno==1 ){ + rc = checkHeaderValid(pPage->pPager, pPage->pData, "walWrite"); + if( rc!=SQLITE_OK ) return rc; + } #if defined(SQLITE_HAS_CODEC) if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; #else @@ -67174,6 +67314,15 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1); pWal->ckptLock = 0; } +#ifdef LOG_DUMP + sqlite3_log(SQLITE_NOTICE, + "checkpoint res[%d], szPage[%u], minFrame[%u], readOnly[%u], exclusiveMode[%d]", + rc, + pWal->szPage, + pWal->minFrame, + pWal->readOnly, + pWal->exclusiveMode); +#endif WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok")); #ifdef SQLITE_ENABLE_SETLK_TIMEOUT if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY; @@ -68550,6 +68699,30 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ } #endif +static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr){ +#ifdef SQLITE_HAS_CODEC + if( pager==NULL || pager->pCodec ){ + return SQLITE_OK; + } +#endif + if( zBuf && strncmp((const char *)zBuf, zMagicHeader, 16)!=0 ){ + sqlite3_log(SQLITE_NOTADB, "[%s]wrong header format, memory might be overwritten!", logStr); + return SQLITE_NOTADB; + } + return SQLITE_OK; +} + +static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ + if( iDbpage==1 && db->aDb ){ + Btree *p = db->aDb[0].pBt; + if( p && p->pBt ){ + Pager *pager = sqlite3BtreePager(p); + return checkHeaderValid(pager, zBuf, "ckpt"); + } + } + return SQLITE_OK; +} + /* ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single ** (MemPage*) as an argument. The (MemPage*) must not be NULL. @@ -70380,6 +70553,23 @@ static int decodeFlags(MemPage *pPage, int flagByte){ pPage->intKeyLeaf = 0; pPage->xCellSize = cellSizePtr; pPage->xParseCell = btreeParseCellPtrIndex; +#ifdef LOG_DUMP + sqlite3_log(SQLITE_CORRUPT, + "database corruption at page[%u], flagByte[%x], isInit[%u], intKey[%u], intKeyLeaf[%u], leaf[%u], " + "childPtrSize[%u], cellOffset[%u], nCell[%u], hdrOffset[%u], minLocal, maxLocal[%u]", + pPage->pgno, + flagByte, + pPage->isInit, + pPage->intKey, + pPage->intKeyLeaf, + pPage->leaf, + pPage->childPtrSize, + pPage->cellOffset, + pPage->nCell, + pPage->hdrOffset, + pPage->minLocal, + pPage->maxLocal); +#endif return SQLITE_CORRUPT_PAGE(pPage); } pPage->max1bytePayload = pBt->max1bytePayload;