Bug 55448 - dbm(3): dbm_nextkey() misbehaves after dbm_store() in dbm(3)
Summary: dbm(3): dbm_nextkey() misbehaves after dbm_store() in dbm(3)
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 4.8-STABLE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-08-10 23:10 UTC by Robert Watson
Modified: 2017-12-31 22:35 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robert Watson freebsd_committer freebsd_triage 2003-08-10 23:10:16 UTC
dbm(3) provides a simply database API based on db(3).  It appears to be
possible to create database corruption through the use of dbm_nextkey()
and dbm_store() in the event that an entry in the database undergoes
a size change.  In particular, if you perform a dbm_fetch() on a key
returned by dbm_nextkey(), and then dbm_store() a larger value than
the data returned by dbm_fetch(), the next return from dbm_query() may
point into the newly updated value of the previous entry.

How-To-Repeat: 
We have a local DBM database with two types of entries: old entries that
have a data size of an int, and new entries, with a data size of two
ints.  During a sweep of the database, the software may decide to update
fields from the old entry type to the new entry.  Typically, this uses
the above-described sequence:

	struct ipdata {
		int	int1;
		int	int2;
	};

	key = dbm_firstkey(dbm);
	while (key.dptr != NULL) {
		data = dbm_fetch(dbm, key);
		switch (data.dsize) {
		case sizeof(int):
			/* fake up the new structure. */
			break;
		case sizeof(id):
			id = *(struct ipdata *)data.dptr;
			break;
		default:
			/* panic */
		}
		/* Perform data updates. */
		data.dptr = (void *)&id;
		data.dsize = sizeof(id);

		if (dbm_store(dbm, key, data, DBM_REPLACE) == -1)
			perror("dbm_store");

		key = dbm_nextkey(dbm);
	}

When an entry is upgraded, the next call to dbm_nextkey() returns the
second int in the new ipdata structure written, rather than the next
field, suggesting that the iterator isn't updated for write changes to
the database.
Comment 1 Robert Watson freebsd_committer freebsd_triage 2003-08-10 23:13:04 UTC
Just as a follow-up to justify the desire for this behavior to work: in
order to change the size of all fields in a database, working around this
bug currently seems to require rescanning the database O(n) each time by
restarting the search as soon as a record is resized, meaning that the
operation takes O(n^2) to complete.  It would be nice to avoid this.

Robert N M Watson             FreeBSD Core Team, TrustedBSD Projects
robert@fledge.watson.org      Network Associates Laboratories
Comment 2 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 07:59:46 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped