SQLite Forum

How to Corrrupt an SQLite DB Section 2.2.1
Login

How to Corrrupt an SQLite DB Section 2.2.1

(1) By anonymous on 2022-08-25 13:59:17 [source]

Hello, before I start, forgive me, my expertise isn't well developed in native development.

I would like some kind of clarification on Section 2.2.1[1] Multiple copies of SQLite linked into the same application. More specifically, around the text "...if multiple copies of SQLite are linked into the same application..."

I wouldn't have thought this would be possible because I would have expected duplicate symbols to be generated during linking or otherwise cause a compilation error. But atlas, I think I may have replicated this kind of situation. I'm going to attempt to explain my setup, then ask a couple of questions.

My project is a Cordova project (my "application"), which imports a Cordova plugin  "LibA". LibA is essentially SQLite built with some additional custom sources and gets distributed as a shared library.

My application, imports another library "LibB", which is built against a static version of SQLite (which may not be the same version as LibA). The library itself is distributed as a shared library.

LibA may open up multiple connections to the same DB file and may do writing to it.
LibB will open a single connection to the same DB file and will only ever read from it.

In Otherwords:

                 ---> LibA ---> SQLite Version X (Sources) ---> LibA.so
                /              
Application ---<               
                \              
                 ---> LibB ---> SQLite Version Y (Static Library) ---> LibB.so

It is my understanding that I'm at risk of corruption as laid out in Section 2.2.1

So ultimately my questions are:

1. Is my understanding of this issue correct? Am I at risk of 2.2.1 (or other file locking issues?)
2. Would building SQLite as a shared library that both libraries links against solve these concerns? e.g.: "The solution was to change the application build procedures to link against just one copy of SQLite instead of two."

In Otherwords, that's saying the application build should look something like:

                 ---> LibA ---
                /             \ 
Application ---<               >---> SQLite.so
                \             / 
                 ---> LibB ---

Thanks in advance. Should additional information be required, please let me know.

References:
[1] https://www.sqlite.org/howtocorrupt.html

(2) By Larry Brasfield (larrybr) on 2022-08-25 14:16:52 in reply to 1 [link] [source]

It is my understanding that I'm at risk of corruption as laid out in Section 2.2.1 ... Is my understanding of this issue correct? Am I at risk of 2.2.1 (or other file locking issues?)

Yes, the scenario you describe is among the set covered by 2.2.2.

Would building SQLite as a shared library that both libraries links against solve these concerns?

Yes.

(6) By anonymous on 2022-08-25 19:29:05 in reply to 2 [link] [source]

Thanks for validating my understanding.

(3.1) By ddevienne on 2022-08-25 14:20:04 edited from 3.0 in reply to 1 [link] [source]

I think it boils down to the design of POSIX that most *nix system implement.

As far as I recall, SQLite has a singleton to maintain some SQLite invariants,
and thus if you manage to have two copies of SQLite in a given process (which is possible indeed),
then you'd have two instances of those singletons, so if both of those access the same DB file,
corruption could ensue.

Note that I'm not 100% sure it's Linux/POSIX only, but AFAIK Windows is not affected.
I'm also not 100% sure it's only dangerous when the same DB is accessed concurrently.
But these are what I do recall. FWIW.

(4) By Richard Hipp (drh) on 2022-08-25 14:24:31 in reply to 1 [link] [source]

It does seem like you are vulnerable. I don't know how you would go about linking your application such that both libA and libB share the same copy of SQLite, but if you can figure it out, that would certainly be a good solution.

The issue goes back to a design problem in posix advisory locks. In posix, if you call close() on a file descriptor, that clears all locks against the same file, even locks from different file descriptors, within the same process. SQLite works around this design bug by using global variables and mutexes to keep track of all open file descriptors to the same file, and not closing any of those file descriptors while other descriptors to the same file are still open. This work-around breaks down if you have two or more copies of SQLite linked, because each copy of SQLite comes with its own set of global variables.

Another way to work around the problem is to ensure that close() is never called while a lock is being held on another file descriptor for the same file. This means, for example, do not close database connections while other database connections to the same database are active. If you have 2 or more connections to the same database, and you want to close one of them, close them all first, then reopen the ones you want to keep. This approach will also prevent problems, but shifts the burden to the application.

The bug is in posix advisory locks. If you run on Windows, this problem never comes up.

(5) By Keith Medcalf (kmedcalf) on 2022-08-25 15:39:42 in reply to 4 [link] [source]

Also each discontiguous saved segment (dll/so) will contain its own memory allocator (they will, in fact, contain their own (separate) sqlite3_malloc and memory allocated by one will cause an explosion if you attempt to release by the other, unless both versions are using the same underlying allocator. Even then, certain cross-segment allocations/releases will cause a crash.