From cf0d56271d975852eae75def5763ca50ff991d53 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Fri, 21 Jun 2024 13:01:55 +0100 Subject: [PATCH] Integrity. --- README.md | 2 +- driver/driver.go | 18 ++++++++++-------- embed/sqlite3.wasm | Bin 1365178 -> 1365234 bytes ext/bloom/bloom.go | 38 +++++++++++++++++++++++++++++++++++--- ext/bloom/bloom_test.go | 10 ++++++++++ sqlite3/vtab.c | 23 +++++++++++++++-------- vfs/adiantum/README.md | 8 +------- vfs/memdb/README.md | 2 +- vfs/readervfs/README.md | 2 +- vtab.go | 31 +++++++++++++++++++++++-------- 10 files changed, 97 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index f8ba77d..25b2ccb 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ run - [`github.com/ncruces/go-sqlite3/ext/blobio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/blobio) simplifies [incremental BLOB I/O](https://sqlite.org/c3ref/blob_open.html). - [`github.com/ncruces/go-sqlite3/ext/bloom`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/bloom) - provides the [`bloom_filter`](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table. + provides a [Bloom filter](https://github.com/nalgeon/sqlean/issues/27#issuecomment-1002267134) virtual table. - [`github.com/ncruces/go-sqlite3/ext/csv`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/csv) reads [comma-separated values](https://sqlite.org/csv.html). - [`github.com/ncruces/go-sqlite3/ext/fileio`](https://pkg.go.dev/github.com/ncruces/go-sqlite3/ext/fileio) diff --git a/driver/driver.go b/driver/driver.go index 912b740..e7863b1 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -229,6 +229,7 @@ func (c *conn) Raw() *sqlite3.Conn { return c.Conn } +// Deprecated: use BeginTx instead. func (c *conn) Begin() (driver.Tx, error) { return c.BeginTx(context.Background(), driver.TxOptions{}) } @@ -559,19 +560,20 @@ func (r *rows) Next(dest []driver.Value) error { return err } -func (r *rows) decodeTime(i int, v any) (_ time.Time, _ bool) { +func (r *rows) decodeTime(i int, v any) (_ time.Time, ok bool) { if r.tmRead == sqlite3.TimeFormatDefault { - return - } - switch r.declType(i) { - case "DATE", "TIME", "DATETIME", "TIMESTAMP": - // maybe - default: + // handled by maybeTime return } switch v.(type) { case int64, float64, string: - // maybe + // could be a time value + default: + return + } + switch r.declType(i) { + case "DATE", "TIME", "DATETIME", "TIMESTAMP": + // could be a time value default: return } diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 2689f773a6c213fe98c56e4700584c25904c5a9e..8dfc7da0c6c642190e25589c6743612dce703195 100755 GIT binary patch delta 3536 zcmaJ@YgAO%89nDRz>EW8m=lBnA{gEesq#<(4OinU8iUeUBDO%P@evSwR3s)cgd`=g z3Ki>zXbfpc#OP{BwHdWdN`ADJ2mxjQ z54lI9LkoLktNV#tp(kXBrn|IVmVy|IeoN+PW%Ol#XqN1EhYf@VXch}r;*Pu>y6n@s z0U<q zH3AKo&^zET1T8-PH}GS87Bm8%wHEyN0|7uFfbt5PJN=^LL;va1VB3KpKnNPR?1<2W z!yS0V5uPs<#SA-&<-=4v?8uT~^s8Y>e6-_-k};!ci#y`J2`1?=h4Rt5P-bA9^ZQWiR4F zOLVW`nt1GeygiS7;Kx$gNQAF+nV@7I6ymD$nqnG2=O6f+)U~8Inx{(Vo3&trNGOe z>=bz4qYWu4OU|W3DQZ0`cY|~DXq+jNqEbOwl*fdsrm85JO*QQ0&~Z@Re3a}`gUudN zRxL&EBAgCmW7t#=qS^waZ*uyD15#A$KIsuoFGRZW6{L&SOA+InZbwwhMY@aAPa@ri zv>y-76}!smJSiwM4NJ3wK=J)q#lC^na!Q9xs9D#8fqa2W*@ zo35PMtXkqh0eCBJ!v4jcRZEwZH+OZZCYB=ixChIqI$cF(-xorvnDc1-D}{?q5&pO) zmLsqNSP876?sOHAd0z*U$^Kw_cr_p9lzE4F#bJQ8z6Q)kArr*s`;Xdv^*j+Q3 zy~pm8lkThxRB0_O&Opu9QmIKUlioIS-5Kcdl&41_eF?X2oyWzq&~F~L*`1>(<^ZZ; ztP@YgSI~F_f-im~#kSljL6Of0T`Z`2L5h{jHM2+<;rrehF-0#6IWVuO#MlLhN=m&+jVuJQ*S0dJ#+1%Jg?rT|Zd<9xV^eMT5z!Mj*Q z*NUg76wml5+MA*H3l@=tN_dCZ=p(qwg7sKLI}VapP~sKPnz^X-rb)Mw-5*Z6N7zLb zjaEn>uvKPC=gwtQ0(>aU=`cbU z1R*6Tl?wuH=IujN+sx01(*@6?z_|I`O|IeFIl%cX$h(eV{3z_bV3lUP9i_FKM-f&G z7X?8l3wG3+Gn%)%TlgCiA)@H|JQXLOqtSUduv;lS6SR%yGi|30poAS5qy4ze?w5PdwNMe%0bB42CeKZfr%z8f5l+z`JXDP}RjMoPL4#qIeN_i4J0T z+d-IhfQ#C*RJ5%g=F5ir$1L@zzsoRhWvN(?sj?@d`BUcR>`B2Jh$b4{(3Q8@hLz~e zCvEmn{#wZ-mnc|Z?x2CLXR8?dD=1_y^3K!>(sNXp9e*Np*C_<9S98Egxj71dE2%gK z?~g{RWqO_3a`05%pvz2$s5b|%<)6_I=MGcYe1qmQ9id{AYMGj-Z9Y0Q(PgG)>gC|i zY1Aa=0>jHQX%o{?ddZ~IOfB?#lWsB{Be_t;)E&cmyWhcj|BVBXw9a!d8(rA05Ciak z0YM)GA!iohRw7`$8X(YJ9XPn0ZieCHG&la0)@IXzeH?;IEGWVG*^mB4B^$ZQXcpiw zbzmjf`5%~w{$)~NF1(|ZWYQ|8R@#w^oww5K?46+Z**igh%2l!1Z5Z$*a0+-6_?$ma zX#C6TF+NAI@6*w&JQca*G&FAk?ErU8!Y5^<$omqU>iVEA7dqEk4VxfWp31Gei@uC8 zfZMm=acuwES(|<1Jvb8p-`i=Zp&bYU`Vkud27%i^Fk*MWL%?*{-+*!1#3R&(+9Sf<8NXGBBK`+D@w5s6 delta 3764 zcmZuzc~Di?9X{s*@*a=<9Sw^h7*RwKWQ!~fKDW>yN?aP_Zd`~_f(8?{CO(YD;EwAL z8;viGM%2zos>!1|>CovvOsW}Xnp)Ck44uhL&16(CDo=&j?|1KgyzA66^Ue2LzO&rl zIrrRq=giDYXJ$5+h6eRG?p>G=dN(9Yh6IPoHS%2WxeKm{jp6c(gO}rn+xFU|a7oA6 z3qQtRlow7UzM=(x+f;sUYj4sAy-5<#fFK|k2muBFp@0pr17Uyz2nQm7NFWM`24cLu zNwJmf@&j+ht=OZIdTz(&$XniwuGj&ZH~&uTq`$at3nAjRNTGqbbpbEEAMm^3m#hr< zci{iIQ3?s>_A{{0;@>rW|9I?+?S`KFu)lt?;X_lb2ex8D|A6-(IB4Esp!CcXI}9@ z>_KCL%@MI{3N$=8fLJqP+8`LMocwZ?k>p21tb>!!cx8|CdPtB*3cB9wjF05rhD?al zl0y2NBPplP>DK-z>3pAap*Q9ir>1FN$-^;f#^+V)n-uMPNrkB@lU`3%x$ej4EP>Ui z8E*>PZ*w_Jd(%?v1#H&MTP?+>m`{V+6rF#!r;M8?vNVJe)C4pWo- zPaYTTI@xV=F>{Hp|kxlhf%)cX4_ZHo2w3(!0J7 z>5(|ZwIfw>N(OYTh(y)?7Ue89tHrZ)ur7l>gG!E~cBavEn<e^z*VsO0EpEo8+t@kC&#=WtLE2)t%ezjv=fXZ=#fnGF3tZ zhg>E~X-TF^jF`^f*(+ zM?4uy8>3FUe~td!UPQ6lciJ5Z-{DTLMA13U$IB}4v0xy|9*uY2FDSQ+;MoPiwS_pK zlLCUN7C{>XQ8C!p%89yw%CnS1R?y2?sB#5uFzBd3m$FpyvI;D$VGo8qh)ar_f8J^4 zu+t%EVZkRjyB-XymjNrUGzBj~(8+=a*q*MZ38*An#o1^0^|XN9nf~!?9XCq-#$!z3XjqJLZBvdECNph1XrtY){UCzWq-vYXk)<)94n7y zU*=i_T`c$-U!m;D`V?+`hjAox23ZDq3qLoBi=T3GQd6kV1@EVc+bS$@X-nTRdIbpzHAK96`8L^b_0S0&lsfLX(!zFfSd zYhbQ5@g{f!M#wHVZz~?7lQ2dtGV4sdMdf*TN#BOM-oyr4i%=HsY=H|`Yy#c^)`V-K z4r3WFJjUv1#8~elvl(#HpYpJtI+$B@_xn8cY=~PoL-SRtX=dj4M`s7jcLRb?0@1%A zD&M1<`Ka+$iYx$aqb#QPsgh|stp(AV0u?;pcMQAe<0nJYmzZ8B#*Z@|y&ikwIgUMf zh|)Fr>%pJ%7DTljNVjo13{{E7hlrbge|K_vCv_L7!EzTxK8HznQ`@1}dYWt`g zvrKG&ssnz)3f#RZQ_b%w2C;D$G#1o-3_&dfWe}LNNMlhD(5!J-bpyS{w4aU`D`Yz9D^iRbRjl-W< ze_dM;&DJ>I2J4|@0XKaF8!BbCqp*Gld4p-eIFbN_JMhDKcW!xPtbhU?iip?fV<4q3NIrX=@=ju;N}D? zU?4CEcm{|A;&BU|Jol6i2}nM*gZE;ID$oXZoz;ThSW>-QM1= 1 { + return err + } + if n := load.ColumnInt64(3); n <= 0 { + return err + } + if k := load.ColumnInt(5); k <= 0 { + return err + } + return nil +} + func (b *bloom) BestIndex(idx *sqlite3.IndexInfo) error { for n, cst := range idx.Constraint { if cst.Usable && cst.Column == 1 && @@ -274,8 +308,6 @@ func (c *cursor) Column(ctx *sqlite3.Context, n int) error { ctx.ResultBool(true) case 1: ctx.ResultValue(*c.arg) - default: - panic(util.AssertErr()) } return nil } diff --git a/ext/bloom/bloom_test.go b/ext/bloom/bloom_test.go index d07e99b..d9df376 100644 --- a/ext/bloom/bloom_test.go +++ b/ext/bloom/bloom_test.go @@ -127,4 +127,14 @@ func Test_compatible(t *testing.T) { if err != nil { t.Fatal(err) } + + err = db.Exec(`PRAGMA integrity_check`) + if err != nil { + t.Error(err) + } + + err = db.Exec(`PRAGMA quick_check`) + if err != nil { + t.Error(err) + } } diff --git a/sqlite3/vtab.c b/sqlite3/vtab.c index a9af043..4c85cf9 100644 --- a/sqlite3/vtab.c +++ b/sqlite3/vtab.c @@ -1,16 +1,18 @@ +#include #include #include "include.h" #include "sqlite3.h" -#define SQLITE_VTAB_CREATOR_GO /******/ 0x01 -#define SQLITE_VTAB_DESTROYER_GO /****/ 0x02 -#define SQLITE_VTAB_UPDATER_GO /******/ 0x04 -#define SQLITE_VTAB_RENAMER_GO /******/ 0x08 -#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x10 -#define SQLITE_VTAB_CHECKER_GO /******/ 0x20 -#define SQLITE_VTAB_TXN_GO /**********/ 0x40 -#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x80 +#define SQLITE_VTAB_CREATOR_GO /******/ 0x001 +#define SQLITE_VTAB_DESTROYER_GO /****/ 0x002 +#define SQLITE_VTAB_UPDATER_GO /******/ 0x004 +#define SQLITE_VTAB_RENAMER_GO /******/ 0x008 +#define SQLITE_VTAB_OVERLOADER_GO /***/ 0x010 +#define SQLITE_VTAB_CHECKER_GO /******/ 0x020 +#define SQLITE_VTAB_TXN_GO /**********/ 0x040 +#define SQLITE_VTAB_SAVEPOINTER_GO /**/ 0x080 +#define SQLITE_VTAB_SHADOWTABS_GO /***/ 0x100 int go_vtab_create(sqlite3_module *, int argc, const char *const *argv, sqlite3_vtab **, char **pzErr); @@ -157,6 +159,8 @@ static int go_vtab_integrity_wrapper(sqlite3_vtab *pVTab, const char *zSchema, return rc; } +static int go_vtab_shadown_name_wrapper(const char *zName) { return 1; } + int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags, go_handle handle) { struct go_module *mod = malloc(sizeof(struct go_module)); @@ -208,6 +212,9 @@ int sqlite3_create_module_go(sqlite3 *db, const char *zName, int flags, mod->base.xRelease = go_vtab_release; mod->base.xRollbackTo = go_vtab_rollback_to; } + if (flags & SQLITE_VTAB_SHADOWTABS_GO) { + mod->base.xShadowName = go_vtab_shadown_name_wrapper; + } if (mod->base.xCreate && !mod->base.xDestroy) { mod->base.xDestroy = mod->base.xDisconnect; } diff --git a/vfs/adiantum/README.md b/vfs/adiantum/README.md index b993484..508c685 100644 --- a/vfs/adiantum/README.md +++ b/vfs/adiantum/README.md @@ -1,13 +1,7 @@ -# Go `"adiantum"` SQLite VFS +# Go `adiantum` SQLite VFS This package wraps an SQLite VFS to offer encryption at rest. -> [!WARNING] -> This work was not certified by a cryptographer. -> If you need vetted encryption, you should purchase the -> [SQLite Encryption Extension](https://sqlite.org/see), -> and either wrap it, or seek assistance wrapping it. - The `"adiantum"` VFS wraps the default SQLite VFS using the [Adiantum](https://github.com/lukechampine/adiantum) tweakable and length-preserving encryption.\ diff --git a/vfs/memdb/README.md b/vfs/memdb/README.md index 193e29d..2e2611b 100644 --- a/vfs/memdb/README.md +++ b/vfs/memdb/README.md @@ -1,4 +1,4 @@ -# Go `"memdb"` SQLite VFS +# Go `memdb` SQLite VFS This package implements the [`"memdb"`](https://sqlite.org/src/doc/tip/src/memdb.c) SQLite VFS in pure Go. diff --git a/vfs/readervfs/README.md b/vfs/readervfs/README.md index 47a5f33..5281b88 100644 --- a/vfs/readervfs/README.md +++ b/vfs/readervfs/README.md @@ -1,4 +1,4 @@ -# Go `"reader"` SQLite VFS +# Go `reader` SQLite VFS This package implements a `"reader"` SQLite VFS that allows accessing any [`io.ReaderAt`](https://pkg.go.dev/io#ReaderAt) diff --git a/vtab.go b/vtab.go index a330c98..7c19330 100644 --- a/vtab.go +++ b/vtab.go @@ -16,14 +16,15 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor var flags int const ( - VTAB_CREATOR = 0x01 - VTAB_DESTROYER = 0x02 - VTAB_UPDATER = 0x04 - VTAB_RENAMER = 0x08 - VTAB_OVERLOADER = 0x10 - VTAB_CHECKER = 0x20 - VTAB_TXN = 0x40 - VTAB_SAVEPOINTER = 0x80 + VTAB_CREATOR = 0x001 + VTAB_DESTROYER = 0x002 + VTAB_UPDATER = 0x004 + VTAB_RENAMER = 0x008 + VTAB_OVERLOADER = 0x010 + VTAB_CHECKER = 0x020 + VTAB_TXN = 0x040 + VTAB_SAVEPOINTER = 0x080 + VTAB_SHADOWTABS = 0x100 ) if create != nil { @@ -52,6 +53,9 @@ func CreateModule[T VTab](db *Conn, name string, create, connect VTabConstructor if implements[VTabSavepointer](vtab) { flags |= VTAB_SAVEPOINTER } + if implements[VTabShadowTabler](vtab) { + flags |= VTAB_SHADOWTABS + } defer db.arena.mark()() namePtr := db.arena.string(name) @@ -174,6 +178,17 @@ type VTabOverloader interface { FindFunction(arg int, name string) (ScalarFunction, IndexConstraintOp) } +// A VTabShadowTabler allows a virtual table to protect the content +// of shadow tables from being corrupted by hostile SQL. +// +// Implementing this interface signals that a virtual table named +// "mumble" reserves all table names starting with "mumble_". +type VTabShadowTabler interface { + VTab + // https://sqlite.org/vtab.html#the_xshadowname_method + ShadowTables() +} + // A VTabChecker allows a virtual table to report errors // to the PRAGMA integrity_check and PRAGMA quick_check commands. //