-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Applications using both gtk3 and sqlcipher do not work #385
Comments
Hello @eli-schwartz, thanks for your interest in SQLCipher. This situation with Signal is serious and undesirable, however, the proposed change to SQLCipher core may not be appropriate in this case. SQLCipher is intended solely as a drop-in replacement for SQLite. The exact duplication of the API and symbols is deliberate because the intended use is for it to be loaded instead of SQLite, not alongside it. That said, this issue can and should be handled downstream at the application level:
That said, as noted before in other similar tickets, we recommend against linking multiple versions of SQLite/SQLCipher simultaneously because it is potentially dangerous and introduces a documented risk of database corruption. Also, as an important point of clarification, this issue is not actually corrupting the Signal database as reported in signalapp/Signal-Desktop#4513 and https://bugs.archlinux.org/task/69980. Rather, when the system libsqlite3.so is being used by Signal and it encounters a pre-existing encrypted database, it simply does not know how to open it. The library reports that it is not a known database format, but the database is just fine. It is the Signal application behavior that offers to delete the database and start over (which is perhaps a dangerous thing to do). We usually advise that applications using SQLCipher via dynamic linking perform a runtime check to verify that the expected libsqlcipher.so library is being used. Executing the Finally, in addition to the potential data loss / functional issue for existing Signal users, this issue risks data exposure for new users. The use of the system SQLite will not throw any errors if an encrypted database does not already exist. I suspect a new install will just leave the user's message database unencrypted on the file system. A runtime version check will help address this problem as well. Let us know if this rationale makes sense or if you have any other thoughts or questions. |
I did acknowledge that applications may report this, then offer to delete something they shouldn't. This is of course not the fault of sqlcipher. But it is an example of real world effects. I tried to make it clear that the larger issue here is sqlcipher is incorrect for assuming that an application gets to choose to only link one of (sqlcipher, libsqlite) and not the other. But maybe I wasn't clear. Applications that have NO dependencies other than sqlcipher and a system libc can choose this. It is not safe, sane, or reasonable to assume any other kind of software gets to choose. Gtk3 demonstrates this by providing operating system level functionality that is supposed to use boring old regular unencrypted sqlite databases. Gtk3 "tracker" filesystem indexing runs in the same process space as, and (this is important) across a project boundary from, "signal, a gtk3 application that uses sqlcipher for the signal database". Running two different sql libraries, each on a different database, in the same process space... is not fundamentally a bad or wrong thing to do. The problem is when they both bind to the same symbol namespace, and the C compiler cannot instruct the binary at runtime to use the same version of the symbol that each location was actually linked to. I don't understand why it would be inappropriate for sqlcipher core. Users and developers still compile against "sqlite_foo", not "sqlite_foo@SQLCIPHER", this is entirely just compiler symbol mangling to avoid runtime collision. Unless you want people to be able to compile applications against libsqlite, distribute the binaries to users, and let the users secretly swap in sqlcipher, collide the symbols, and trick the binary into successfully reading encrypted databases??? |
Note that cipher_version seems like it would not be useful for any purpose other than to gracefully error out and say "sorry, Mr. User, we can't find the right sql library so we have no idea what to do. Your system is broken. Sorry." Which is admittedly better than claiming the database is broken and deleting data. But I can't help feeling that the right solution is to make gtk3 applications actually able to use sqlcipher. |
Note also that signal happens to use a forked private copy of sqlcipher that doesn't do the right thing, but other applications use the system sqlcipher, I mentioned for example element-desktop. Those can't be fixed by statically compiling, or by version scripts on a system loaded external .so |
Hello @eli-schwartz. Before going any further into discussion about whether this should be included in SQLCipher core, we decided to run a proof of concept to determine if this approach is a viable option to solve the original problem. This involved setting up a test case as follows. First,
The resulting .so was verified to ensure it included the version tag via
Next, we created two simple shared libraries that simply invoke some basic functions of the sqlite3_* API (e.g The first,
The second,
Finally a simple driver program was linked with Unfortunately, even when using the version script for To round out the experiment we did prepare a specialized standalone build of Based on these results, it seems that in order for this to work consistently, both the I will be the first to admit that my knowledge of DSO versioning is limited. On the other hand, there are posts on other forums which describe this same behavior, including in the context of problems substituting specific versions of SQLite (albeit with Firefox). If you are able to provide advice on how to alter this linker behavior, or you can prepare a working reference example that demonstrates this solution as intended, we'd be happy to take a look at it and discuss further. |
AFAIK this is the only reliable way for us to ensure SQLCipher will be loaded instead of SQLite. It feels like a hack/workaround but according to the SQLCipher developers [0] "this issue can and should be handled downstream at the application level: 1. While it may feel like a workaround, using LD_PRELOAD is a legitimate approach here because it will substitute the system SQLite with SQLCipher which is the intended usage model;". This fixes NixOS#108772 for NixOS 20.09 users who upgrade to NixOS 21.05 and replaces NixOS#117555. For nixos-unstable users this will unfortunately break everything again so we should add a script to ease the transition (in a separate commit so that we can revert it for NixOS 21.05). [0]: sqlcipher/sqlcipher#385 (comment)
Landed here because my Signal installation exploded, but back on the topic of symbol versioning: Reading https://maskray.me/blog/2020-11-26-all-about-symbol-versioning#linker-behavior suggests that |
Hey @rfjakob - thanks for taking a look at this. Can you provide any advice on how to link so that the single "@" is used? I've read through the document you linked to, but don't see any guidance on how to do so. |
PS: Whoops, misinterpreted this issue, sorry. This one is about sqlcipher in general, not just in the context of Signal/Electron. |
I think you would need to change the headers and add |
After reviewing many related issues, it seems that almost all dependent projects have been able to resolve these issues either via linking changes or preloading, with no invasive changes required to SQLCipher. I will close this for now, as we haven't had any other reported issues in more than a year. |
I don't agree with you , it is required change SQLCipher to not clash with SQLLite , you should find a way to change all symbols |
Hi @sergiomb2,
This isn't just an issue with SQLCipher, nor of addressing duplicate symbols; linking multiple versions of SQLite into the same application pose a database corruption possibility 1. Footnotes |
Quoting "Recent versions of gtk3 directly link to upstream sqlite3 to provide generic system features." the link above describe exactly the same problem, when an app link to 2 versions on SQLite . Clearly SQLite is problematic with versions, but be forced to use export LD_PRELOAD= is not a good solution , so modify all symbols with a prefix or suffix and bump the "so" version , I think is an easy thing to do |
Expected Behavior
An sqlcipher-using program should not care what UI toolkits or other dependencies use indirectly. Opening databases exclusively via the sqlcipher API should work in a self-contained manner.
Actual Behavior
Recent versions of gtk3 directly link to upstream sqlite3 to provide generic system features.
Applications that link to both gtk3 and sqlcipher report data corruption due to inability to open the database, then offer to delete the encrypted database and start afresh.
See for example:
signalapp/Signal-Desktop#4513 (comment)
https://bugs.archlinux.org/task/69980
Steps to Reproduce
Install Signal Desktop or Element Desktop on Arch Linux, and downgrade gtk3 to 3.24.27-3.
Try to access encrypted messages.
Recommended fix
Since sqlcipher provides an overlapping API with sqlite, it is not safe to load both libraries into the same process space. The symbols will clash and unpredictably resolve one or the other.
Symbol clashing can be fixed! Please consider using a GNU ld version script: https://sourceware.org/binutils/docs-2.29/ld/VERSION.html
The build-time API will remain the same. The ABI will change, and after relinking, programs which use e.g.
sqlite3_open
via sqlcipher will resolve the symbolsqlite3_open@SQLCIPHER
(or however you choose to name it) which ensures the symbol comes from libsqlcipher.so rather than libsqlite3.soSQLCipher version: 4.4.2
The text was updated successfully, but these errors were encountered: