m4heshd / better-sqlite3-multiple-ciphers

better-sqlite3 with multiple-cipher encryption support 🔒
MIT License
140 stars 27 forks source link

core dump - segmentation fault #27

Closed julianhille closed 2 years ago

julianhille commented 2 years ago

It seems a bit tricky to do trigger but this is what i did:

node Version: 16.16, also tried 16.13 better-sqlite3-multiple-ciphers: 7.6.2 OS: Kernel 5.15.0-41-generic, x86_64 GNU/Linux

node                                                                                                                                                                                                                                                                                                                                                                                       [22/07/19| 5:28PM]
Welcome to Node.js v16.16.0.
Type ".help" for more information.
> 
> sq = require('better-sqlite3-multiple-ciphers')
[Function: Database] { SqliteError: [Function: SqliteError] }
> db = sq(':memory:')
Database {
  name: ':memory:',
  open: true,
  inTransaction: false,
  readonly: false,
  memory: true
}
> db.pragma("rekey='password'")
[1]    179170 segmentation fault (core dumped)  node

This does not happen always. Most of the time it works.

Jul 19 17:32:01 julian systemd-coredump[179207]: Process 179170 (node) of user 1000 dumped core.#012#012Stack trace of thread 179170:#012#0  0x00007f8538a6ef84 _int_malloc (libc.so.6 + 0x97f84)#012#1  0x00007f8538a71299 __GI___libc_malloc (libc.so.6 + 0x9a299)#012#2  0x00007f8538e00b39 _Znwm (libstdc++.so.6 + 0xaab39)#012#3  0x0000000000d8a68e n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x98a68e)#012
#4  0x0000000000d464fd n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x9464fd)#012#5  0x0000000000d5269d n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x95269d)#012#6  0x0000000000d52adb n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x952adb)#012#7  0x0000000000d90923 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x990923)#012#8  0x0000000000d93f56 n/a (/home/julian/.nvm/versions/n
ode/v16.16.0/bin/node + 0x993f56)#012#9  0x0000000000d45003 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x945003)#012#10 0x0000000000d452e3 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x9452e3)#012#11 0x00000000011fc655 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0xdfc655)#012#12 0x00000000011fe037 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0xdfe037)#012#13 0x00000000015f2
d39 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11f2d39)#012#14 0x00000000016888c5 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x12888c5)#012#15 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#16 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#17 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#18 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#19 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#20 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#21 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#22 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#23 0x00007f852a06f936 n/a (n/a + 0x0)#012#24 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#25 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#26 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#27 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#28 0x00007f852a04f433 n/a (n/a + 0x0)#012#29 0x00007f852a067834 n/a (n/a + 0x0)#012#30 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#31 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#32 0x00007f852a053f97 n/a (n/a + 0x0)#012#33 0x00007f852a051983 n/a (n/a + 0x0)#012#34 0x00007f852a04e7ee n/a (n/a + 0x0)#012#35 0x00007f852a04f29b n/a (n/a + 0x0)#012#36 0x00007f852a067834 n/a (n/a + 0x0)#012#37 0x00007f852a06efaa n/a (n/a + 0x0)#012#38 0x00000000015b72b0 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11b72b0)#012#39 0x00007f852a0508cc n/a (n/a + 0x0)#012#40 0x00007f852a04f29b n/a (n/a + 0x0)#012#41 0x00007f852a067834 n/a (n/a + 0x0)#012#42 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#43 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#44 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#45 0x00000000015857ea n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11857ea)#012#46 0x00007f852a072550 n/a (n/a + 0x0)#012#47 0x00000000015839f8 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11839f8)#012#48 0x0000000001583783 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1183783)#012#49 0x0000000000e250c8 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0xa250c8)#012#50 0x0000000000e25f1f n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0xa25f1f)#012#51 0x0000000000d15dc2 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x915dc2)#012#52 0x0000000000a43316 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x643316)#012#53 0x0000000000a54029 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x654029)#012#54 0x0000000000be74a8 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x7e74a8)#012#55 0x0000000000be9efa n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x7e9efa)#012#56 0x0000000000bf46c8 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x7f46c8)#012#57 0x0000000001571307 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1171307)#012#58 0x0000000001571b30 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1171b30)#012#59 0x0000000001577d14 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1177d14)#012#60 0x0000000001565f38 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1165f38)#012#61 0x0000000000a43dd5 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x643dd5)#012#62 0x0000000000b4ca06 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x74ca06)#012#63 0x0000000000ace5a2 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x6ce5a2)#012#012Stack trace of thread 179171:#012#0  0x00007f8538af646e epoll_wait (libc.so.6 + 0x11f46e)#012#1  0x0000000001577eb7 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1177eb7)#012#2  0x0000000001565f38 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1165f38)#012#3  0x0000000000b7c2ab n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x77c2ab)#012#4  0x00007f8538bd1609 start_thread (libpthread.so.0 + 0x8609)#012#5  0x00007f8538af6133 __clone (libc.so.6 + 0x11f133)#012#012Stack trace of thread 179173:#012#0  0x00007f8538bd8376 futex_wait_cancelable (libpthread.so.0 + 0xf376)#012#1  0x0000000001574489 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1174489)#012#2  0x0000000000b7716b n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x77716b)#012#3  0x00007f8538bd1609 start_thread (libpthread.so.0 + 0x8609)#012#4  0x00007f8538af6133 __clone (libc.so.6 + 0x11f133)#012#012Stack trace of thread 179175:#012#0  0x00007f8538bd8376 futex_wait_cancelable (libpthread.so.0 + 0xf376)#012#1  0x0000000001574489 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1174489)#012#2  0x0000000000b7716b n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x77716b)#012#3  0x00007f8538bd1609 start_thread (libpthread.so.0 + 0x8609)#012#4  0x00007f8538af6133 __clone (libc.so.6 + 0x11f133)#012#012Stack trace of thread 179176:#012#0  0x00007f8538bdb454 futex_abstimed_wait_cancelable (libpthread.so.0 + 0x12454)#012#1  0x00007f8538bdb548 __new_sem_wait_slow (libpthread.so.0 + 0x12548)#012#2  0x00000000015742c2 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x11742c2)#012#3  0x0000000000c15215 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x815215)#012#4  0x00007f8538bd1609 start_thread (libpthread.so.0 + 0x8609)#012#5  0x00007f8538af6133 __clone (libc.so.6 + 0x11f133)#012#012Stack trace of thread 179174:#012#0  0x00007f8538bd8376 futex_wait_cancelable (libpthread.so.0 + 0xf376)#012#1  0x0000000001574489 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1174489)#012#2  0x0000000000b7716b n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x77716b)#012#3  0x00007f8538bd1609 start_thread (libpthread.so.0 + 0x8609)#012#4  0x00007f8538af6133 __clone (libc.so.6 + 0x11f133)#012#012Stack trace of thread 179172:#012#0  0x00007f8538bd8376 futex_wait_cancelable (libpthread.so.0 + 0xf376)#012#1  0x0000000001574489 n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x1174489)#012#2  0x0000000000b7716b n/a (/home/julian/.nvm/versions/node/v16.16.0/bin/node + 0x77716b)#012#3  0x00007f8538bd1609 start_thread (libpthread.so.0 + 0x8609)#012#4  0x00007f8538af6133 __clone (libc.so.6 + 0x11f133)#012#012Stack trace of thread 179179:#012#0  

Jul 19 17:11:54 julian systemd-coredump[174735]: Process 174650 (node) of user 1000 dumped core.#012#012Stack trace of thread 174650:#012#0  0x00007fcd11a1ff84 _int_malloc (libc.so.6 + 0x97f84)#012#1  0x00007fcd11a22299 __GI___libc_malloc (libc.so.6 + 0x9a299)#012#2  0x00000000012599be n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xe599be)#012#3  0x0000000001265b85 n/a (/home/julian/.nvm/versions/node
/v16.13.0/bin/node + 0xe65b85)#012#4  0x0000000001265e15 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xe65e15)#012#5  0x00000000011db1ad n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xddb1ad)#012#6  0x00000000011dcafe n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xddcafe)#012#7  0x00000000011dec1c n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xddec1c)#012#8  0x000000000108b511
 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xc8b511)#012#9  0x00000000011f9253 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xdf9253)#012#10 0x00000000015e7879 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x11e7879)#012#11 0x0000000001679d9d n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x1279d9d)#012#12 0x000000000157a32a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x117a32a)#012#13 0x000000000157a32a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x117a32a)#012#14 0x00007fcd03079ad6 n/a (n/a + 0x0)#012#15 0x000000000157a32a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x117a32a)#012#16 0x00007fcd0308955e n/a (n/a + 0x0)#012#17 0x00007fcd030896de n/a (n/a + 0x0)#012#18 0x000000000157a32a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x117a32a)#012#19 0x00007fcd030753f3 n/a (n/a + 0x0)#012#20 0x00007fcd03086134 n/a (n/a + 0x0)#012#21 0x000000000157a32a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x117a32a)#012#22 0x000000000157a32a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x117a32a)#012#23 0x00007fcd0309f297 n/a (n/a + 0x0)#012#24 0x00007fcd030974c3 n/a (n/a + 0x0)#012#25 0x00007fcd030747ae n/a (n/a + 0x0)#012#26 0x00007fcd0307525b n/a (n/a + 0x0)#012#27 0x00007fcd03086134 n/a (n/a + 0x0)#012#28 0x00007fcd0309c26a n/a (n/a + 0x0)#012#29 0x00000000015abdf0 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x11abdf0)#012#30 0x00007fcd0305df2c n/a (n/a + 0x0)#012#31 0x00007fcd0307525b n/a (n/a + 0x0)#012#32 0x00007fcd03086134 n/a (n/a + 0x0)#012#33 0x00007fcd03077f18 n/a (n/a + 0x0)#012#34 0x00007fcd03084bbd n/a (n/a + 0x0)#012#35 0x00007fcd0305f1aa n/a (n/a + 0x0)#012#36 0x00007fcd030836ef n/a (n/a + 0x0)#012#37 0x00007fcd0304d330 n/a (n/a + 0x0)#012#38 0x0000000001578538 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x1178538)#012#39 0x00000000015782c3 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x11782c3)#012#40 0x0000000000e19208 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xa19208)#012#41 0x0000000000e19f4f n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0xa19f4f)#012#42 0x0000000000d09eb2 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x909eb2)#012#43 0x0000000000a3f546 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x63f546)#012#44 0x0000000000a50289 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x650289)#012#45 0x0000000000bde618 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x7de618)#012#46 0x0000000000be166a n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x7e166a)#012#47 0x0000000000beb9c8 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x7eb9c8)#012#48 0x0000000001565e47 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x1165e47)#012#49 0x0000000001566680 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x1166680)#012#50 0x000000000156c804 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x116c804)#012#51 0x000000000155acc8 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x115acc8)#012#52 0x0000000000a3ffe5 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x63ffe5)#012#53 0x0000000000b45056 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x745056)#012#54 0x0000000000ac67e2 n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x6c67e2)#012#55 0x00007fcd119ac083 __libc_start_main (libc.so.6 + 0x24083)#012#56 0x0000000000a3bfbc n/a (/home/julian/.nvm/versions/node/v16.13.0/bin/node + 0x63bfbc)
m4heshd commented 2 years ago

Hi @julianhille, I've done some tests and you're right. The issue is reproducible and it's intermittent. Take a look at these tests. Very inconsistent. And that's a HUGE problem. Intermittent issues are the worst because those are pretty much impossible to debug. Also way harder to do trial and error tests.

I'm currently on a very tight schedule and this needs a lot more debugging to be able to track down anything that might be causing the issue. I'll keep this issue as open for third-party help for the moment.

julianhille commented 2 years ago

I have a system at hand were this always happens. I could try to debug this and come back. I had similar issues with my CPP/node pdf extension and so got a bit of experience debugging things like that.

Thanks for the quick response and confirmation.

julianhille commented 2 years ago

Segmentation fault comes from sqlite3.c from sqlite3mcGetReservedWriteCipher. codec->m_hasWriter is a big negative number (which should not) and this ends up in an out of bounds when accessing: codecDescriptorTable[codec->m_writeCipherType-1].

What fixes it for me is do not use rekey for an empty in memory database. If one yses key it works totally fine.

If i fix the line to be

int reserved = (codec->m_hasWriteCipher == 1 && codec->m_writeCipher != NULL) ? codecDescriptorTable[codec->m_writeCipherType-1]->m_getReserved(codec->m_writeCipher) : -1;

(see check against == 1 as intended) the seg fault is gone BUT we still get an abort with

sqlite3BtreeSetPageSize: Assertion `nReserve>=0 && nReserve<=255' failed.

somehow the codec value breaks in sqlite3_rekey_v2

m4heshd commented 2 years ago

This is all great information. sqlite3_rekey_v2 is a SQLite3MultipleCiphers function. Would you be willing to test an in-memory DB via the SQLite3MultipleCiphers CLI on that same system you managed to debug from? That would help us clarify if the issue's actually in SQLite3MultipleCiphers and not when it's executed through NAN.

julianhille commented 2 years ago

Yes. Will get to it.

julianhille commented 2 years ago
➜  SQLite3MultipleCiphers git:(main) ✗ ./sqlite3shell ":memory:"   
SQLite version 3.39.2 2022-07-21 15:24:47 (SQLite3 Multiple Ciphers 1.4.7)
Enter ".help" for usage hints.
sqlite> ATTACH DATABASE ':memory:' AS aux1;
sqlite> PRAGMA rekey='password';
[1]    301894 segmentation fault (core dumped)  ./sqlite3shell ":memory:"

build locally and only rekey it.

utelle commented 2 years ago

As documented here transient (i.e. in-memory) databases and temporary databases will not be encrypted. Only file-based databases (and journals) can be encrypted,

That said, it is simply a misuse to try to encrypt an in-memory database.

Nevertheless, an application should certainly not crash, even in case of misuse of a feature. So, I will address this issue soon.

Regarding the error analysis:

Segmentation fault comes from sqlite3.c from sqlite3mcGetReservedWriteCipher. codec->m_hasWriter is a big negative number (which should not) and this ends up in an out of bounds when accessing: codecDescriptorTable[codec->m_writeCipherType-1].

The reason for this is that function sqlite3_rekey currently doesn't explicitly check for an in-memory database. Internally, the function tries to allocate a codec and link it to the associated database file (which does not exist for in-memory databases). Therefore, the codec is deleted (because usually the underlying vfs takes ownership of the codec structure). However, function sqlite3_rekey makes use of the codec after it has been deleted - and this leads to a crash, of course.

If i fix the line to be

int reserved = (codec->m_hasWriteCipher == 1 && codec->m_writeCipher != NULL) ? codecDescriptorTable[codec->m_writeCipherType-1]->m_getReserved(codec->m_writeCipher) : -1;

(see check against == 1 as intended) the seg fault is gone BUT we still get an abort with

This is not a fix, but only hides the real cause of the problem ...

sqlite3BtreeSetPageSize: Assertion `nReserve>=0 && nReserve<=255' failed.

... as this assert proves.

For the time being do not use "pragma key" or "pragma rekey" on an in-memory database - it isn't supported anyway.

julianhille commented 2 years ago

Thanks @utelle for the insights.

This is not a fix, but only hides the real cause of the problem ...

Yes you are right and it was not meant as a fix for the issue more a test to see that the segfault is really originating in that piece.

@m4heshd what we want to do with this outcome?

i don't see other possible todos. Checking for pragma rekey or key if the database is an in-memory would be to error prone, i guess.

utelle commented 2 years ago

Commit https://github.com/utelle/SQLite3MultipleCiphers/commit/e1b82c1f9d09ba9576aadfcca1b23d4e0fdd28fe should fix the problem.

Since this project uses the SQLite3 Multiple Ciphers amalgamation sources, you probably want to wait for the next release. This may take a day or two.

m4heshd commented 2 years ago

@julianhille Thank you for debugging and your findings. @utelle Much appreciated you chiming in and providing a solution right away.

add a bit more prominent documentation about that

This IMO is a very rare case and unlikely to happen again 🤔. Since the functionality is already documented in SQLite3MC and a proper error is being thrown now, I'll keep the bs3mc documentation simple as it is for now.

Just merged the latest release of SQLite3MC and added some tests too. Changes are available in the latest beta release (v7.6.3-beta.0). Closing the issue.

julianhille commented 2 years ago

This IMO is a very rare case and unlikely to happen again . Since the functionality is already documented in SQLite3MC and a proper error is being thrown now, I'll keep the bs3mc documentation simple as it is for now.

Not sure how likely/unlekliy that is, just wanted to say that i always use in-memory DBs for unit tests that is why i found this.