@@ -96,6 +96,24 @@ inline MaybeLocal<String> Utf8StringMaybeOneByte(Isolate* isolate,
9696 } \
9797 } while (0 )
9898
99+ // SQLite requires that an authorizer callback not modify the connection that
100+ // invoked it. Preparing and stepping statements both count as modifying it.
101+ // See https://www.sqlite.org/c3ref/set_authorizer.html.
102+ #define THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db ) \
103+ THROW_AND_RETURN_ON_BAD_STATE ( \
104+ (env), \
105+ (db)->IsInAuthorizerCallback (), \
106+ "database cannot be accessed from an authorizer callback")
107+
108+ // Finalizing a statement frees its virtual machine. Any callback that SQLite
109+ // invokes from inside sqlite3_step() may be running on that very statement, so
110+ // finalizing from one is a use-after-free rather than a contract violation.
111+ #define THROW_AND_RETURN_IF_IN_CALLBACK (env, db ) \
112+ THROW_AND_RETURN_ON_BAD_STATE ( \
113+ (env), \
114+ (db)->IsInCallback (), \
115+ "statement cannot be finalized from a callback")
116+
99117#define SQLITE_VALUE_TO_JS (from, isolate, use_big_int_args, result, ...) \
100118 do { \
101119 switch (sqlite3_##from##_type (__VA_ARGS__)) { \
@@ -825,6 +843,12 @@ Intercepted DatabaseSyncLimits::LimitsSetter(
825843 return Intercepted::kYes ;
826844 }
827845
846+ if (limits->database_ ->IsInAuthorizerCallback ()) {
847+ THROW_ERR_INVALID_STATE (
848+ env, " database cannot be accessed from an authorizer callback" );
849+ return Intercepted::kYes ;
850+ }
851+
828852 if (!value->IsNumber ()) {
829853 THROW_ERR_INVALID_ARG_TYPE (
830854 isolate, " Limit value must be a non-negative integer or Infinity." );
@@ -1081,6 +1105,7 @@ void DatabaseSync::CreateTagStore(const FunctionCallbackInfo<Value>& args) {
10811105 THROW_ERR_INVALID_STATE (env, " database is not open" );
10821106 return ;
10831107 }
1108+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
10841109 int capacity = 1000 ;
10851110 if (args.Length () > 0 && !args[0 ]->IsUndefined ()) {
10861111 if (!args[0 ]->IsNumber ()) {
@@ -1483,6 +1508,7 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) {
14831508 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
14841509 Environment* env = Environment::GetCurrent (args);
14851510 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1511+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
14861512
14871513 if (!args[0 ]->IsString ()) {
14881514 THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
@@ -1606,6 +1632,7 @@ void DatabaseSync::Exec(const FunctionCallbackInfo<Value>& args) {
16061632 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
16071633 Environment* env = Environment::GetCurrent (args);
16081634 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1635+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
16091636
16101637 if (!args[0 ]->IsString ()) {
16111638 THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
@@ -1630,6 +1657,7 @@ void DatabaseSync::CustomFunction(const FunctionCallbackInfo<Value>& args) {
16301657 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
16311658 Environment* env = Environment::GetCurrent (args);
16321659 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1660+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
16331661
16341662 if (!args[0 ]->IsString ()) {
16351663 THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
@@ -1803,6 +1831,7 @@ void DatabaseSync::Serialize(const FunctionCallbackInfo<Value>& args) {
18031831 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
18041832 Environment* env = Environment::GetCurrent (args);
18051833 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1834+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
18061835
18071836 std::string db_name = " main" ;
18081837 if (!args[0 ]->IsUndefined ()) {
@@ -1858,6 +1887,7 @@ void DatabaseSync::Deserialize(const FunctionCallbackInfo<Value>& args) {
18581887 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
18591888 Environment* env = Environment::GetCurrent (args);
18601889 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1890+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
18611891
18621892 if (!args[0 ]->IsUint8Array ()) {
18631893 THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
@@ -1933,6 +1963,7 @@ void DatabaseSync::AggregateFunction(const FunctionCallbackInfo<Value>& args) {
19331963 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
19341964 Environment* env = Environment::GetCurrent (args);
19351965 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
1966+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
19361967 Utf8Value name (env->isolate (), args[0 ].As <String>());
19371968 Local<Object> options = args[1 ].As <Object>();
19381969 Local<Value> start_v;
@@ -2144,6 +2175,7 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
21442175 DatabaseSync* db;
21452176 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
21462177 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
2178+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
21472179
21482180 sqlite3_session* pSession;
21492181 int r = sqlite3session_create (db->connection_ , db_name.c_str (), &pSession);
@@ -2313,6 +2345,7 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
23132345 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
23142346 Environment* env = Environment::GetCurrent (args);
23152347 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
2348+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
23162349
23172350 if (!args[0 ]->IsUint8Array ()) {
23182351 THROW_ERR_INVALID_ARG_TYPE (
@@ -2447,6 +2480,7 @@ void DatabaseSync::EnableLoadExtension(
24472480 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
24482481 Environment* env = Environment::GetCurrent (args);
24492482 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
2483+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
24502484
24512485 Isolate* isolate = env->isolate ();
24522486 if (!args[0 ]->IsBoolean ()) {
@@ -2475,6 +2509,7 @@ void DatabaseSync::EnableDefensive(const FunctionCallbackInfo<Value>& args) {
24752509 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
24762510 Environment* env = Environment::GetCurrent (args);
24772511 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
2512+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
24782513
24792514 Isolate* isolate = env->isolate ();
24802515 if (!args[0 ]->IsBoolean ()) {
@@ -2500,6 +2535,7 @@ void DatabaseSync::LoadExtension(const FunctionCallbackInfo<Value>& args) {
25002535 env, !db->allow_load_extension_ , " extension loading is not allowed" );
25012536 THROW_AND_RETURN_ON_BAD_STATE (
25022537 env, !db->enable_load_extension_ , " extension loading is not allowed" );
2538+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
25032539
25042540 if (!args[0 ]->IsString ()) {
25052541 THROW_ERR_INVALID_ARG_TYPE (env->isolate (),
@@ -2528,6 +2564,7 @@ void DatabaseSync::SetAuthorizer(const FunctionCallbackInfo<Value>& args) {
25282564 ASSIGN_OR_RETURN_UNWRAP (&db, args.This ());
25292565 Environment* env = Environment::GetCurrent (args);
25302566 THROW_AND_RETURN_ON_BAD_STATE (env, !db->IsOpen (), " database is not open" );
2567+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, db);
25312568
25322569 Isolate* isolate = env->isolate ();
25332570
@@ -2564,6 +2601,7 @@ int DatabaseSync::AuthorizerCallback(void* user_data,
25642601 const char * param4) {
25652602 DatabaseSync* db = static_cast <DatabaseSync*>(user_data);
25662603 CallbackDepthGuard guard (db);
2604+ AuthorizerDepthGuard authorizer_guard (db);
25672605 Environment* env = db->env ();
25682606 Isolate* isolate = env->isolate ();
25692607 HandleScope handle_scope (isolate);
@@ -2677,12 +2715,20 @@ void StatementSync::Close(const FunctionCallbackInfo<Value>& args) {
26772715 Environment* env = Environment::GetCurrent (args);
26782716 THROW_AND_RETURN_ON_BAD_STATE (
26792717 env, stmt->IsFinalized (), " statement has been finalized" );
2718+ THROW_AND_RETURN_IF_IN_CALLBACK (env, stmt->db_ .get ());
26802719 stmt->Close ();
26812720}
26822721
26832722void StatementSync::Dispose (const FunctionCallbackInfo<Value>& args) {
26842723 StatementSync* stmt;
26852724 ASSIGN_OR_RETURN_UNWRAP (&stmt, args.This ());
2725+ Environment* env = Environment::GetCurrent (args);
2726+ // Disposal is idempotent, so an already-finalized statement is a no-op even
2727+ // inside a callback.
2728+ if (stmt->IsFinalized ()) {
2729+ return ;
2730+ }
2731+ THROW_AND_RETURN_IF_IN_CALLBACK (env, stmt->db_ .get ());
26862732 stmt->Close ();
26872733}
26882734
@@ -3127,6 +3173,7 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
31273173 Environment* env = Environment::GetCurrent (args);
31283174 THROW_AND_RETURN_ON_BAD_STATE (
31293175 env, stmt->IsFinalized (), " statement has been finalized" );
3176+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, stmt->db_ .get ());
31303177 Isolate* isolate = env->isolate ();
31313178 int r = stmt->ResetStatement ();
31323179 CHECK_ERROR_OR_THROW (isolate, stmt->db_ .get (), r, SQLITE_OK , void ());
@@ -3154,6 +3201,7 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
31543201 Environment* env = Environment::GetCurrent (args);
31553202 THROW_AND_RETURN_ON_BAD_STATE (
31563203 env, stmt->IsFinalized (), " statement has been finalized" );
3204+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, stmt->db_ .get ());
31573205 int r = stmt->ResetStatement ();
31583206 CHECK_ERROR_OR_THROW (env->isolate (), stmt->db_ .get (), r, SQLITE_OK , void ());
31593207
@@ -3177,6 +3225,7 @@ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
31773225 Environment* env = Environment::GetCurrent (args);
31783226 THROW_AND_RETURN_ON_BAD_STATE (
31793227 env, stmt->IsFinalized (), " statement has been finalized" );
3228+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, stmt->db_ .get ());
31803229 int r = stmt->ResetStatement ();
31813230 CHECK_ERROR_OR_THROW (env->isolate (), stmt->db_ .get (), r, SQLITE_OK , void ());
31823231
@@ -3201,6 +3250,7 @@ void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
32013250 Environment* env = Environment::GetCurrent (args);
32023251 THROW_AND_RETURN_ON_BAD_STATE (
32033252 env, stmt->IsFinalized (), " statement has been finalized" );
3253+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, stmt->db_ .get ());
32043254 int r = stmt->ResetStatement ();
32053255 CHECK_ERROR_OR_THROW (env->isolate (), stmt->db_ .get (), r, SQLITE_OK , void ());
32063256
@@ -3483,6 +3533,7 @@ void SQLTagStore::Run(const FunctionCallbackInfo<Value>& args) {
34833533
34843534 THROW_AND_RETURN_ON_BAD_STATE (
34853535 env, !session->database_ ->IsOpen (), " database is not open" );
3536+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, session->database_ .get ());
34863537
34873538 BaseObjectPtr<StatementSync> stmt = PrepareStatement (args);
34883539
@@ -3509,6 +3560,7 @@ void SQLTagStore::Iterate(const FunctionCallbackInfo<Value>& args) {
35093560
35103561 THROW_AND_RETURN_ON_BAD_STATE (
35113562 env, !session->database_ ->IsOpen (), " database is not open" );
3563+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, session->database_ .get ());
35123564
35133565 BaseObjectPtr<StatementSync> stmt = PrepareStatement (args);
35143566
@@ -3537,6 +3589,7 @@ void SQLTagStore::Get(const FunctionCallbackInfo<Value>& args) {
35373589
35383590 THROW_AND_RETURN_ON_BAD_STATE (
35393591 env, !session->database_ ->IsOpen (), " database is not open" );
3592+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, session->database_ .get ());
35403593
35413594 BaseObjectPtr<StatementSync> stmt = PrepareStatement (args);
35423595
@@ -3566,6 +3619,7 @@ void SQLTagStore::All(const FunctionCallbackInfo<Value>& args) {
35663619
35673620 THROW_AND_RETURN_ON_BAD_STATE (
35683621 env, !session->database_ ->IsOpen (), " database is not open" );
3622+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, session->database_ .get ());
35693623
35703624 BaseObjectPtr<StatementSync> stmt = PrepareStatement (args);
35713625
@@ -3592,6 +3646,10 @@ void SQLTagStore::All(const FunctionCallbackInfo<Value>& args) {
35923646void SQLTagStore::Clear (const FunctionCallbackInfo<Value>& args) {
35933647 SQLTagStore* store;
35943648 ASSIGN_OR_RETURN_UNWRAP (&store, args.This ());
3649+ Environment* env = Environment::GetCurrent (args);
3650+ if (store->database_ ) {
3651+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, store->database_ .get ());
3652+ }
35953653 store->sql_tags_ .Clear ();
35963654}
35973655
@@ -3785,6 +3843,7 @@ void StatementSyncIterator::Next(const FunctionCallbackInfo<Value>& args) {
37853843 Environment* env = Environment::GetCurrent (args);
37863844 THROW_AND_RETURN_ON_BAD_STATE (
37873845 env, iter->stmt_ ->IsFinalized (), " statement has been finalized" );
3846+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, iter->stmt_ ->db_ .get ());
37883847 Isolate* isolate = env->isolate ();
37893848
37903849 auto iter_template = getLazyIterTemplate (env);
@@ -3862,6 +3921,7 @@ void StatementSyncIterator::Return(const FunctionCallbackInfo<Value>& args) {
38623921 Environment* env = Environment::GetCurrent (args);
38633922 THROW_AND_RETURN_ON_BAD_STATE (
38643923 env, iter->stmt_ ->IsFinalized (), " statement has been finalized" );
3924+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, iter->stmt_ ->db_ .get ());
38653925 Isolate* isolate = env->isolate ();
38663926
38673927 sqlite3_reset (iter->stmt_ ->statement_ );
@@ -3940,6 +4000,7 @@ void Session::Changeset(const FunctionCallbackInfo<Value>& args) {
39404000 env, !session->database_ ->IsOpen (), " database is not open" );
39414001 THROW_AND_RETURN_ON_BAD_STATE (
39424002 env, session->session_ == nullptr , " session is not open" );
4003+ THROW_AND_RETURN_IF_IN_AUTHORIZER (env, session->database_ .get ());
39434004
39444005 int nChangeset;
39454006 void * pChangeset;
0 commit comments