Issue 8424 - mdb_env_cwalk() is broken, leading to crash if MDB_CP_COMPACT is set
Summary: mdb_env_cwalk() is broken, leading to crash if MDB_CP_COMPACT is set
Status: VERIFIED FIXED
Alias: None
Product: OpenLDAP
Classification: Unclassified
Component: slapd (show other issues)
Version: unspecified
Hardware: All All
: --- normal
Target Milestone: ---
Assignee: OpenLDAP project
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-05-14 15:34 UTC by ddmitrie@gmail.com
Modified: 2018-02-09 18:58 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description ddmitrie@gmail.com 2016-05-14 15:34:19 UTC
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);

Comment 1 Howard Chu 2016-05-14 23:46:30 UTC
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/

Comment 2 Howard Chu 2016-05-17 20:05:55 UTC
changed notes
changed state Open to Test
moved from Incoming to Software Bugs
Comment 3 OpenLDAP project 2018-02-09 18:58:10 UTC
fixed in mdb.master
fixed in 0.9.19
Comment 4 Quanah Gibson-Mount 2018-02-09 18:58:10 UTC
changed notes
changed state Test to Closed