[PATCH] slub/slab: fix kmemleak didn't work on some case

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



when kernel uses kmalloc to allocate memory, slub/slab will find

a suitable kmem_cache. Ususally the cache's object size is often

greater than requested size. There is unused space which contains

dirty data. These dirty data might have pointers pointing to a block

of leaked memory. Kernel wouldn't consider this memory as leaked when

scanning kmemleak object.

 

The patch fixes it by clearing the unused memory.

 

Signed-off-by: Liu, XinwuX <xinwux.liu@xxxxxxxxx>

Signed-off-by: Chen Lin Z <lin.z.chen@xxxxxxxxx>

---

mm/slab.c | 22 +++++++++++++++++++++-

mm/slub.c | 35 +++++++++++++++++++++++++++++++++++

2 files changed, 56 insertions(+), 1 deletion(-)

 

diff --git a/mm/slab.c b/mm/slab.c

index 7eb38dd..ef25e7d 100644

--- a/mm/slab.c

+++ b/mm/slab.c

@@ -3423,6 +3423,12 @@ kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)

                ret = slab_alloc(cachep, flags, _RET_IP_);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = cachep->object_size - size;

+

+             if (ret && likely(!(flags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

               trace_kmalloc(_RET_IP_, ret,

                                     size, cachep->size, flags);

               return ret;

@@ -3476,11 +3482,19 @@ static __always_inline void *

__do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller)

{

               struct kmem_cache *cachep;

+             void *ret;

                cachep = kmalloc_slab(size, flags);

               if (unlikely(ZERO_OR_NULL_PTR(cachep)))

                               return cachep;

-              return kmem_cache_alloc_node_trace(cachep, flags, node, size);

+             ret = kmem_cache_alloc_node_trace(cachep, flags, node, size);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = cachep->object_size - size;

+

+             if (ret && likely(!(flags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

+             return ret;

}

 void *__kmalloc_node(size_t size, gfp_t flags, int node)

@@ -3513,6 +3527,12 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,

               if (unlikely(ZERO_OR_NULL_PTR(cachep)))

                               return cachep;

               ret = slab_alloc(cachep, flags, caller);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = cachep->object_size - size;

+

+             if (ret && likely(!(flags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

                trace_kmalloc(caller, ret,

                                     size, cachep->size, flags);

diff --git a/mm/slub.c b/mm/slub.c

index 54c0876..b53d9af 100644

--- a/mm/slub.c

+++ b/mm/slub.c

@@ -2530,6 +2530,12 @@ EXPORT_SYMBOL(kmem_cache_alloc);

void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)

{

               void *ret = slab_alloc(s, gfpflags, _RET_IP_);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = s->object_size - size;

+

+             if (ret && likely(!(gfpflags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

               trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags);

               kasan_kmalloc(s, ret, size);

               return ret;

@@ -2556,6 +2562,12 @@ void *kmem_cache_alloc_node_trace(struct kmem_cache *s,

{

               void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = s->object_size - size;

+

+             if (ret && likely(!(gfpflags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

               trace_kmalloc_node(_RET_IP_, ret,

                                                  size, s->size, gfpflags, node);

@@ -3316,6 +3328,12 @@ void *__kmalloc(size_t size, gfp_t flags)

                               return s;

                ret = slab_alloc(s, flags, _RET_IP_);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = s->object_size - size;

+

+             if (ret && likely(!(flags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

                trace_kmalloc(_RET_IP_, ret, size, s->size, flags);

@@ -3361,6 +3379,12 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)

                               return s;

                ret = slab_alloc_node(s, flags, node, _RET_IP_);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = s->object_size - size;

+

+             if (ret && likely(!(flags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

                trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node);

@@ -3819,7 +3843,12 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller)

                               return s;

                ret = slab_alloc(s, gfpflags, caller);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = s->object_size - size;

+             if (ret && likely(!(gfpflags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

               /* Honor the call site pointer we received. */

               trace_kmalloc(caller, ret, size, s->size, gfpflags);

@@ -3849,6 +3878,12 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,

                               return s;

                ret = slab_alloc_node(s, gfpflags, node, caller);

+#ifdef CONFIG_DEBUG_KMEMLEAK

+             int delta = s->object_size - size;

+

+             if (ret && likely(!(gfpflags & __GFP_ZERO)) && (delta > 0))

+                             memset((void *)((char *)ret + size), 0, delta);

+#endif

                /* Honor the call site pointer we received. */

               trace_kmalloc_node(caller, ret, size, s->size, gfpflags, node);

--

1.9.1


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]