summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2016-09-01 19:15:07 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-09-01 20:52:01 -0400
commitc11600e4fed67ae4cd6a8096936afd445410e8ed (patch)
tree0f71f8ca5028621c2615eb83699535fa8b0ffe84
parent19feeff18bbfde659baa58c2346f15a24d7c405e (diff)
mm, mempolicy: task->mempolicy must be NULL before dropping final reference
KASAN allocates memory from the page allocator as part of kmem_cache_free(), and that can reference current->mempolicy through any number of allocation functions. It needs to be NULL'd out before the final reference is dropped to prevent a use-after-free bug: BUG: KASAN: use-after-free in alloc_pages_current+0x363/0x370 at addr ffff88010b48102c CPU: 0 PID: 15425 Comm: trinity-c2 Not tainted 4.8.0-rc2+ #140 ... Call Trace: dump_stack kasan_object_err kasan_report_error __asan_report_load2_noabort alloc_pages_current <-- use after free depot_save_stack save_stack kasan_slab_free kmem_cache_free __mpol_put <-- free do_exit This patch sets current->mempolicy to NULL before dropping the final reference. Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1608301442180.63329@chino.kir.corp.google.com Fixes: cd11016e5f52 ("mm, kasan: stackdepot implementation. Enable stackdepot for SLAB") Signed-off-by: David Rientjes <rientjes@google.com> Reported-by: Vegard Nossum <vegard.nossum@oracle.com> Acked-by: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Alexander Potapenko <glider@google.com> Cc: Dmitry Vyukov <dvyukov@google.com> Cc: <stable@vger.kernel.org> [4.6+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/mempolicy.h4
-rw-r--r--kernel/exit.c7
-rw-r--r--mm/mempolicy.c17
3 files changed, 22 insertions, 6 deletions
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 4429d255c8ab..5e5b2969d931 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -195,6 +195,7 @@ static inline bool vma_migratable(struct vm_area_struct *vma)
195} 195}
196 196
197extern int mpol_misplaced(struct page *, struct vm_area_struct *, unsigned long); 197extern int mpol_misplaced(struct page *, struct vm_area_struct *, unsigned long);
198extern void mpol_put_task_policy(struct task_struct *);
198 199
199#else 200#else
200 201
@@ -297,5 +298,8 @@ static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma,
297 return -1; /* no node preference */ 298 return -1; /* no node preference */
298} 299}
299 300
301static inline void mpol_put_task_policy(struct task_struct *task)
302{
303}
300#endif /* CONFIG_NUMA */ 304#endif /* CONFIG_NUMA */
301#endif 305#endif
diff --git a/kernel/exit.c b/kernel/exit.c
index 2f974ae042a6..091a78be3b09 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -848,12 +848,7 @@ void do_exit(long code)
848 TASKS_RCU(preempt_enable()); 848 TASKS_RCU(preempt_enable());
849 exit_notify(tsk, group_dead); 849 exit_notify(tsk, group_dead);
850 proc_exit_connector(tsk); 850 proc_exit_connector(tsk);
851#ifdef CONFIG_NUMA 851 mpol_put_task_policy(tsk);
852 task_lock(tsk);
853 mpol_put(tsk->mempolicy);
854 tsk->mempolicy = NULL;
855 task_unlock(tsk);
856#endif
857#ifdef CONFIG_FUTEX 852#ifdef CONFIG_FUTEX
858 if (unlikely(current->pi_state_cache)) 853 if (unlikely(current->pi_state_cache))
859 kfree(current->pi_state_cache); 854 kfree(current->pi_state_cache);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index d8c4e38fb5f4..2da72a5b6ecc 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -2336,6 +2336,23 @@ out:
2336 return ret; 2336 return ret;
2337} 2337}
2338 2338
2339/*
2340 * Drop the (possibly final) reference to task->mempolicy. It needs to be
2341 * dropped after task->mempolicy is set to NULL so that any allocation done as
2342 * part of its kmem_cache_free(), such as by KASAN, doesn't reference a freed
2343 * policy.
2344 */
2345void mpol_put_task_policy(struct task_struct *task)
2346{
2347 struct mempolicy *pol;
2348
2349 task_lock(task);
2350 pol = task->mempolicy;
2351 task->mempolicy = NULL;
2352 task_unlock(task);
2353 mpol_put(pol);
2354}
2355
2339static void sp_delete(struct shared_policy *sp, struct sp_node *n) 2356static void sp_delete(struct shared_policy *sp, struct sp_node *n)
2340{ 2357{
2341 pr_debug("deleting %lx-l%lx\n", n->start, n->end); 2358 pr_debug("deleting %lx-l%lx\n", n->start, n->end);