From 6eb1691529f172be126b4c69861a5657ecf725ed Mon Sep 17 00:00:00 2001
From: alex <alex>
Date: Fri, 6 Feb 2004 22:54:44 +0000
Subject: [PATCH] - use-after-free debugging tool against 2.4.24 - additional
 functionality: free routine checks for possible corruptions   after given
 size

---
 .../slab-use-after-free-debug-2.4.24.patch    | 748 ++++++++++++++++++
 1 file changed, 748 insertions(+)
 create mode 100644 lustre/kernel_patches/patches/slab-use-after-free-debug-2.4.24.patch

diff --git a/lustre/kernel_patches/patches/slab-use-after-free-debug-2.4.24.patch b/lustre/kernel_patches/patches/slab-use-after-free-debug-2.4.24.patch
new file mode 100644
index 0000000000..eb508d3f49
--- /dev/null
+++ b/lustre/kernel_patches/patches/slab-use-after-free-debug-2.4.24.patch
@@ -0,0 +1,748 @@
+%patch
+Index: linux-2.4.24/mm/slab.c
+===================================================================
+--- linux-2.4.24.orig/mm/slab.c	2004-02-06 11:15:22.000000000 +0300
++++ linux-2.4.24/mm/slab.c	2004-02-07 00:42:38.000000000 +0300
+@@ -97,6 +97,8 @@
+ #define	FORCED_DEBUG	0
+ #endif
+ 
++#include	<linux/vmalloc.h>
++
+ /*
+  * Parameters for kmem_cache_reap
+  */
+@@ -825,6 +827,12 @@
+ 	return cachep;
+ }
+ 
++#ifdef CONFIG_DEBUG_UAF
++void * uaf_alloc(kmem_cache_t *, int gfp_mask);
++int uaf_cache_free(kmem_cache_t *, void *addr);
++int uaf_free(void *addr);
++struct page *uaf_vaddr_to_page(void *obj);
++#endif
+ 
+ #if DEBUG
+ /*
+@@ -1342,6 +1350,20 @@
+ 	unsigned long save_flags;
+ 	void* objp;
+ 
++#ifdef CONFIG_DEBUG_UAF
++	/* try to use uaf-allocator first */
++	objp = uaf_alloc(cachep, flags);
++	if (objp) {
++		if (cachep->ctor) {
++			unsigned long ctor_flags;
++			ctor_flags = SLAB_CTOR_CONSTRUCTOR;
++			if (!(flags & __GFP_WAIT))
++				ctor_flags |= SLAB_CTOR_ATOMIC;
++			cachep->ctor(objp, cachep, ctor_flags);
++		}
++		return objp;
++	}
++#endif
+ 	kmem_cache_alloc_head(cachep, flags);
+ try_again:
+ 	local_irq_save(save_flags);
+@@ -1436,13 +1458,17 @@
+ 
+ 	if (cachep->flags & SLAB_RED_ZONE) {
+ 		objp -= BYTES_PER_WORD;
+-		if (xchg((unsigned long *)objp, RED_MAGIC1) != RED_MAGIC2)
++		if (xchg((unsigned long *)objp, RED_MAGIC1) != RED_MAGIC2) {
+ 			/* Either write before start, or a double free. */
++			printk("inconsistency in %s\n", cachep->name);
+ 			BUG();
++		}
+ 		if (xchg((unsigned long *)(objp+cachep->objsize -
+-				BYTES_PER_WORD), RED_MAGIC1) != RED_MAGIC2)
++				BYTES_PER_WORD), RED_MAGIC1) != RED_MAGIC2) {
+ 			/* Either write past end, or a double free. */
++			printk("inconsistency in %s\n", cachep->name);
+ 			BUG();
++		}
+ 	}
+ 	if (cachep->flags & SLAB_POISON)
+ 		kmem_poison_obj(cachep, objp);
+@@ -1578,6 +1604,10 @@
+ void kmem_cache_free (kmem_cache_t *cachep, void *objp)
+ {
+ 	unsigned long flags;
++#ifdef CONFIG_DEBUG_UAF
++	if (uaf_cache_free(cachep, objp))
++		return;
++#endif
+ #if DEBUG
+ 	CHECK_PAGE(virt_to_page(objp));
+ 	if (cachep != GET_PAGE_CACHE(virt_to_page(objp)))
+@@ -1603,6 +1633,10 @@
+ 
+ 	if (!objp)
+ 		return;
++#ifdef CONFIG_DEBUG_UAF
++	if (uaf_free((void *) objp))
++		return;
++#endif
+ 	local_irq_save(flags);
+ 	CHECK_PAGE(virt_to_page(objp));
+ 	c = GET_PAGE_CACHE(virt_to_page(objp));
+@@ -2078,3 +2112,471 @@
+ #endif
+ }
+ #endif
++
++
++
++#ifdef CONFIG_DEBUG_UAF
++
++#define MAX_UAF_OBJ_SIZE	8	/* in pages */
++#define UAF_ASSERT(xxx)		if (!(xxx)) BUG();
++#define UAF_DEBUG__
++#ifdef UAF_DEBUG
++#define uaf_printk(fmt,a...)	printk(fmt, ##a)
++#else
++#define uaf_printk(a,...)	
++#endif
++
++struct uaf_stats {
++	atomic_t uaf_allocated;
++	atomic_t uaf_allocations;
++	atomic_t uaf_failed;
++};
++
++static int uaf_max = 32768;
++static void *uaf_bitmap = NULL;
++static spinlock_t uaf_lock;
++static int uaf_last_found = 0;
++static int uaf_used = 0;
++static struct vm_struct *uaf_area = NULL;
++static struct uaf_stats uaf_stats[MAX_UAF_OBJ_SIZE + 1];
++
++static int __init uaf_setup(char *str)
++{
++        uaf_max = simple_strtoul(str, NULL, 0);
++        return 1;
++}
++
++__setup("uaf=", uaf_setup);
++
++
++void uaf_init(void)
++{
++	int size;
++
++	printk("UAF: total vmalloc-space - %lu\n",
++			VMALLOC_END - VMALLOC_START);
++
++	uaf_area = get_vm_area(PAGE_SIZE * uaf_max, VM_ALLOC);
++	if (!uaf_area) {
++		printk(KERN_ALERT "UAF: can't reserve %lu bytes in KVA\n",
++				PAGE_SIZE * uaf_max);
++		return;
++	}
++	
++	printk("UAF: reserved %lu bytes in KVA at 0x%p\n",
++			PAGE_SIZE * uaf_max, uaf_area->addr);
++
++	/* how many bytes we need to track space usage? */
++	size = uaf_max / 8 + 8;
++
++	uaf_bitmap = vmalloc(size);
++	if (!uaf_bitmap) {
++		printk(KERN_ALERT
++			"UAF: can't allocate %d bytes for bitmap\n", size);
++		return;
++	}
++	memset(uaf_bitmap, 0, size);
++	spin_lock_init(&uaf_lock);
++	memset(uaf_stats, 0, sizeof(uaf_stats));
++
++	printk("UAF: allocated %d for bitmap\n", size);
++}
++
++static int uaf_find(int len)
++{
++	int new_last_found = -1;
++	int loop = 0;
++	int i, j;
++
++	j = uaf_last_found;
++
++	do {
++		i = find_next_zero_bit(uaf_bitmap, uaf_max, j);
++		if (i >= uaf_max) {
++			/* repeat from 0 */
++			if (++loop > 1) {
++				/* this is 2nd loop and it's useless */
++				return -1;
++			}
++
++			i = find_next_zero_bit(uaf_bitmap, uaf_max, 0);
++			if (i >= uaf_max)
++				return -1;
++
++			/* save found num for subsequent searches */
++			if (new_last_found == -1)
++				new_last_found = uaf_last_found = i;
++			UAF_ASSERT(new_last_found < uaf_max);
++		}
++
++		/*
++		 * OK. found first zero bit.
++		 * now, try to find requested cont. zero-space
++		 */
++
++		/* FIXME: implmement multipage allocation! */
++		break;
++
++		/*
++		j = find_next_bit(uaf_bitmap, uaf_max, i);
++		if (++loop2 > 10000) {
++			printk("ALERT: loop2=%d\n", loop2);
++			return -1;
++		}
++		*/
++	} while (j - i < len);
++
++	/* found! */
++	if (new_last_found == -1)
++		uaf_last_found = i + 1;
++	if (uaf_last_found >= uaf_max)
++		uaf_last_found = 0;
++	return i;
++}
++
++extern int __vmalloc_area_pages (unsigned long address, unsigned long size,
++					int gfp_mask, pgprot_t prot,
++					struct page ***pages);
++void * uaf_alloc(kmem_cache_t *cachep, int gfp_mask)
++{
++	struct page *ptrs[MAX_UAF_OBJ_SIZE];
++	int size = cachep->objsize;
++	struct page **pages;
++	unsigned long flags;
++	unsigned long addr;
++	int i, j, err = -2000;
++
++	if (uaf_bitmap == NULL)
++		return NULL;
++
++	if (!(cachep->flags & SLAB_USE_UAF))
++		return NULL;
++
++	pages = (struct page **) ptrs;
++	size = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
++	/* FIXME: implement multipage allocation! */
++	if (size > 1)
++		return NULL;
++	if (size > MAX_UAF_OBJ_SIZE) {
++		printk(KERN_ALERT "size is too big: %d\n", size);
++		return NULL;
++	}
++
++	if (uaf_used == uaf_max) {
++		uaf_printk("UAF: space exhausted!\n");
++		atomic_inc(&uaf_stats[size].uaf_failed);
++		return NULL;
++	}
++
++
++	spin_lock_irqsave(&uaf_lock, flags);
++	i = uaf_find(size);
++	if (i < 0) {
++		spin_unlock_irqrestore(&uaf_lock, flags);
++		atomic_inc(&uaf_stats[size].uaf_failed);
++		return NULL;
++	}
++	for (j = 0; j < size; j++) {
++		UAF_ASSERT(!test_bit(i + j, uaf_bitmap));
++		set_bit(i + j, uaf_bitmap);
++		uaf_used++;
++	}
++	spin_unlock_irqrestore(&uaf_lock, flags);
++
++	addr = ((unsigned long) uaf_area->addr) + (PAGE_SIZE * i);
++	uaf_printk("UAF: found %d/%d, base 0x%p, map at 0x%lx: ", i,
++			size, uaf_area->addr, addr);
++
++	/* OK. we've found free space, let's allocate pages */
++	memset(pages, 0, sizeof(struct page *) * MAX_UAF_OBJ_SIZE);
++	for (j = 0; j < size; j++) {
++		pages[j] = alloc_page(gfp_mask);
++		if (pages[j] == NULL)
++			goto nomem;
++		uaf_printk("0x%p ", pages[j]);
++	}
++
++	/* time to map just allocated pages */
++	err = __vmalloc_area_pages(addr, PAGE_SIZE * size, gfp_mask,
++					PAGE_KERNEL, &pages);
++	pages = (struct page **) ptrs;
++	if (err == 0) {
++		/* put slab cache pointer in first page */
++		ptrs[0]->list.next = (void *) cachep;
++		uaf_printk(" -> 0x%lx\n", addr);
++		atomic_inc(&uaf_stats[size].uaf_allocated);
++		atomic_inc(&uaf_stats[size].uaf_allocations);
++		if (!in_interrupt() && !in_softirq())
++			flush_tlb_all();
++		else
++			local_flush_tlb();
++		size = cachep->objsize;
++		if (size < PAGE_SIZE)
++			memset((char *) addr + size, 0xa7, PAGE_SIZE - size);
++		return (void *) addr;
++	}
++
++nomem:
++	printk(KERN_ALERT "can't map pages: %d\n", err);
++	for (j = 0; j < size; j++)
++		if (pages[j])
++			__free_page(pages[j]);
++
++	/* can't find free pages */
++	spin_lock_irqsave(&uaf_lock, flags);
++	for (j = 0; j < size; j++) {
++		clear_bit(i + j, uaf_bitmap);
++		uaf_used--;
++	}
++	spin_unlock_irqrestore(&uaf_lock, flags);
++	atomic_inc(&uaf_stats[size].uaf_failed);
++
++	return NULL;
++}
++
++extern void free_area_pmd(pgd_t *dir, unsigned long address,
++				  unsigned long size);
++static void uaf_unmap(unsigned long address, unsigned long size)
++{
++	unsigned long end = (address + size);
++	pgd_t *dir;
++
++	dir = pgd_offset_k(address);
++	flush_cache_all();
++	do {
++		free_area_pmd(dir, address, end - address);
++		address = (address + PGDIR_SIZE) & PGDIR_MASK;
++		dir++;
++	} while (address && (address < end));
++
++	/*
++	 * we must not call smp_call_function() with interrtups disabled
++	 * otherwise we can get into deadlock
++	 */
++	if (!in_interrupt() && !in_softirq())
++		flush_tlb_all();
++	else
++		local_flush_tlb();
++}
++
++/*
++ * returns 1 if free was successfull
++ */
++int uaf_cache_free(kmem_cache_t *cachep, void *addr)
++{
++	struct page *pages[MAX_UAF_OBJ_SIZE];
++	int size = cachep->objsize;
++	unsigned long flags;
++	int i, j;
++
++	uaf_printk("UAF: to free 0x%p/%d\n", addr, size);
++
++	size = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
++	if (size > MAX_UAF_OBJ_SIZE)
++		return 0;
++
++	if (uaf_bitmap == NULL)
++		return 0;
++
++	/* first, check is address is in UAF space */
++	if ((unsigned) addr < (unsigned) uaf_area->addr ||
++		(unsigned) addr >= (unsigned) uaf_area->addr + uaf_area->size)
++		return 0;
++
++	if (cachep->objsize < PAGE_SIZE) {
++		unsigned char *a = (void *) addr;
++		for (i = 0; i < PAGE_SIZE - cachep->objsize; i++)
++			if (a[cachep->objsize + i] != 0xa7) {
++				printk("corruption(0x%x) at %u in %s/0x%p\n",
++					(unsigned) a[cachep->objsize + i],
++					cachep->objsize + i, cachep->name, addr);
++				BUG();
++			}
++	}
++	UAF_ASSERT(((unsigned long) addr & ~PAGE_MASK) == 0UL);
++	
++	/* calculate placement in bitmap */
++	i = (unsigned) addr - (unsigned) uaf_area->addr;
++	UAF_ASSERT(i >= 0);
++	i = i / PAGE_SIZE;
++
++	/* collect all the pages */
++	uaf_printk("free/unmap %d pages: ", size);
++	/* NOTE: we need not page_table_lock here. bits in bitmap
++	 * protect those pte's from to be reused */
++	for (j = 0; j < size; j++) {
++		unsigned long address;
++		address = ((unsigned long) addr) + (PAGE_SIZE * j);
++		pages[j] = vmalloc_to_page((void *) address);
++		uaf_printk("0x%lx->0x%p ", address, pages[j]);
++	}
++	uaf_printk("\n");
++
++	uaf_unmap((unsigned long) addr, PAGE_SIZE * size);
++	/* free all the pages */
++	for (j = 0; j < size; j++)
++		__free_page(pages[j]);
++
++	spin_lock_irqsave(&uaf_lock, flags);
++	for (j = 0; j < size; j++) {
++		/* now check is correspondend bit set */
++		UAF_ASSERT(i+j >= 0 && i+j < uaf_max);
++		UAF_ASSERT(test_bit(i+j, uaf_bitmap));
++		
++		/* now free space in UAF */
++		clear_bit(i+j, uaf_bitmap);
++		uaf_used--;
++	}
++	spin_unlock_irqrestore(&uaf_lock, flags);
++
++	atomic_dec(&uaf_stats[size].uaf_allocated);
++	
++	uaf_printk("UAF: freed %d/%d at 0x%p\n", i, size, addr);
++	//printk("UAF: freed %d/%d at 0x%p\n", i, size, addr);
++
++	return 1;
++}
++
++struct page *uaf_vaddr_to_page(void *obj)
++{
++	if (uaf_bitmap == NULL)
++		return NULL;
++
++	/* first, check is address is in UAF space */
++	if ((unsigned) obj < (unsigned) uaf_area->addr ||
++		(unsigned) obj >= (unsigned) uaf_area->addr + uaf_area->size)
++		return NULL;
++	
++	return vmalloc_to_page(obj);
++}
++
++int uaf_free(void *obj)
++{
++	struct page *page = uaf_vaddr_to_page((void *) obj);
++	kmem_cache_t *c;
++
++	if (!page)
++		return 0;
++
++	c = GET_PAGE_CACHE(page);
++	return uaf_cache_free(c, (void *) obj);
++}
++
++int uaf_is_allocated(void *obj)
++{
++	unsigned long addr = (unsigned long) obj;
++	int i;
++
++	if (uaf_bitmap == NULL)
++		return 0;
++
++	addr &= PAGE_MASK;
++	/* first, check is address is in UAF space */
++	if (addr < (unsigned long) uaf_area->addr ||
++			addr >= (unsigned long) uaf_area->addr + uaf_area->size)
++		return 0;
++
++	/* calculate placement in bitmap */
++	i = (unsigned) addr - (unsigned) uaf_area->addr;
++	i = i / PAGE_SIZE;
++	return test_bit(i, uaf_bitmap);
++}
++
++static void *uaf_s_start(struct seq_file *m, loff_t *pos)
++{
++	loff_t n = *pos;
++
++	if (!n)
++		seq_printf(m, "size(pgs) allocated failed allocations. "
++				"%d reserved, %d in use, %d last\n",
++				uaf_max, uaf_used, uaf_last_found);
++	else if (n > MAX_UAF_OBJ_SIZE)
++		return NULL;
++
++	*pos = 1;
++	return (void *) 1;
++}
++
++static void *uaf_s_next(struct seq_file *m, void *p, loff_t *pos)
++{
++	unsigned long n = *pos;
++	++*pos;
++	if (n + 1 > MAX_UAF_OBJ_SIZE)
++		return NULL;
++	return (void *) (n + 1);
++}
++
++static void uaf_s_stop(struct seq_file *m, void *p)
++{
++}
++
++static int uaf_s_show(struct seq_file *m, void *p)
++{
++	int n = (int) p;
++
++	if (n > MAX_UAF_OBJ_SIZE)
++		return 0;
++	seq_printf(m, "%d  %d  %d %d\n", n, 
++			atomic_read(&uaf_stats[n].uaf_allocated),
++			atomic_read(&uaf_stats[n].uaf_failed),
++			atomic_read(&uaf_stats[n].uaf_allocations));
++	return 0;
++}
++
++struct seq_operations uafinfo_op = {
++	.start	= uaf_s_start,
++	.next	= uaf_s_next,
++	.stop	= uaf_s_stop,
++	.show	= uaf_s_show,
++};
++
++ssize_t uafinfo_write(struct file *file, const char *buffer,
++				size_t count, loff_t *ppos)
++{
++	char kbuf[MAX_SLABINFO_WRITE+1], *tmp;
++	char *key, *name;
++	int res;
++	struct list_head *p;
++	
++	if (count > MAX_SLABINFO_WRITE)
++		return -EINVAL;
++	if (copy_from_user(&kbuf, buffer, count))
++		return -EFAULT;
++	kbuf[MAX_SLABINFO_WRITE] = '\0'; 
++
++	tmp = kbuf;
++	key = strsep(&tmp, " \t\n");
++	if (!key)
++		return -EINVAL;
++	if (!strcmp(key, "on"))
++		res = 1;
++	else if (!strcmp(key, "off"))
++		res = 0;
++	else
++		return -EINVAL;
++
++	name = strsep(&tmp, " \t\n");
++	if (!name)
++		return -EINVAL;
++
++	/* Find the cache in the chain of caches. */
++	down(&cache_chain_sem);
++	list_for_each(p,&cache_chain) {
++		kmem_cache_t *cachep = list_entry(p, kmem_cache_t, next);
++
++		if (!strcmp(cachep->name, name)) {
++			if (res) {
++				printk("UAF: use on %s\n", cachep->name);
++				cachep->flags |= SLAB_USE_UAF;
++			} else {
++				printk("UAF: dont use on %s\n", cachep->name);
++				cachep->flags &= ~SLAB_USE_UAF;
++			}
++			break;
++		}
++	}
++	up(&cache_chain_sem);
++	return count;
++}
++#endif
++
+Index: linux-2.4.24/mm/vmalloc.c
+===================================================================
+--- linux-2.4.24.orig/mm/vmalloc.c	2004-01-10 17:05:20.000000000 +0300
++++ linux-2.4.24/mm/vmalloc.c	2004-02-06 11:17:09.000000000 +0300
+@@ -53,7 +53,7 @@
+ 	} while (address < end);
+ }
+ 
+-static inline void free_area_pmd(pgd_t * dir, unsigned long address, unsigned long size)
++void free_area_pmd(pgd_t * dir, unsigned long address, unsigned long size)
+ {
+ 	pmd_t * pmd;
+ 	unsigned long end;
+@@ -152,7 +152,7 @@
+ 	return 0;
+ }
+ 
+-static inline int __vmalloc_area_pages (unsigned long address,
++int __vmalloc_area_pages (unsigned long address,
+ 					unsigned long size,
+ 					int gfp_mask,
+ 					pgprot_t prot,
+Index: linux-2.4.24/init/main.c
+===================================================================
+--- linux-2.4.24.orig/init/main.c	2004-01-10 17:05:59.000000000 +0300
++++ linux-2.4.24/init/main.c	2004-02-06 11:17:43.000000000 +0300
+@@ -437,6 +437,9 @@
+ #if defined(CONFIG_SYSVIPC)
+ 	ipc_init();
+ #endif
++#ifdef CONFIG_DEBUG_UAF
++	uaf_init();
++#endif
+ 	rest_init();
+ }
+ 
+Index: linux-2.4.24/fs/proc/proc_misc.c
+===================================================================
+--- linux-2.4.24.orig/fs/proc/proc_misc.c	2004-01-10 17:05:55.000000000 +0300
++++ linux-2.4.24/fs/proc/proc_misc.c	2004-02-06 11:35:27.000000000 +0300
+@@ -303,6 +303,22 @@
+ 	release:	seq_release,
+ };
+ 
++#ifdef CONFIG_DEBUG_UAF
++extern struct seq_operations uafinfo_op;
++extern ssize_t uafinfo_write(struct file *, const char *, size_t, loff_t *);
++static int uafinfo_open(struct inode *inode, struct file *file)
++{
++	return seq_open(file, &uafinfo_op);
++}
++static struct file_operations proc_uafinfo_operations = {
++	.open		= uafinfo_open,
++	.read		= seq_read,
++	.write		= uafinfo_write,
++	.llseek		= seq_lseek,
++	.release	= seq_release,
++};
++#endif
++
+ static int kstat_read_proc(char *page, char **start, off_t off,
+ 				 int count, int *eof, void *data)
+ {
+@@ -640,6 +656,9 @@
+ 	create_seq_entry("iomem", 0, &proc_iomem_operations);
+ 	create_seq_entry("partitions", 0, &proc_partitions_operations);
+ 	create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
++#ifdef CONFIG_DEBUG_UAF
++	create_seq_entry("uafinfo",S_IWUSR|S_IRUGO,&proc_uafinfo_operations);
++#endif
+ #ifdef CONFIG_MODULES
+ 	create_seq_entry("ksyms", 0, &proc_ksyms_operations);
+ #endif
+Index: linux-2.4.24/include/linux/slab.h
+===================================================================
+--- linux-2.4.24.orig/include/linux/slab.h	2004-01-29 15:01:10.000000000 +0300
++++ linux-2.4.24/include/linux/slab.h	2004-02-06 11:18:26.000000000 +0300
+@@ -40,6 +40,7 @@
+ #define	SLAB_HWCACHE_ALIGN	0x00002000UL	/* align objs on a h/w cache lines */
+ #define SLAB_CACHE_DMA		0x00004000UL	/* use GFP_DMA memory */
+ #define SLAB_MUST_HWCACHE_ALIGN	0x00008000UL	/* force alignment */
++#define SLAB_USE_UAF		0x00040000UL	/* use UAF allocator */
+ 
+ /* flags passed to a constructor func */
+ #define	SLAB_CTOR_CONSTRUCTOR	0x001UL		/* if not set, then deconstructor */
+Index: linux-2.4.24/include/asm-i386/io.h
+===================================================================
+--- linux-2.4.24.orig/include/asm-i386/io.h	2004-01-29 15:01:10.000000000 +0300
++++ linux-2.4.24/include/asm-i386/io.h	2004-02-06 11:18:26.000000000 +0300
+@@ -75,6 +75,16 @@
+  
+ static inline unsigned long virt_to_phys(volatile void * address)
+ {
++#ifdef CONFIG_DEBUG_UAF
++	unsigned long addr = (unsigned long) address;
++	if (vmlist && addr >= VMALLOC_START && addr < VMALLOC_END) {
++		struct page *page = vmalloc_to_page((void *) address);
++		if (page) {
++			unsigned long offset = addr & ~PAGE_MASK;
++			address = page_address(page) + offset;
++		}
++	}
++#endif
+ 	return __pa(address);
+ }
+ 
+Index: linux-2.4.24/include/asm-i386/page.h
+===================================================================
+--- linux-2.4.24.orig/include/asm-i386/page.h	2004-01-14 02:58:46.000000000 +0300
++++ linux-2.4.24/include/asm-i386/page.h	2004-02-06 11:17:09.000000000 +0300
+@@ -131,9 +131,49 @@
+ #define VMALLOC_RESERVE		((unsigned long)__VMALLOC_RESERVE)
+ #define __MAXMEM		(-__PAGE_OFFSET-__VMALLOC_RESERVE)
+ #define MAXMEM			((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
++
++#ifndef CONFIG_DEBUG_UAF
+ #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
+ #define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
+ #define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
++#else
++#define __pa(x)		({							\
++				unsigned long __pn, __fr;			\
++				__pn = (unsigned long)(x)-PAGE_OFFSET;		\
++				__fr = __pn >> PAGE_SHIFT;			\
++				if (jiffies > HZ*3 && __fr >= max_mapnr) {	\
++					printk("invalid arg __pa(0x%x)"		\
++						" at %s:%d\n", (unsigned) (x),	\
++						__FILE__, __LINE__);		\
++					dump_stack();				\
++				}						\
++				__pn;						\
++			})
++
++#define __va(x)		({							\
++				unsigned long __pn;				\
++				__pn = (unsigned long) (x) >> PAGE_SHIFT;	\
++				if (jiffies > HZ*3 && __pn >= max_mapnr) {	\
++					printk("invalid arg __va(0x%x)"		\
++						" at %s:%d\n", (unsigned) (x),	\
++						__FILE__, __LINE__);		\
++					dump_stack();				\
++				}						\
++				((void *)((unsigned long)(x) + PAGE_OFFSET));	\
++			})
++
++#define virt_to_page(ka) ({							\
++				struct page *_p;				\
++				if ((unsigned long)(ka) >= VMALLOC_START) {	\
++					_p = vmalloc_to_page((void *)(ka));	\
++					BUG_ON(!_p);				\
++				} else 						\
++					_p = mem_map+(__pa(ka) >> PAGE_SHIFT);	\
++				(_p);						\
++			})
++#endif
++
++
+ #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+ 
+ #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
+Index: linux-2.4.24/arch/i386/config.in
+===================================================================
+--- linux-2.4.24.orig/arch/i386/config.in	2004-01-14 02:58:46.000000000 +0300
++++ linux-2.4.24/arch/i386/config.in	2004-02-06 11:17:09.000000000 +0300
+@@ -508,6 +508,9 @@
+    bool '  Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW
+    bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
+    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
++   if [ "$CONFIG_DEBUG_SLAB" != "n" ]; then
++      bool '  Debug memory allocations (use-after-free via vmalloced space)' CONFIG_DEBUG_UAF
++   fi
+    bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
+    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
+
+%diffstat
+ arch/i386/config.in     |    3 
+ fs/proc/proc_misc.c     |   19 +
+ include/asm-i386/io.h   |   10 
+ include/asm-i386/page.h |   40 +++
+ include/linux/slab.h    |    1 
+ init/main.c             |    3 
+ mm/slab.c               |  506 +++++++++++++++++++++++++++++++++++++++++++++++-
+ mm/vmalloc.c            |    4 
+ 8 files changed, 582 insertions(+), 4 deletions(-)
+
-- 
GitLab