code: plan9front

Download patch

ref: 99e2d549e86cbdf4c364a476b8eb008c8fcff6ec
parent: e8242918f4073dfff640da6b4a01287664ccb9f0
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Nov 25 14:08:21 EST 2023

libndb: do some extra robustness checks around hash files

- make sure the hash-file has non-zero hlen field (avoid division by zero)
- bound the chain walking by hlen, so we wont end up in a infinite loop
- always check for NDBNAP (nil) pointer while walking chain
- verify chain pointers (must be multiple of NDBPLEN and not overlap hashtable)

--- a/sys/src/libndb/ndbhash.c
+++ b/sys/src/libndb/ndbhash.c
@@ -29,13 +29,13 @@
  *  read a hash file with buffering
  */
 static uchar*
-hfread(Ndbhf *hf, long off, int len)
+hfread(Ndbhf *hf, ulong off, int len)
 {
 	if(off < hf->off || off + len > hf->off + hf->len){
-		if(seek(hf->fd, off, 0) < 0
-		|| (hf->len = read(hf->fd, hf->buf, sizeof(hf->buf))) < len){
-			hf->off = -1;
-			return 0;
+		if((hf->len = pread(hf->fd, hf->buf, sizeof(hf->buf), off)) < len){
+			hf->off = 0;
+			hf->len = 0;
+			return nil;
 		}
 		hf->off = off;
 	}
@@ -95,7 +95,7 @@
 		if(p != nil){
 			hf->dbmtime = NDBGETUL(p);
 			hf->hlen = NDBGETUL(p+NDBULLEN);
-			if(hf->dbmtime == db->mtime){
+			if(hf->hlen > 0 && hf->dbmtime == db->mtime){
 				hf->next = db->hf;
 				db->hf = hf;
 				return hf;
@@ -174,12 +174,11 @@
 	Ndbtuple *t;
 	Ndb *db;
 	uchar *p;
+	ulong nchain;
 
+	nchain = 0;
 	db = s->db;
-	if(s->ptr == NDBNAP)
-		goto nextfile;
-
-	for(;;){
+	for(;;) {
 		if(s->type == Dptr){
 			if(Bseek(&db->b, s->ptr, 0) < 0)
 				break;
@@ -203,7 +202,18 @@
 			ndbfree(t);
 		} else if(s->type == Cptr1){
 			if(s->ptr & NDBCHAIN){	/* hash chain continuation */
+				if(s->ptr == NDBNAP)
+					break;
+				/* chain in a loop? */
+				if(++nchain > s->hf->hlen)
+					break;
 				s->ptr &= ~NDBCHAIN;
+				/* must be multiple of NDBPLEN */
+				if(s->ptr % NDBPLEN)
+					break;
+				/* must not overlap hash table */
+				if(s->ptr / NDBPLEN < s->hf->hlen)
+					break;
 				p = hfread(s->hf, s->ptr+NDBHLEN, 2*NDBPLEN);
 				if(p == nil)
 					break;
@@ -222,10 +232,12 @@
 				ndbfree(t);
 				break;
 			}
+		} else {
+			/* shouldnt happen */
+			break;
 		}
 	}
 
-nextfile:
 	/* nothing left to search? */
 	s->ptr = NDBNAP;
 	if(db->next == nil)
--- a/sys/src/libndb/ndbhf.h
+++ b/sys/src/libndb/ndbhf.h
@@ -9,7 +9,7 @@
 	char	attr[Ndbalen];	/* attribute hashed */
 
 	uchar	buf[256];	/* hash file buffer */
-	long	off;		/* offset of first byte of buffer */
+	ulong	off;		/* offset of first byte of buffer */
 	int	len;		/* length of valid data in buffer */
 };