shithub: 5v

ref: f1f56304b68bf740f6f282ed270fee7e9f9596e1
dir: 5v/chk.c

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <bio.h>
#include <mach.h>
#include "dat.h"
#include "fns.h"


uvlong	okrange[32];
int	nokrange;

void
dumpmap(Segment *seg, u32int off, u32int len, char *fmt, ...)
{
	char buf[16*1024], *p, *e;
	va_list ap;
	int i, c;

	p = buf;
	e = p + sizeof(buf)-1;
	va_start(ap, fmt);
	p = vseprint(p, e, fmt, ap);
	va_end(ap);
	if(seg->shadow == nil){
		print("not tracing\n");
		return;
	}
	for(i = off/8; i <= (off+len+7)/8; i++){
		if(i >= off/8 && i+40 < off/8)
			c = '*';
		else
			c = ' ';
		if(i % 40 == 0)
			p = seprint(p, e, "\n[%04x]%c", seg->start+i*8, c);
		p = seprint(p, e, "%02ux", seg->shadow[i]);
	}
	*p++ = '\n';
	write(1, buf, p - buf);
}

static u32int
arg(int n)
{
	/* no locking necessary, since we're on the stack */
	return *(u32int*) vaddrnol(P->R[13] + 4 + 4 * n, 4, ARD);
}

static int
okfunc(u32int pc)
{
	uvlong *p;
	int i;

	for(i = 0, p = okrange; i < nokrange; i += 2, p += 2)
		if(p[0] <= pc && pc <= p[1])
			return 1;
	return 0;
}

void
checkaccess(Segment *seg, u32int off, u32int len, int chk)
{
	static int never;
	u32int end, bits;

	/*
	 * when we're within a malloc or free operation, we're looking at
	 * memory that we don't want to allow user programs to touch; skip
	 * the check here.
	 */
	if(P->hookpc != 0)
		return;
	end = off+len;
	if(end > seg->size){
		print("read past end of segment: %#x at %#x\n", seg->start+off, P->R[15] - 4);
		rendezvous(&never, nil);
		exits("bad access");
	}
	for(; off != end; off++){
		bits = seg->shadow[off>>2] >> (2*(off&3));
		if((bits&chk) != chk && !okfunc(P->R[15]-4)){
			if((bits&MARKALLOC) == 0)
				print("%d: access outside alloc: %#x at PC %#x\n",
					P->pid, seg->start+off, P->R[15] - 4);
			if((bits&MARKINIT) == 0)
				print("%d: invalid read: %#x at PC %#x\n", 
					P->pid, seg->start+off, P->R[15] - 4);
			rendezvous(&never, nil);
			exits("bad access");
		}
	}
}

void
markvalid(Segment *seg, u32int off, u32int len, int chk)
{
	u32int end;

	end = off+len;
	if(end > seg->size)
		end = seg->size;
//print("valid: %#x..%#x\n", seg->start+off, seg->start+end);
	for(; off != end; off++)
		seg->shadow[off>>2] |= chk<<(2*(off&3));
}

void
markinvalid(Segment *seg, u32int off, u32int len, int chk)
{
	u32int end;

	end = off+len;
	if(end > seg->size)
		end = seg->size;
//print("invalid: %#x..%#x\n", seg->start+off, seg->start+end);
	for(; off != end; off++)
		seg->shadow[off>>2] &= ~(chk<<(2*(off&3)));
}

void
hookmalloc(u32int *av)
{
	Segment *seg;
	uchar *p;

	p = vaddr(P->R[0], 0, 0, &seg);
	markvalid(seg, p - (uchar*)seg->data, av[0], MARKALLOC);
	segunlock(seg);
}


void
hookrealloc(u32int *av)
{
	uchar *oldp, *newp;
	u32int oldsz, newsz, sz;
	u32int oldoff, newoff;
	Segment *seg0, *seg1;

	seg0 = nil;
	seg1 = nil;
	oldp = nil;
	newp = nil;
	oldsz = 0;
	newsz = 0;
	oldoff = 0;
	newoff = 0;
	if(av[0] != 0){
		oldp = vaddr(av[0], 0, 0, &seg0);
		oldsz = av[1];
		oldoff = oldp - (uchar*)seg0->data;
	}
	if(P->R[0] != 0){
		newp = vaddr(P->R[0], 0, 0, &seg1);
		newsz = av[2];
		newoff = newp - (uchar*)seg1->data;
	}
	sz = (oldsz < newsz) ? oldsz : newsz;
	if(oldp != newp && oldsz > 0){
		memcpy(seg1->shadow+oldoff/4, seg0->shadow+newoff/4, (sz+3)/4);
		markinvalid(seg0, oldoff, oldsz, MARKALLOC|MARKINIT);
	}
	if(newsz > oldsz){
		markvalid(seg1, newoff+oldsz, newsz-oldsz, MARKALLOC);
		markinvalid(seg1, newoff+oldsz, newsz-oldsz, MARKINIT);
	}
	if(seg0 != nil)
		segunlock(seg0);

	if(seg1 != nil)
		segunlock(seg1);
}

void
hookfree(u32int *av)
{
	Segment *seg;
	uchar *p;

	p = vaddr(av[0], 0, 0, &seg);
	markinvalid(seg, p - (uchar*)seg->data, av[1], MARKALLOC|MARKINIT);
	segunlock(seg);
}