@ -0,0 +1,20 @@ | |||
#include <rangecheck.h> | |||
#include <safemult.h> | |||
/* 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); | |||
} | |||
@ -0,0 +1,13 @@ | |||
#include <rangecheck.h> | |||
#include <inttypes.h> | |||
/* 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); | |||
} | |||
@ -0,0 +1,13 @@ | |||
#include <rangecheck.h> | |||
#include <inttypes.h> | |||
/* 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); | |||
} | |||
@ -0,0 +1,12 @@ | |||
#include <rangecheck.h> | |||
/* 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<y && *x; ++x); | |||
return (x<y); | |||
} | |||
@ -0,0 +1,65 @@ | |||
#ifndef RANGECHECK_H | |||
#define RANGECHECK_H | |||
#include <stddef.h> | |||
/* 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)<len); /* this one is a little tricky. | |||
"ptr-c" checks the offset of ptr in the buffer is inside the buffer size. | |||
Now, ptr-c can underflow; say it is -1. When we cast it to size_t, it becomes | |||
a very large number. */ | |||
} | |||
/* Is this a plausible buffer? | |||
* Check whether buf is NULL, and whether buf+len overflows. | |||
* Does NOT check whether buf has a non-zero length! */ | |||
__static inline int range_validbuf(const void* buf,size_t len) { | |||
#if (__GNUC__ == 4) && (__GNUC_MINOR__ == 1) | |||
return (buf && (size_t)buf+len>=(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 |
@ -0,0 +1,90 @@ | |||
#include "rangecheck.h" | |||
#include <assert.h> | |||
#include <stdio.h> | |||
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; | |||
} |