Fix crash on edit s, p, u key 'U' with negative argument
authorMarkus Armbruster <armbru@pond.sub.org>
Sun, 13 Jan 2013 09:32:54 +0000 (10:32 +0100)
committerMarkus Armbruster <armbru@pond.sub.org>
Wed, 8 May 2013 04:55:21 +0000 (06:55 +0200)
ef_ensure_space() oopses on negative ID, but succeeds anyway.  edit()
proceeds to ef_write(), which neglects to check for negative ID.
Since the ID isn't in the cache, it then passes a NULL old element to
callback prewrite(), which crashes.

Fix ef_ensure_space() to fail on negative ID.  Commit 5173f8cd
(v4.3.0) made it oops, but neglected to make it fail.

Fix ef_write() to oops and fail on negative ID.

ef_write() still passes NULL old element to prewrite() when the ID
isn't in the cache.  Doesn't actually happen, because we use
prewrite() callbacks only with fully cached tables.  Fragile.  Make
ef_open() fail when that assumption is violated.

src/lib/common/file.c

index 31f8f0fd777978cffb17923ae3dc7577d1c64f54..e985ce65de91af27e0c3f03a72c89ec5540d1e48 100644 (file)
@@ -29,7 +29,7 @@
  *  Known contributors to this file:
  *     Dave Pare, 1989
  *     Steve McClure, 2000
- *     Markus Armbruster, 2005-2012
+ *     Markus Armbruster, 2005-2013
  */
 
 #include <config.h>
@@ -85,6 +85,8 @@ ef_open(int type, int how)
     ep = &empfile[type];
     if (CANT_HAPPEN(!ep->file || ep->base != EF_BAD || ep->fd >= 0))
        return 0;
+    if (CANT_HAPPEN(ep->prewrite && !(how & EFF_MEM)))
+       return 0;               /* not implemented */
     oflags = O_RDWR;
     if (how & EFF_PRIVATE)
        oflags = O_RDONLY;
@@ -542,6 +544,8 @@ ef_write(int type, int id, void *from)
     ep = &empfile[type];
     if (CANT_HAPPEN((ep->flags & (EFF_MEM | EFF_PRIVATE)) == EFF_PRIVATE))
        return 0;
+    if (CANT_HAPPEN(id < 0))
+       return 0;
     if (CANT_HAPPEN(ep->nent >= 0 && id >= ep->nent))
        return 0;               /* beyond fixed size */
     new_seqno(ep, from);
@@ -966,9 +970,8 @@ ef_check(int type)
 int
 ef_ensure_space(int type, int id, int count)
 {
-    if (ef_check(type) < 0)
+    if (ef_check(type) < 0 || CANT_HAPPEN(id < 0))
        return 0;
-    CANT_HAPPEN(id < 0);
 
     while (id >= empfile[type].fids) {
        if (!ef_extend(type, count))