[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#9097) lmdb: premature free of env->me_txn0



Full_Name: Christopher Zimmermann
Version: lmdb 0.9.24
OS: OpenBSD
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (85.212.180.240)


Hi,

I can reliably hit a Bus error on OpenBSD.
This is triggered by OpenBSDs malloc/free junking [1] and a use-after-free bug
in lmdb.

Steps to reproduce:
- begin a read/write transaction (getting env->me_txn0)
- fill the environment
  -> returns MDB_MAP_FULL
  -> sets txn->mt_flags |= MDB_TXN_ERROR; (This is also env->me_txn0 !)
  -> calls mdb_txn_abort
     -> calls mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE):
        mdb_txn_end tries not to free env->me_txn0:

        } else if (!F_ISSET(txn->mt_flags, MDB_TXN_FINISHED)) {
          [...]
          txn->mt_flags = MDB_TXN_FINISHED;
          if (!txn->mt_parent) {
            [...]
            mdb.c:3020    mode = 0;	/* txn == env->me_txn0, do not free() it */
            [...]
          }
          [...]
        }
	if (mode & MDB_END_FREE)
		free(txn);

        this prevents the free only for unfinished transactions.
        Unfinished transactions are now finished.
- abort the transaction (again) with mdb_abort()
  -> calls mdb_txn_end(txn, MDB_END_ABORT|MDB_END_SLOT|MDB_END_FREE):
     since the env->me_txn0 detection is skipped on MDB_TXN_FINISHED
transactions 
     the transaction is freed, the memory will get "junked".
- begin a read/write transaction (getting now invalid env->me_txn0)
  -> calls mdb_txn_renew0(env->me_txn0)
    	MDB_env *env = txn->mt_env; /* txn->mt_env is now invalid */
	MDB_txninfo *ti = env->me_txns; /* triggers bus error */

Please make the protection against freeing of me_txn0 more robust.

Thanks,
Christopher Zimmermann

[1] https://man.openbsd.org/malloc#j