[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
(ITS#8777) [LMDB] Closing read cursor uses already freed transaction (MDB_VL32)
- To: openldap-its@OpenLDAP.org
- Subject: (ITS#8777) [LMDB] Closing read cursor uses already freed transaction (MDB_VL32)
- From: markus@greenrobot.de
- Date: Sun, 26 Nov 2017 12:01:03 +0000
- Auto-submitted: auto-generated (OpenLDAP-ITS)
Full_Name: Markus Junginger
Version: mdb.master
OS: Ubuntu
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (77.190.230.93)
Read cursors may outlive a transaction to be renewed with another. Thus, cursors
should be correctly closed even after their last transaction was aborted. But
they access the (already freed) transaction during closing when MDB_VL32 is used
(mdb.master branch).
ASan captures this like this:
==19722==ERROR: AddressSanitizer: heap-use-after-free on address 0x61100001b140
at pc 0x000000ea2387 bp 0x7ffd36e3cd20 sp 0x7ffd36e3cd18
READ of size 8 at 0x61100001b140 thread T0
#0 0xea2386 in mdb_cursor_unref mdb.c:2082:18
#1 0xec577b in mdb_cursor_close mdb.c:8538:3
0x61100001b140 is located 128 bytes inside of 250-byte region
[0x61100001b0c0,0x61100001b1ba)
freed by thread T0 here:
#0 0x74f840 in __interceptor_cfree.localalias.0 (...)
#1 0xe8ea98 in mdb_txn_end mdb.c:3380:3
#2 0xe8ecc5 in mdb_txn_abort mdb.c:3405:2
Possible fix for line mdb.c:2082 (applying what I found in mdb_cursor_close):
- if (mc->mc_txn->mt_rpages[0].mid) {
+ if ((mc->mc_flags & C_UNTRACK) && mc->mc_txn->mt_rpages[0].mid) {
Code to reproduce using MDB_VL32:
err = mdb_txn_begin(env, nullptr, MDB_RDONLY, &tx);
err = mdb_cursor_open(tx, dbi, &cursor);
// We must have data so get will set C_INITIALIZED
err = mdb_cursor_get(cursor, &key, &value, MDB_SET_KEY);
mdb_txn_abort(tx);
mdb_cursor_close(cursor); // <- still uses tx