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_node *lhp;
- if (dent_addr < min_addr)
- goto out;
- 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))))
+ /* Check whether the ptr might be valid at all.. */
+ if (!kmem_ptr_validate(dentry_cache, dentry))
goto out;
if (dentry->d_parent != dparent)
extern unsigned int ksize(const void *);
extern int FASTCALL(kmem_cache_reap(int));
+extern int FASTCALL(kmem_ptr_validate(kmem_cache_t *cachep, void *ptr));
/* System wide caches */
extern kmem_cache_t *vm_area_cachep;
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
* @size: how many bytes of memory are required.