From dbd9fe1ea54ca39dc9e47c384c5c46b0ce64ce4f Mon Sep 17 00:00:00 2001 From: leitner Date: Mon, 17 Apr 2006 04:33:40 +0000 Subject: [PATCH] add rangecheck.h --- CHANGES | 1 + Makefile | 2 +- mult/range_arrayinbuf.c | 20 +++++++++ mult/range_str2inbuf.c | 13 ++++++ mult/range_str4inbuf.c | 13 ++++++ mult/range_strinbuf.c | 12 ++++++ rangecheck.h | 65 +++++++++++++++++++++++++++++ t.c | 4 +- test/range.c | 90 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 mult/range_arrayinbuf.c create mode 100644 mult/range_str2inbuf.c create mode 100644 mult/range_str4inbuf.c create mode 100644 mult/range_strinbuf.c create mode 100644 rangecheck.h create mode 100644 test/range.c diff --git a/CHANGES b/CHANGES index f08bfea..df7bd8c 100644 --- a/CHANGES +++ b/CHANGES @@ -10,6 +10,7 @@ implement Nikola's idea to remove limit number of strings in errmsg add taia_half add cdb + add rangecheck.h 0.24: fix scan_to_sa (Tim Lorenz) diff --git a/Makefile b/Makefile index e6b4799..6fb801a 100644 --- a/Makefile +++ b/Makefile @@ -585,7 +585,7 @@ dep libsocket havealloca.h INCLUDES=buffer.h byte.h fmt.h ip4.h ip6.h mmap.h scan.h socket.h str.h stralloc.h \ uint16.h uint32.h uint64.h open.h textcode.h tai.h taia.h dns.h iopause.h case.h \ openreadclose.h readclose.h ndelay.h array.h io.h safemult.h iob.h havealloca.h \ -errmsg.h cdb.h cdb_make.h +errmsg.h cdb.h cdb_make.h rangecheck.h install: libowfat.a install -d $(INCLUDEDIR) $(MAN3DIR) $(LIBDIR) diff --git a/mult/range_arrayinbuf.c b/mult/range_arrayinbuf.c new file mode 100644 index 0000000..2cf879b --- /dev/null +++ b/mult/range_arrayinbuf.c @@ -0,0 +1,20 @@ +#include +#include + +/* does an array of "elements" members of size "membersize" starting at + * "arraystart" lie inside buf1[0..len-1]? */ +int range_arrayinbuf(const void* buf1,size_t len, + const void* arraystart,size_t elements,size_t membersize) { + size_t alen; + if (sizeof(alen)==8) { + uint64 x; + if (!umult64(elements,membersize,&x)) return 0; + alen=x; + } else { + unsigned long long t=(unsigned long long)elements*membersize; + alen=t; + if (alen!=t) return 0; + } + return range_bufinbuf(buf1,len,arraystart,alen); +} + diff --git a/mult/range_str2inbuf.c b/mult/range_str2inbuf.c new file mode 100644 index 0000000..f206700 --- /dev/null +++ b/mult/range_str2inbuf.c @@ -0,0 +1,13 @@ +#include +#include + +/* does an UTF-16 string starting at "ptr" lie in buf[0..len-1]? */ +int range_str2inbuf(const void* buf,size_t len,const void* stringstart) { + const uint16_t* x; + const uint16_t* y; + if (!range_ptrinbuf(buf,len,x=stringstart)) return 0; + y=(const uint16_t*)((char*)x+len); + for (; x+1<=y && *x; ++x); + return (x+1<=y); +} + diff --git a/mult/range_str4inbuf.c b/mult/range_str4inbuf.c new file mode 100644 index 0000000..cb11587 --- /dev/null +++ b/mult/range_str4inbuf.c @@ -0,0 +1,13 @@ +#include +#include + +/* does an UTF-32 string starting at "ptr" lie in buf[0..len-1]? */ +int range_str4inbuf(const void* buf,size_t len,const void* stringstart) { + const uint32_t* x; + const uint32_t* y; + if (!range_ptrinbuf(buf,len,x=stringstart)) return 0; + y=(const uint32_t*)((char*)x+len); + for (; x+1<=y && *x; ++x); + return (x+1<=y); +} + diff --git a/mult/range_strinbuf.c b/mult/range_strinbuf.c new file mode 100644 index 0000000..f994f5d --- /dev/null +++ b/mult/range_strinbuf.c @@ -0,0 +1,12 @@ +#include + +/* does an ASCIIZ string starting at "ptr" lie in buf[0..len-1]? */ +int range_strinbuf(const void* buf,size_t len,const void* stringstart) { + const char* x; + const char* y; + if (!range_ptrinbuf(buf,len,x=stringstart)) return 0; + y=x+len; + for (; x + +/* return 0 for range error / overflow, 1 for ok */ + +#if defined(__GNUC__) && defined(__OPTIMIZE__) +#define __static extern +#else +#define __static static +#endif + +/* does ptr point to one of buf[0], buf[1], ... buf[len-1]? */ +__static inline int range_ptrinbuf(const void* buf,size_t len,const void* ptr) { + register const char* c=(const char*)buf; /* no pointer arithmetic on void* */ + return (c && /* is buf non-NULL? */ +#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 1) + ((size_t)c)+len>(size_t)c && /* gcc 4.1 miscompiles this test */ +#else + c+len>c && /* catch integer overflows and fail if buffer is 0 bytes long */ + /* because then ptr can't point _in_ the buffer */ +#endif + (size_t)((const char*)ptr-c)=(size_t)buf); /* gcc 4.1 miscompiles this test */ +#else + return (buf && (const char*)buf+len>=(const char*)buf); +#endif +} + +/* is buf2[0..len2-1] inside buf1[0..len-1]? */ +__static inline int range_bufinbuf(const void* buf1,size_t len1,const void* buf2,size_t len2) { + return range_validbuf(buf1,len1) && + range_validbuf(buf2,len2) && + buf1<=buf2 && + (ptrdiff_t)buf1+len1>=(ptrdiff_t)buf2+len2; +} + +/* does an array of "elements" members of size "membersize" starting at + * "arraystart" lie inside buf1[0..len-1]? */ +int range_arrayinbuf(const void* buf1,size_t len, + const void* arraystart,size_t elements,size_t membersize); + +/* does an ASCIIZ string starting at "ptr" lie in buf[0..len-1]? */ +int range_strinbuf(const void* buf,size_t len,const void* stringstart); + +/* does an UTF-16 string starting at "ptr" lie in buf[0..len-1]? */ +int range_str2inbuf(const void* buf,size_t len,const void* stringstart); + +/* does an UTF-32 string starting at "ptr" lie in buf[0..len-1]? */ +int range_str4inbuf(const void* buf,size_t len,const void* stringstart); + +#undef __static + +#endif diff --git a/t.c b/t.c index 2bf33a8..2b452d9 100644 --- a/t.c +++ b/t.c @@ -64,7 +64,7 @@ int main(int argc,char* argv[]) { #if 0 buffer_putmflush(buffer_1,"foo ","bar ","baz.\n"); #endif -#if 1 +#if 0 char* c="fnord"; int fd=open_read(c); errmsg_iam(argv[0]); @@ -318,7 +318,7 @@ int main(int argc,char* argv[]) { rdtscl(c); printf("%lu %lu\n",b-a,c-b); #endif -#if 0 +#if 1 unsigned long size; char* buf=mmap_read(argv[1],&size); if (buf) { diff --git a/test/range.c b/test/range.c new file mode 100644 index 0000000..972d19b --- /dev/null +++ b/test/range.c @@ -0,0 +1,90 @@ +#include "rangecheck.h" +#include +#include + +int main() { + char buf[1000]; + + /* does range_ptrinbuf check all the incoming pointer cases right? */ + assert(range_ptrinbuf(buf,sizeof(buf),0)==0); + assert(range_ptrinbuf(buf,sizeof(buf),buf-1)==0); + assert(range_ptrinbuf(buf,sizeof(buf),buf)==1); + assert(range_ptrinbuf(buf,sizeof(buf),buf+50)==1); + assert(range_ptrinbuf(buf,sizeof(buf),buf+sizeof(buf))==0); + + /* what if we give it an invalid buffer? */ + assert(range_ptrinbuf(0,sizeof(buf),0)==0); + assert(range_ptrinbuf(buf,(unsigned long)-1,buf+1)==0); + + /* see if range_validbuf works */ + assert(range_validbuf(buf,sizeof(buf))==1); + assert(range_validbuf(0,sizeof(buf))==0); + assert(range_validbuf(buf,(unsigned long)-1)==0); + + /* range_bufinbuf */ + assert(range_bufinbuf(buf,sizeof(buf),buf,sizeof(buf))==1); + assert(range_bufinbuf(buf,sizeof(buf),buf,sizeof(buf)+1)==0); + assert(range_bufinbuf(buf,sizeof(buf),buf-1,sizeof(buf))==0); + assert(range_bufinbuf(buf-1,sizeof(buf)+1,buf,sizeof(buf))==1); + assert(range_bufinbuf(buf-1,sizeof(buf)+2,buf,sizeof(buf))==1); + assert(range_bufinbuf(0,sizeof(buf),(void*)1,1)==0); + assert(range_bufinbuf(buf,(unsigned long)-1,buf,1)==0); + /* the quintessential integer overflow exploit scenario */ + assert(range_bufinbuf(buf,sizeof(buf),buf+10,(unsigned long)-5)==0); + assert(range_bufinbuf(buf,sizeof(buf),buf+10,sizeof(buf))==0); + assert(range_bufinbuf(buf,sizeof(buf),buf+10,sizeof(buf)-10)==1); + + /* range_arrayinbuf */ + assert(range_arrayinbuf(buf,sizeof(buf),buf,1,10)==1); + assert(range_arrayinbuf(buf,sizeof(buf),buf+sizeof(buf)-10,1,10)==1); + assert(range_arrayinbuf(buf,sizeof(buf),buf-1,1,10)==0); + assert(range_arrayinbuf(buf,sizeof(buf),buf+1,1,1000)==0); + assert(range_arrayinbuf(buf,sizeof(buf),buf-1,1,1002)==0); + /* now overflow the array parameters */ + assert(range_arrayinbuf(buf,sizeof(buf),buf+10,0x10000,0x10000)==0); + assert(range_arrayinbuf(buf,sizeof(buf),buf+10,0x80000000,2)==0); + assert(range_arrayinbuf(buf,sizeof(buf),buf+10,0xffffffff,1)==0); + + /* range_strinbuf */ + assert(range_strinbuf(buf,sizeof(buf),0)==0); + assert(range_strinbuf(buf,sizeof(buf),buf+sizeof(buf))==0); + { + char* x="fnord"; + assert(range_strinbuf(x,5,x)==0); + assert(range_strinbuf(x,6,x)==1); + assert(range_strinbuf(x,6,x+5)==1); + assert(range_strinbuf(x,6,x+6)==0); + } + + /* range_str2inbuf */ + assert(range_str2inbuf(buf,sizeof(buf),0)==0); + assert(range_str2inbuf(buf,sizeof(buf),buf+sizeof(buf))==0); + { + uint16_t y[6]; + int i; + for (i=0; i<7; ++i) y[i]="fnord"[i]; + assert(range_str2inbuf(y,5*2,y)==0); + assert(range_str2inbuf(y,5*2+1,y)==0); + assert(range_str2inbuf(y,sizeof(y),y)==1); + assert(range_str2inbuf(y,sizeof(y),y+5)==1); + assert(range_str2inbuf(y,sizeof(y),y+6)==0); + } + + /* range_str4inbuf */ + assert(range_str4inbuf(buf,sizeof(buf),0)==0); + assert(range_str4inbuf(buf,sizeof(buf),buf+sizeof(buf))==0); + { + uint32_t y[6]; + int i; + for (i=0; i<7; ++i) y[i]="fnord"[i]; + assert(range_str4inbuf(y,5*4,y)==0); + assert(range_str4inbuf(y,5*4+3,y)==0); + assert(range_str4inbuf(y,sizeof(y),y)==1); + assert(range_str4inbuf(y,sizeof(y),y+5)==1); + assert(range_str4inbuf(y,sizeof(y),y+6)==0); + } + + + puts("all tests ok"); + return 0; +}