diff --git a/.gitattributes b/.gitattributes
index 3cb6410ac237805e3cc5bbe434cd95cc5673d167..d539d16943e7f7d170a3a5e3a0be50029e382a7c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,8 @@
 * text=auto !eol
 /Makefile.in -text
+buffrecv/Makefile.in -text
+buffrecv/br_callbacks.c -text
+buffrecv/cgc.s -text
 canaries/Makefile.in -text
 canaries/canaries_callbacks.c -text
 canaries/debug_canary_callbacks.c -text
diff --git a/buffrecv/Makefile.in b/buffrecv/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..2951b502824c067f08ad83782aa8fea8b57a53b9
--- /dev/null
+++ b/buffrecv/Makefile.in
@@ -0,0 +1,28 @@
+
+
+CC=@CC@
+CFLAGS=@CFLAGS@
+LIB=@LIB@
+AR=@AR@
+AS=@AS@
+ASFLAGS=@ASFLAGS@
+
+OBJS=br_callbacks.o cgc.o
+
+
+.SUFFIXES: .o .s .c
+
+.c.o:
+	$(CC) $(CFLAGS) $(INCLUDE) -D__$(ARCH) -c $<
+
+.s.o:
+	$(AS) $(ASFLAGS) $<
+
+
+all: 	$(OBJS)
+	$(AR) -r $(LIB) $(OBJS)
+
+clean:
+	rm *.o
+	
+
diff --git a/buffrecv/br_callbacks.c b/buffrecv/br_callbacks.c
new file mode 100644
index 0000000000000000000000000000000000000000..a2870b6bf2ff0fd3de54310046f4d89feee0e783
--- /dev/null
+++ b/buffrecv/br_callbacks.c
@@ -0,0 +1,226 @@
+#ifdef DEBUG
+
+#include "malloc.h"
+#include "itox.h"
+#include "strlen.h"
+#include "null.h"
+
+#define DEBUG_ADD
+#else
+
+typedef unsigned uintptr_t;
+#define NULL 0L
+
+#endif
+
+
+#ifdef DEBUG
+	#define print_str_debug print_str
+	#define print_int_debug print_int
+	#define assert(a) {if(!a) print_str("assert failure!"), cgc_terminate(254);}
+#else
+	#define print_str_debug(a) 
+	#define print_int_debug(a) 
+	#define assert(a)
+#endif
+
+
+#ifdef DEBUG
+#define write_fd 2
+void print_char(char c)
+{
+	write(write_fd,&c,1);
+}
+void print_str(char *s)
+{
+	write(write_fd,s,strlen(s));
+}
+void print_int(int x)
+{
+	char buf[100];
+	itox(x,buf);
+	write(write_fd,buf,strlen(buf));
+}
+#endif
+
+
+
+typedef struct
+{
+        int edi;
+        int esi;
+        int ebp;
+        int esp_dummy;
+        int ebx;
+        int edx;
+        int ecx; 
+        int eax;
+        int flags;
+} reg_values_t;
+
+/*
+deallocate(addr, length)
+int zipr_delayed_deallocate(unsigned int ret_pc, reg_values_t rv)
+{
+	void *addr=rv.ebx;
+	unsigned int length=rv.ecx;
+
+	static void* old_addr=0;
+	static unsigned int old_length=0;
+
+	cgc_deallocate(old_addr,old_length);
+
+	old_addr=addr;
+	old_length=length;
+	return 0;
+}
+
+global cgc_receive
+cgc_receive:
+
+orig_receive:
+	mov    eax,0x3
+	push   ebx
+	push   ecx
+	push   edx
+	push   esi
+	mov    ebx, [esp+0x14]
+	mov    ecx, [esp+0x18]
+	mov    edx, [esp+0x1c]
+	mov    esi, [esp+0x20]
+
+                         pushf
+                         pusha
+                         push retPC
+	int    0x80 ==>  NOP callback to buffered_receive()
+
+
+retPC:
+
+                         popa
+                         popf
+
+	pop    esi
+	pop    edx
+	pop    ecx
+	pop    ebx
+	ret    
+*/
+
+
+#define STORAGE_SIZE 128
+static char storage[STORAGE_SIZE];      
+static int cursor_pos = 0;
+static int bytes_buffered = 0;
+
+int buffered_receive(unsigned int ret_pc, reg_values_t rv)
+{
+	int  fd = rv.ebx;
+	char *buf = (char*) rv.ecx;
+	int  count = rv.edx;
+	int  *rx_bytes = (int*) rv.esi;
+
+#ifdef DEBUG
+	print_str("\ncount: ");
+	print_int(count);
+	print_str("\n*rx_bytes: ");
+	print_int((int)rx_bytes);
+#endif
+
+	int ret = cgc_receive(fd, buf, count, rx_bytes);
+
+#ifdef DEBUG
+	print_str("\nret: ");
+	print_int(ret);
+	print_str("\nfd: ");
+	print_int(fd);
+	print_str("\nbuf[0]: ");
+	print_char(buf[0]);
+	print_str("\ncount: ");
+	print_int(count);
+	print_str("\nrx_bytes: ");
+	print_int(*rx_bytes);
+#endif
+
+	rv.eax = ret; 
+	return ret;
+}
+
+#ifdef XXX
+/*
+static int receive2(int fd, char *buf, int count, int *rx_bytes) 
+{
+*/
+        int bytes_out = 0;
+
+        if (bytes_buffered == 0)
+        {   
+                cursor_pos = 0;
+
+                // handle the case where nothing's buffered
+                // and requested size > STORAGE_SIZE
+                if (count > STORAGE_SIZE) 
+                {   
+                        // call out to original receive()
+                        return cgc_receive(fd, buf, count, rx_bytes);
+                }   
+        }   
+        else
+        {   
+                // drain out buffer up to count bytes
+                while (bytes_buffered > 0 && bytes_out < count) {
+                        *buf++ = storage[cursor_pos++];
+			bytes_out++;
+			bytes_buffered--;
+		}
+
+                if (bytes_buffered == 0 || cursor_pos == STORAGE_SIZE) {
+                        cursor_pos = 0; 
+                }   
+
+                // if we're lucky, we've copied out all the requested data
+                count -= bytes_out;
+                if (count == 0)
+                {   
+                        if (rx_bytes)
+                                *rx_bytes = bytes_out;
+                        return 0;
+                }   
+        }   
+
+        // fill up the storage area again
+        int num_bytes;
+        int err_code = cgc_receive(fd, &storage[cursor_pos], STORAGE_SIZE - cursor_pos, &num_bytes);
+        if (err_code == 0)  
+        {   
+                int bytes_to_copy = count;
+                if (num_bytes < count) {
+                        bytes_to_copy = num_bytes;
+                }   
+
+                // copy out to user buffer
+                while (bytes_to_copy--) {
+                        *buf++ = storage[cursor_pos++];
+                }   
+ 
+                bytes_buffered = num_bytes - count; 
+                if (bytes_buffered >= 0)  
+                { 
+                        if (rx_bytes) 
+                                *rx_bytes = count + bytes_out; 
+                }  
+                else  
+                { 
+			// the user requested more bytes that we can hold in storage area... 
+			// return only the bytes we have
+                        // higher-level code has to be able to cope w/ the case 
+                        // where the OS returns fewer bytes than requested anyhow 
+                        if (rx_bytes) 
+                                *rx_bytes = num_bytes + bytes_out; 
+                        bytes_buffered = 0; 
+                } 
+        }  
+ 
+        return err_code; 
+}
+#endif
diff --git a/buffrecv/cgc.s b/buffrecv/cgc.s
new file mode 100644
index 0000000000000000000000000000000000000000..44d7645b802d07a1bf44811f9172c0c5b7ba6ce1
--- /dev/null
+++ b/buffrecv/cgc.s
@@ -0,0 +1,136 @@
+%ifdef CGC
+section .text
+
+
+BITS 32
+
+global cgc_terminate
+cgc_terminate:
+	mov    eax,0x1
+	push   ebx
+	mov    ebx, [esp+0x8]
+	int    0x80
+	pop    ebx
+	ret    
+
+global cgc_transmit
+cgc_transmit:
+	mov    eax,0x2
+	push   ebx
+	push   ecx
+	push   edx
+	push   esi
+	mov    ebx, [esp+0x14]
+	mov    ecx, [esp+0x18]
+	mov    edx, [esp+0x1c]
+	mov    esi, [esp+0x20]
+	int    0x80
+	pop    esi
+	pop    edx
+	pop    ecx
+	pop    ebx
+	ret    
+
+
+global cgc_receive
+cgc_receive:
+	mov    eax,0x3
+	push   ebx
+	push   ecx
+	push   edx
+	push   esi
+	mov    ebx, [esp+0x14]
+	mov    ecx, [esp+0x18]
+	mov    edx, [esp+0x1c]
+	mov    esi, [esp+0x20]
+	int    0x80
+	pop    esi
+	pop    edx
+	pop    ecx
+	pop    ebx
+	ret    
+
+global cgc_fdwait
+cgc_fdwait:
+	mov    eax,0x4
+	push   ebx
+	push   ecx
+	push   edx
+	push   esi
+	push   edi
+	mov    ebx, [esp+0x18]
+	mov    ecx, [esp+0x1c]
+	mov    edx, [esp+0x20]
+	mov    esi, [esp+0x24]
+	mov    edi, [esp+0x28]
+	int    0x80
+	pop    edi
+	pop    esi
+	pop    edx
+	pop    ecx
+	pop    ebx
+	ret    
+
+global cgc_allocate
+cgc_allocate:
+	mov    eax,0x5
+	push   ebx
+	push   ecx
+	push   edx
+	mov    ebx, [esp+0x10]
+	mov    ecx, [esp+0x14]
+	mov    edx, [esp+0x18]
+	int    0x80
+	pop    edx
+	pop    ecx
+	pop    ebx
+	ret    
+
+global cgc_deallocate
+cgc_deallocate:
+	mov    eax,0x6
+	push   ebx
+	push   ecx
+	mov    ebx, [esp+0xc]
+	mov    ecx, [esp+0x10]
+	int    0x80
+	pop    ecx
+	pop    ebx
+	ret    
+
+global cgc_random
+cgc_random:
+	mov    eax,0x7
+	push   ebx
+	push   ecx
+	push   edx
+	mov    ebx, [esp+0x10]
+	mov    ecx, [esp+0x14]
+	mov    edx, [esp+0x18]
+	int    0x80
+	pop    edx
+	pop    ecx
+	pop    ebx
+	ret    
+
+%else
+
+global syscall
+syscall:
+	push   edi
+	push   esi
+	push   ebx
+	mov    edi, [esp+0x24]
+	mov    esi, [esp+0x20]
+	mov    edx, [esp+0x1c]
+	mov    ecx, [esp+0x18]
+	mov    ebx, [esp+0x14]
+	mov    eax, [esp+0x10]
+	int    0x80
+	pop    ebx
+	pop    esi
+	pop    edi
+	ret    
+
+
+%endif