[PATCH 15/18] mm/vchecker: pass allocation caller address to vchecker hook

From: js1304
Date: Tue Nov 28 2017 - 02:50:19 EST


From: Joonsoo Kim <iamjoonsoo.kim@xxxxxxx>

Vchecker requires kmalloc caller address to support validation on
*specific* kmalloc user. Therefore, this patch passes slab allocation
caller address to vchecker hook. This caller address will be used in the
following patch.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@xxxxxxx>
---
include/linux/slab.h | 2 ++
mm/kasan/kasan.c | 1 -
mm/kasan/vchecker.c | 3 ++-
mm/kasan/vchecker.h | 5 +++--
mm/slab.c | 14 ++++++++++----
mm/slab.h | 4 +++-
mm/slab_common.c | 6 ++++++
mm/slub.c | 11 ++++++++---
8 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/include/linux/slab.h b/include/linux/slab.h
index f6efbbe..25a74f3c 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -421,6 +421,7 @@ static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s,
void *ret = kmem_cache_alloc(s, flags);

kasan_kmalloc(s, ret, size, flags);
+ vchecker_kmalloc(s, ret, size, _THIS_IP_);
return ret;
}

@@ -432,6 +433,7 @@ kmem_cache_alloc_node_trace(struct kmem_cache *s,
void *ret = kmem_cache_alloc_node(s, gfpflags, node);

kasan_kmalloc(s, ret, size, gfpflags);
+ vchecker_kmalloc(s, ret, size, _THIS_IP_);
return ret;
}
#endif /* CONFIG_TRACING */
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index 984e423..8634e43 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -552,7 +552,6 @@ void kasan_kmalloc(struct kmem_cache *cache, const void *object, size_t size,
kasan_unpoison_shadow(object, size);
kasan_poison_shadow((void *)redzone_start, redzone_end - redzone_start,
KASAN_KMALLOC_REDZONE);
- vchecker_kmalloc(cache, object, size);

if (cache->flags & SLAB_KASAN)
set_track(&get_alloc_info(cache, object)->alloc_track, flags);
diff --git a/mm/kasan/vchecker.c b/mm/kasan/vchecker.c
index 4d140e7..918f05a 100644
--- a/mm/kasan/vchecker.c
+++ b/mm/kasan/vchecker.c
@@ -144,7 +144,8 @@ void vchecker_cache_create(struct kmem_cache *s,
*size += sizeof(struct vchecker_data);
}

-void vchecker_kmalloc(struct kmem_cache *s, const void *object, size_t size)
+void vchecker_kmalloc(struct kmem_cache *s, const void *object, size_t size,
+ unsigned long ret_ip)
{
struct vchecker *checker;
struct vchecker_cb *cb;
diff --git a/mm/kasan/vchecker.h b/mm/kasan/vchecker.h
index efebc63..ab5a6f6 100644
--- a/mm/kasan/vchecker.h
+++ b/mm/kasan/vchecker.h
@@ -12,7 +12,8 @@ struct vchecker_cache {


#ifdef CONFIG_VCHECKER
-void vchecker_kmalloc(struct kmem_cache *s, const void *object, size_t size);
+void vchecker_kmalloc(struct kmem_cache *s, const void *object, size_t size,
+ unsigned long ret_ip);
bool vchecker_check(unsigned long addr, size_t size,
bool write, unsigned long ret_ip);
int init_vchecker(struct kmem_cache *s);
@@ -26,7 +27,7 @@ void vchecker_enable_obj(struct kmem_cache *s, const void *object,

#else
static inline void vchecker_kmalloc(struct kmem_cache *s,
- const void *object, size_t size) { }
+ const void *object, size_t size, unsigned long ret_ip) { }
static inline bool vchecker_check(unsigned long addr, size_t size,
bool write, unsigned long ret_ip) { return false; }
static inline int init_vchecker(struct kmem_cache *s) { return 0; }
diff --git a/mm/slab.c b/mm/slab.c
index 64d768b..f6b1adf 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3359,7 +3359,7 @@ slab_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
if (unlikely(flags & __GFP_ZERO) && ptr)
memset(ptr, 0, cachep->object_size);

- slab_post_alloc_hook(cachep, flags, 1, &ptr);
+ slab_post_alloc_hook(cachep, flags, 1, &ptr, caller);
return ptr;
}

@@ -3416,7 +3416,7 @@ slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller)
if (unlikely(flags & __GFP_ZERO) && objp)
memset(objp, 0, cachep->object_size);

- slab_post_alloc_hook(cachep, flags, 1, &objp);
+ slab_post_alloc_hook(cachep, flags, 1, &objp, caller);
return objp;
}

@@ -3579,6 +3579,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
void *ret = slab_alloc(cachep, flags, _RET_IP_);

kasan_slab_alloc(cachep, ret, flags);
+ vchecker_kmalloc(cachep, ret, cachep->object_size, _RET_IP_);
trace_kmem_cache_alloc(_RET_IP_, ret,
cachep->object_size, cachep->size, flags);

@@ -3624,13 +3625,13 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
for (i = 0; i < size; i++)
memset(p[i], 0, s->object_size);

- slab_post_alloc_hook(s, flags, size, p);
+ slab_post_alloc_hook(s, flags, size, p, _RET_IP_);
/* FIXME: Trace call missing. Christoph would like a bulk variant */
return size;
error:
local_irq_enable();
cache_alloc_debugcheck_after_bulk(s, flags, i, p, _RET_IP_);
- slab_post_alloc_hook(s, flags, i, p);
+ slab_post_alloc_hook(s, flags, i, p, _RET_IP_);
__kmem_cache_free_bulk(s, i, p);
return 0;
}
@@ -3645,6 +3646,7 @@ kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)
ret = slab_alloc(cachep, flags, _RET_IP_);

kasan_kmalloc(cachep, ret, size, flags);
+ vchecker_kmalloc(cachep, ret, size, _RET_IP_);
trace_kmalloc(_RET_IP_, ret,
size, cachep->size, flags);
return ret;
@@ -3669,6 +3671,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid)
void *ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);

kasan_slab_alloc(cachep, ret, flags);
+ vchecker_kmalloc(cachep, ret, cachep->object_size, _RET_IP_);
trace_kmem_cache_alloc_node(_RET_IP_, ret,
cachep->object_size, cachep->size,
flags, nodeid);
@@ -3688,6 +3691,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
ret = slab_alloc_node(cachep, flags, nodeid, _RET_IP_);

kasan_kmalloc(cachep, ret, size, flags);
+ vchecker_kmalloc(cachep, ret, size, _RET_IP_);
trace_kmalloc_node(_RET_IP_, ret,
size, cachep->size,
flags, nodeid);
@@ -3707,6 +3711,7 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller)
return cachep;
ret = kmem_cache_alloc_node_trace(cachep, flags, node, size);
kasan_kmalloc(cachep, ret, size, flags);
+ vchecker_kmalloc(cachep, ret, size, _RET_IP_);

return ret;
}
@@ -3743,6 +3748,7 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
ret = slab_alloc(cachep, flags, caller);

kasan_kmalloc(cachep, ret, size, flags);
+ vchecker_kmalloc(cachep, ret, size, _RET_IP_);
trace_kmalloc(caller, ret,
size, cachep->size, flags);

diff --git a/mm/slab.h b/mm/slab.h
index c1cf486..9fce8ab 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -435,7 +435,8 @@ static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
}

static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
- size_t size, void **p)
+ size_t size, void **p,
+ unsigned long caller)
{
size_t i;

@@ -446,6 +447,7 @@ static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
kmemleak_alloc_recursive(object, s->object_size, 1,
s->flags, flags);
kasan_slab_alloc(s, object, flags);
+ vchecker_kmalloc(s, object, s->object_size, caller);
}

if (memcg_kmem_enabled())
diff --git a/mm/slab_common.c b/mm/slab_common.c
index 6f700f3..ffc7515 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -1446,12 +1446,18 @@ static __always_inline void *__do_krealloc(const void *p, size_t new_size,
{
void *ret;
size_t ks = 0;
+ struct page *page;

if (p)
ks = ksize(p);

if (ks >= new_size) {
kasan_krealloc((void *)p, new_size, flags);
+ page = virt_to_head_page(p);
+ if (PageSlab(page)) {
+ vchecker_kmalloc(page->slab_cache, p,
+ new_size, _RET_IP_);
+ }
return (void *)p;
}

diff --git a/mm/slub.c b/mm/slub.c
index c099b33..d37f023 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2755,7 +2755,7 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s,
if (unlikely(gfpflags & __GFP_ZERO) && object)
memset(object, 0, s->object_size);

- slab_post_alloc_hook(s, gfpflags, 1, &object);
+ slab_post_alloc_hook(s, gfpflags, 1, &object, addr);

return object;
}
@@ -2783,6 +2783,7 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
void *ret = slab_alloc(s, gfpflags, _RET_IP_);
trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);
kasan_kmalloc(s, ret, size, gfpflags);
+ vchecker_kmalloc(s, ret, size, _RET_IP_);
return ret;
}
EXPORT_SYMBOL(kmem_cache_alloc_trace);
@@ -2811,6 +2812,7 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
size, s->size, gfpflags, node);

kasan_kmalloc(s, ret, size, gfpflags);
+ vchecker_kmalloc(s, ret, size, _RET_IP_);
return ret;
}
EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
@@ -3184,11 +3186,11 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
}

/* memcg and kmem_cache debug support */
- slab_post_alloc_hook(s, flags, size, p);
+ slab_post_alloc_hook(s, flags, size, p, _RET_IP_);
return i;
error:
local_irq_enable();
- slab_post_alloc_hook(s, flags, i, p);
+ slab_post_alloc_hook(s, flags, i, p, _RET_IP_);
__kmem_cache_free_bulk(s, i, p);
return 0;
}
@@ -3388,6 +3390,7 @@ static void early_kmem_cache_node_alloc(int node)
#endif
kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node),
GFP_KERNEL);
+ vchecker_kmalloc(kmem_cache_node, n, sizeof(*n), _RET_IP_);
init_kmem_cache_node(n);
inc_slabs_node(kmem_cache_node, node, page->objects);

@@ -3794,6 +3797,7 @@ void *__kmalloc(size_t size, gfp_t flags)
trace_kmalloc(_RET_IP_, ret, size, s->size, flags);

kasan_kmalloc(s, ret, size, flags);
+ vchecker_kmalloc(s, ret, size, _RET_IP_);

return ret;
}
@@ -3839,6 +3843,7 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node);

kasan_kmalloc(s, ret, size, flags);
+ vchecker_kmalloc(s, ret, size, _RET_IP_);

return ret;
}
--
2.7.4