Commit fa36f31a authored by Linus Torvalds's avatar Linus Torvalds

Clean up dentry pointer validation by moving it into

a function of its own.

This also allows us to do a better job, since slab.c
can now do more proper tests.
parent d9efde4d
...@@ -1035,20 +1035,11 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) ...@@ -1035,20 +1035,11 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
int d_validate(struct dentry *dentry, struct dentry *dparent) int d_validate(struct dentry *dentry, struct dentry *dparent)
{ {
unsigned long dent_addr = (unsigned long) dentry;
unsigned long min_addr = PAGE_OFFSET;
unsigned long align_mask = 0x0F;
struct hlist_head *base; struct hlist_head *base;
struct hlist_node *lhp; struct hlist_node *lhp;
if (dent_addr < min_addr) /* Check whether the ptr might be valid at all.. */
goto out; if (!kmem_ptr_validate(dentry_cache, dentry))
if (dent_addr > (unsigned long)high_memory - sizeof(struct dentry))
goto out;
if (dent_addr & align_mask)
goto out;
if ((!kern_addr_valid(dent_addr)) || (!kern_addr_valid(dent_addr -1 +
sizeof(struct dentry))))
goto out; goto out;
if (dentry->d_parent != dparent) if (dentry->d_parent != dparent)
......
...@@ -101,6 +101,7 @@ extern void kfree(const void *); ...@@ -101,6 +101,7 @@ extern void kfree(const void *);
extern unsigned int ksize(const void *); extern unsigned int ksize(const void *);
extern int FASTCALL(kmem_cache_reap(int)); extern int FASTCALL(kmem_cache_reap(int));
extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr));
/* System wide caches */ /* System wide caches */
extern kmem_cache_t *vm_area_cachep; extern kmem_cache_t *vm_area_cachep;
......
...@@ -2073,6 +2073,48 @@ void * kmem_cache_alloc (kmem_cache_t *cachep, int flags) ...@@ -2073,6 +2073,48 @@ void * kmem_cache_alloc (kmem_cache_t *cachep, int flags)
EXPORT_SYMBOL(kmem_cache_alloc); EXPORT_SYMBOL(kmem_cache_alloc);
/**
* kmem_ptr_validate - check if an untrusted pointer might
* be a slab entry.
* @cachep: the cache we're checking against
* @ptr: pointer to validate
*
* This verifies that the untrusted pointer looks sane:
* it is _not_ a guarantee that the pointer is actually
* part of the slab cache in question, but it at least
* validates that the pointer can be dereferenced and
* looks half-way sane.
*
* Currently only used for dentry validation.
*/
int kmem_ptr_validate(kmem_cache_t *cachep, void *ptr)
{
unsigned long addr = (unsigned long) ptr;
unsigned long min_addr = PAGE_OFFSET;
unsigned long align_mask = BYTES_PER_WORD-1;
unsigned long size = cachep->objsize;
struct page *page;
if (unlikely(addr < min_addr))
goto out;
if (unlikely(addr > (unsigned long)high_memory - size))
goto out;
if (unlikely(addr & align_mask))
goto out;
if (unlikely(!kern_addr_valid(addr)))
goto out;
if (unlikely(!kern_addr_valid(addr + size - 1)))
goto out;
page = virt_to_page(ptr);
if (unlikely(!PageSlab(page)))
goto out;
if (unlikely(GET_PAGE_CACHE(page) != cachep))
goto out;
return 1;
out:
return 0;
}
/** /**
* kmalloc - allocate memory * kmalloc - allocate memory
* @size: how many bytes of memory are required. * @size: how many bytes of memory are required.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment