summaryrefslogtreecommitdiffstats
path: root/php-sqlite3-defensive.patch
blob: c2e87cabd218ccf1a1f83889ca57ee78a01b548f (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
From 467239f10a6021d3eabe237ad0508b12d5d7d19e Mon Sep 17 00:00:00 2001
From: bohwaz <github.bohwaz@miam.kd2.org>
Date: Sun, 16 Dec 2018 22:52:37 +0100
Subject: [PATCH] SQLite3: add DEFENSIVE config for SQLite >= 3.26.0 as a
 mitigation strategy against potential security flaws

(cherry picked from commit 58c25bf679125a2da354db58ddc6b0cf6d10ee00)
---
 NEWS                                     |  5 +++
 ext/sqlite3/php_sqlite3.h                |  1 +
 ext/sqlite3/sqlite3.c                    |  9 ++++++
 ext/sqlite3/tests/sqlite3_defensive.phpt | 40 ++++++++++++++++++++++++
 php.ini-development                      | 11 +++++++
 php.ini-production                       | 11 +++++++
 6 files changed, 77 insertions(+)
 create mode 100644 ext/sqlite3/tests/sqlite3_defensive.phpt

diff --git a/NEWS b/NEWS
index 16da63bbb2..0bff457d2b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,11 @@
 PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 
+Backported from 7.1.28
+
+- SQLite3:
+  . Added sqlite3.defensive INI directive. (BohwaZ)
+
 Backported from 7.1.27
 
 - Core:
diff --git a/ext/sqlite3/php_sqlite3.h b/ext/sqlite3/php_sqlite3.h
index 88da39e75c..5304f00dbf 100644
--- a/ext/sqlite3/php_sqlite3.h
+++ b/ext/sqlite3/php_sqlite3.h
@@ -28,6 +28,7 @@ extern zend_module_entry sqlite3_module_entry;
 
 ZEND_BEGIN_MODULE_GLOBALS(sqlite3)
 	char *extension_dir;
+	int dbconfig_defensive;
 ZEND_END_MODULE_GLOBALS(sqlite3)
 
 #ifdef ZTS
diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c
index 80d6b897f1..761b777d06 100644
--- a/ext/sqlite3/sqlite3.c
+++ b/ext/sqlite3/sqlite3.c
@@ -82,6 +82,9 @@ static void php_sqlite3_error(php_sqlite3_db_object *db_obj, char *format, ...)
 */
 PHP_INI_BEGIN()
 	STD_PHP_INI_ENTRY("sqlite3.extension_dir",  NULL, PHP_INI_SYSTEM, OnUpdateString, extension_dir, zend_sqlite3_globals, sqlite3_globals)
+#if SQLITE_VERSION_NUMBER >= 3026000
+	STD_PHP_INI_ENTRY("sqlite3.defensive",  "1", PHP_INI_SYSTEM, OnUpdateBool, dbconfig_defensive, zend_sqlite3_globals, sqlite3_globals)
+#endif
 PHP_INI_END()
 /* }}} */
 
@@ -177,6 +180,12 @@ PHP_METHOD(sqlite3, open)
 		sqlite3_set_authorizer(db_obj->db, php_sqlite3_authorizer, NULL);
 	}
 
+#if SQLITE_VERSION_NUMBER >= 3026000
+	if (SQLITE3G(dbconfig_defensive)) {
+		sqlite3_db_config(db_obj->db, SQLITE_DBCONFIG_DEFENSIVE, 1, NULL);
+	}
+#endif
+
 	if (fullpath != filename) {
 		efree(fullpath);
 	}
diff --git a/ext/sqlite3/tests/sqlite3_defensive.phpt b/ext/sqlite3/tests/sqlite3_defensive.phpt
new file mode 100644
index 0000000000..064d87b50a
--- /dev/null
+++ b/ext/sqlite3/tests/sqlite3_defensive.phpt
@@ -0,0 +1,40 @@
+--TEST--
+SQLite3 defensive mode ini setting
+--SKIPIF--
+<?php require_once(__DIR__ . '/skipif.inc');
+
+if (SQLite3::version()['versionNumber'] < 3026000) {
+	die("skip: sqlite3 library version < 3.26: no support for defensive mode");
+}
+
+?>
+--INI--
+sqlite3.defensive=On
+--FILE--
+<?php
+
+$db = new SQLite3(':memory:');
+var_dump($db->exec('CREATE TABLE test (a, b);'));
+
+// This does not generate an error!
+var_dump($db->exec('PRAGMA writable_schema = ON;'));
+var_dump($db->querySingle('PRAGMA writable_schema;'));
+
+// Should be 1
+var_dump($db->querySingle('SELECT COUNT(*) FROM sqlite_master;'));
+
+// Should generate an error!
+var_dump($db->querySingle('DELETE FROM sqlite_master;'));
+
+// Should still be 1
+var_dump($db->querySingle('SELECT COUNT(*) FROM sqlite_master;'));
+?>
+--EXPECTF--
+bool(true)
+bool(true)
+int(1)
+int(1)
+
+Warning: SQLite3::querySingle(): Unable to prepare statement: 1, table sqlite_master may not be modified in %s on line %d
+bool(false)
+int(1)
\ No newline at end of file
diff --git a/php.ini-development b/php.ini-development
index 752f601436..27cc55b75b 100644
--- a/php.ini-development
+++ b/php.ini-development
@@ -981,8 +981,19 @@ cli_server.color = On
 ;intl.use_exceptions = 0
 
 [sqlite3]
+; Directory pointing to SQLite3 extensions
+; http://php.net/sqlite3.extension-dir
 ;sqlite3.extension_dir =
 
+; SQLite defensive mode flag (only available from SQLite 3.26+)
+; When the defensive flag is enabled, language features that allow ordinary
+; SQL to deliberately corrupt the database file are disabled. This forbids
+; writing directly to the schema, shadow tables (eg. FTS data tables), or
+; the sqlite_dbpage virtual table.
+; https://www.sqlite.org/c3ref/c_dbconfig_defensive.html
+; (for older SQLite versions, this flag has no use)
+sqlite3.defensive = 1
+
 [Pcre]
 ;PCRE library backtracking limit.
 ; http://php.net/pcre.backtrack-limit
diff --git a/php.ini-production b/php.ini-production
index 97b5043ce9..d7e9420a72 100644
--- a/php.ini-production
+++ b/php.ini-production
@@ -981,8 +981,19 @@ cli_server.color = On
 ;intl.use_exceptions = 0
 
 [sqlite3]
+; Directory pointing to SQLite3 extensions
+; http://php.net/sqlite3.extension-dir
 ;sqlite3.extension_dir =
 
+; SQLite defensive mode flag (only available from SQLite 3.26+)
+; When the defensive flag is enabled, language features that allow ordinary
+; SQL to deliberately corrupt the database file are disabled. This forbids
+; writing directly to the schema, shadow tables (eg. FTS data tables), or
+; the sqlite_dbpage virtual table.
+; https://www.sqlite.org/c3ref/c_dbconfig_defensive.html
+; (for older SQLite versions, this flag has no use)
+sqlite3.defensive = 1
+
 [Pcre]
 ;PCRE library backtracking limit.
 ; http://php.net/pcre.backtrack-limit