Documentation Source Text

Check-in [3ae0a793ec]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Further typo fixes in the pointer-passing document.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3ae0a793ec163c509980bc7ddf8bc7c4b65e85be4a54675b24b06df65d7d11db
User & Date: drh 2017-07-24 15:29:56
Context
2017-07-25
15:40
Fix typo in the pointer-passing document. check-in: 2f0174e967 user: drh tags: trunk
2017-07-24
15:29
Further typo fixes in the pointer-passing document. check-in: 3ae0a793ec user: drh tags: trunk
15:19
Add a couple of sentences to the pointer-passing document to try to clarify that the caller owns the passed pointers. check-in: 74ab40f1f1 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to pages/bindptr.in.

1
2
3
4
5
6
7
8
9
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<title>Pointer Passing Interfaces</title>
<tcl>hd_keywords {pointer passing interfaces}
</tcl>

<fancy_format>

<h1>Overview</h1>

<p>
................................................................................
Passing around pointers as if they were integers or BLOBs is easy,
effective, and works well in an environment where the application
components are all friendly toward one another.  However, passing pointers
as integers and BLOBs allows hostile SQL text to forge invalid pointers that
can carry out mischief.

<p>
For example, the first argument to the [snippet()] function is suppose to
be a special column of the FTS3 table that contains a pointer to an fts3cursor
object that contains information about the current full text search match.
That pointer was formerly passed as a BLOB.  
For example, if the FTS3 table is named "t1" and has a column named "cx",
one might write:

<codeblock>
................................................................................
prevent pointer values from being forged.  This was accomplished by
having the sender attach a subtype to each pointer using
[sqlite3_result_subtype()] and having the receiver verify that subtype
using [sqlite3_value_subtype()] and reject pointers that had an incorrect
subtype.  Since there is no way to attach a subtype to a result using
pure SQL, this prevents pointers from being forged using SQL.  The only
way to send a pointer is to use C code.  If an attacker can set a subtype,
then he is also able to forge pointer without the help of SQLite.

<p>
Using subtypes to identify valid pointers prevented the WebSQL exploit.
But it turned out to be an incomplete solution.

<tcl>hd_fragment ptrleak {pointer leak} {pointer leaks}</tcl>
<h2>Pointer Leaks</h2>
................................................................................
value of a pointer will get an SQL NULL answer.  The only way to
discover whether or not a value has an associated pointer is to
use the [sqlite3_value_pointer()] interface with the appropriate
type string T. 

<p>
Pointer values read by [sqlite3_value_pointer()]
cannot be generated by pure SQL.  Hence, it is not possible for SQL to forge
a pointers.

<p>
Pointer values generated by [sqlite3_bind_pointer()] and
[sqlite3_result_pointer()] cannot be read by pure SQL.
Hence, it is not possible for SQL to leak the value of pointers.

<p>
................................................................................
<p>
Except, the statement above does not work, thanks to pointer types.
The pointer generated by the MATCH operator has a type of "fts3cursor"
but the carray() function expects to receives a pointer of type "carray".
Because the pointer type on the [sqlite3_result_pointer()] does not match
the pointer type on the [sqlite3_value_pointer()] call, 
[sqlite3_value_pointer()] returns NULL in carray() and thus signals
the CARRAY extension that it has been passed and invalid pointer.

<p>
Pointer types are static strings, which ideally should be string literals
embedded directly in the SQLite API call, not parameters passed in from
other functions.  Consideration was given to using integer values as
the pointer type, but static strings provides a much larger name space
which reduces the chance of accidental type-name collisions between
................................................................................
<p>
The pointers that piggy-back on SQL NULL values using the
[sqlite3_bind_pointer()], [sqlite3_result_pointer()], and
[sqlite3_value_pointer()] interface are transient and ephemeral.
The pointers are never written into the database.  The pointers
will not survive sorting.  The latter fact is why there is no
sqlite3_column_pointer() interface, since it is impossible to
predict whether or not the query planner will insert a sort operating
prior to returning a value from a query, so it would be impossible to
know if a pointer value inserted into a query by
[sqlite3_bind_pointer()] or [sqlite3_result_pointer()] would survive
through to the result set.

<p>
Pointer values must flow directly from their producer into their

|







 







|







 







|







 







|
|







 







|







 







|







1
2
3
4
5
6
7
8
9
..
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<title>Pointer Passing Interfaces</title>
<tcl>hd_keywords {pointer passing interfaces} {pointer passing interface}
</tcl>

<fancy_format>

<h1>Overview</h1>

<p>
................................................................................
Passing around pointers as if they were integers or BLOBs is easy,
effective, and works well in an environment where the application
components are all friendly toward one another.  However, passing pointers
as integers and BLOBs allows hostile SQL text to forge invalid pointers that
can carry out mischief.

<p>
For example, the first argument to the [snippet()] function is supposed to
be a special column of the FTS3 table that contains a pointer to an fts3cursor
object that contains information about the current full text search match.
That pointer was formerly passed as a BLOB.  
For example, if the FTS3 table is named "t1" and has a column named "cx",
one might write:

<codeblock>
................................................................................
prevent pointer values from being forged.  This was accomplished by
having the sender attach a subtype to each pointer using
[sqlite3_result_subtype()] and having the receiver verify that subtype
using [sqlite3_value_subtype()] and reject pointers that had an incorrect
subtype.  Since there is no way to attach a subtype to a result using
pure SQL, this prevents pointers from being forged using SQL.  The only
way to send a pointer is to use C code.  If an attacker can set a subtype,
then he is also able to forge a pointer without the help of SQLite.

<p>
Using subtypes to identify valid pointers prevented the WebSQL exploit.
But it turned out to be an incomplete solution.

<tcl>hd_fragment ptrleak {pointer leak} {pointer leaks}</tcl>
<h2>Pointer Leaks</h2>
................................................................................
value of a pointer will get an SQL NULL answer.  The only way to
discover whether or not a value has an associated pointer is to
use the [sqlite3_value_pointer()] interface with the appropriate
type string T. 

<p>
Pointer values read by [sqlite3_value_pointer()]
cannot be generated by pure SQL.  Hence, it is not possible for SQL to
forge pointers.

<p>
Pointer values generated by [sqlite3_bind_pointer()] and
[sqlite3_result_pointer()] cannot be read by pure SQL.
Hence, it is not possible for SQL to leak the value of pointers.

<p>
................................................................................
<p>
Except, the statement above does not work, thanks to pointer types.
The pointer generated by the MATCH operator has a type of "fts3cursor"
but the carray() function expects to receives a pointer of type "carray".
Because the pointer type on the [sqlite3_result_pointer()] does not match
the pointer type on the [sqlite3_value_pointer()] call, 
[sqlite3_value_pointer()] returns NULL in carray() and thus signals
the CARRAY extension that it has been passed an invalid pointer.

<p>
Pointer types are static strings, which ideally should be string literals
embedded directly in the SQLite API call, not parameters passed in from
other functions.  Consideration was given to using integer values as
the pointer type, but static strings provides a much larger name space
which reduces the chance of accidental type-name collisions between
................................................................................
<p>
The pointers that piggy-back on SQL NULL values using the
[sqlite3_bind_pointer()], [sqlite3_result_pointer()], and
[sqlite3_value_pointer()] interface are transient and ephemeral.
The pointers are never written into the database.  The pointers
will not survive sorting.  The latter fact is why there is no
sqlite3_column_pointer() interface, since it is impossible to
predict whether or not the query planner will insert a sort operation
prior to returning a value from a query, so it would be impossible to
know if a pointer value inserted into a query by
[sqlite3_bind_pointer()] or [sqlite3_result_pointer()] would survive
through to the result set.

<p>
Pointer values must flow directly from their producer into their