From: Andrea Arcangeli Date: Wed, 22 Feb 2017 23:43:55 +0000 (-0800) Subject: userfaultfd: shmem: avoid leaking blocks and used blocks in UFFDIO_COPY X-Git-Tag: v4.11-rc1~106^2~59 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=cb658a453b9327ce96ce5222c24d162b5b65b564;p=linux.git userfaultfd: shmem: avoid leaking blocks and used blocks in UFFDIO_COPY If the atomic copy_user fails because of a real dangling userland pointer, we won't go back into the shmem method, so when the method returns it must not leave anything charged up, except the page itself. Link: http://lkml.kernel.org/r/20161216144821.5183-37-aarcange@redhat.com Signed-off-by: Andrea Arcangeli Cc: "Dr. David Alan Gilbert" Cc: Hillf Danton Cc: Michael Rapoport Cc: Mike Kravetz Cc: Mike Rapoport Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- diff --git a/mm/shmem.c b/mm/shmem.c index 8d7d80cf8708..9c6d22ff44e2 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2214,17 +2214,17 @@ int shmem_mcopy_atomic_pte(struct mm_struct *dst_mm, pte_t _dst_pte, *dst_pte; int ret; - if (!*pagep) { - ret = -ENOMEM; - if (shmem_acct_block(info->flags, 1)) - goto out; - if (sbinfo->max_blocks) { - if (percpu_counter_compare(&sbinfo->used_blocks, - sbinfo->max_blocks) >= 0) - goto out_unacct_blocks; - percpu_counter_inc(&sbinfo->used_blocks); - } + ret = -ENOMEM; + if (shmem_acct_block(info->flags, 1)) + goto out; + if (sbinfo->max_blocks) { + if (percpu_counter_compare(&sbinfo->used_blocks, + sbinfo->max_blocks) >= 0) + goto out_unacct_blocks; + percpu_counter_inc(&sbinfo->used_blocks); + } + if (!*pagep) { page = shmem_alloc_page(gfp, info, pgoff); if (!page) goto out_dec_used_blocks; @@ -2237,6 +2237,9 @@ int shmem_mcopy_atomic_pte(struct mm_struct *dst_mm, /* fallback to copy_from_user outside mmap_sem */ if (unlikely(ret)) { *pagep = page; + if (sbinfo->max_blocks) + percpu_counter_add(&sbinfo->used_blocks, -1); + shmem_unacct_blocks(info->flags, 1); /* don't free the page */ return -EFAULT; }