add rangecheck.h
parent
8ccd1cdd5f
commit
dbd9fe1ea5
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue