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.
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
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