Full_Name: Dmitry Dmitrienko Version: trunk, 0.9.18 OS: Linux, Windows URL: Submission from: (NULL) (100.36.101.84) In short: Reproduce: create a large database (1GB would be enough), run md_copy with -c argument. Expected result - compacted new database, Actual result - empty new database and crash in md_copy. In details: mdb_env_cwalk() defines cursor and does not initialize most of its fields, including mc_flags field. Then it calls mdb_page_get() procedure, which checks if (C_ORIG_RDONLY|C_WRITEMAP) flags are set in mc_flags. Since this field is not initialized, it may have arbitrary value. If these flags are not set, it starts checking txn's mt_u.dirty_list, as if it was a writing transaction, while in fact this is a walker, it is a reader, so it initialized mt_u.reader fields. This field is in the same memory location with dirty_list just because it's union. So mdb_page_get() actually reads lock file memory (it's where mt_u.reader points to). If the database is large enough, it leads to access to far beyond lock file memory mapped region and crashes md_copy. Proposed fix: mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags) ... + memset(&mc, 0, sizeof(mc)); mc.mc_snum = 1; mc.mc_top = 0; mc.mc_txn = my->mc_txn; + mc.mc.mc_flags = my->mc_txn->mt_flags & (C_ORIG_RDONLY|C_WRITEMAP);
ddmitrie@gmail.com wrote: > Full_Name: Dmitry Dmitrienko > Version: trunk, 0.9.18 > OS: Linux, Windows > URL: > Submission from: (NULL) (100.36.101.84) > Thanks, fixed now in git mdb.master > In short: > Reproduce: create a large database (1GB would be enough), run md_copy with -c > argument. Expected result - compacted new database, Actual result - empty new > database and crash in md_copy. > > In details: > mdb_env_cwalk() defines cursor and does not initialize most of its fields, > including mc_flags field. Then it calls mdb_page_get() procedure, which checks > if (C_ORIG_RDONLY|C_WRITEMAP) flags are set in mc_flags. Since this field is not > initialized, it may have arbitrary value. If these flags are not set, it starts > checking txn's mt_u.dirty_list, as if it was a writing transaction, while in > fact this is a walker, it is a reader, so it initialized mt_u.reader fields. > This field is in the same memory location with dirty_list just because it's > union. So mdb_page_get() actually reads lock file memory (it's where mt_u.reader > points to). If the database is large enough, it leads to access to far beyond > lock file memory mapped region and crashes md_copy. > > Proposed fix: > mdb_env_cwalk(mdb_copy *my, pgno_t *pg, int flags) > ... > + memset(&mc, 0, sizeof(mc)); > mc.mc_snum = 1; > mc.mc_top = 0; > mc.mc_txn = my->mc_txn; > + mc.mc.mc_flags = my->mc_txn->mt_flags & (C_ORIG_RDONLY|C_WRITEMAP); > > > > -- -- Howard Chu CTO, Symas Corp. http://www.symas.com Director, Highland Sun http://highlandsun.com/hyc/ Chief Architect, OpenLDAP http://www.openldap.org/project/
changed notes changed state Open to Test moved from Incoming to Software Bugs
fixed in mdb.master fixed in 0.9.19
changed notes changed state Test to Closed