bin/55448: dbm_nextkey() misbehaves after dbm_store() in dbm(3)
Robert Watson
rwatson at FreeBSD.org
Sun Aug 10 15:10:18 PDT 2003
>Number: 55448
>Category: bin
>Synopsis: dbm_nextkey() misbehaves after dbm_store() in dbm(3)
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sun Aug 10 15:10:16 PDT 2003
>Closed-Date:
>Last-Modified:
>Originator: Robert Watson
>Release: FreeBSD 4.8-STABLE i386
>Organization:
>Environment:
System: FreeBSD fledge.watson.org 4.8-STABLE FreeBSD 4.8-STABLE #4: Mon Aug 4 00:26:28 EDT 2003 robert at fledge.watson.org:/home/data/obj/home/data/fbsd-stable/src/sys/FLEDGE i386
>Description:
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.
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list