summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2018-12-28 03:34:43 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-12-28 15:11:47 -0500
commitca880420665dbc8beec3693bee9f5eccb89de4a6 (patch)
tree7255c489175110780706a7eaf04fe8f0f34611b5
parent66f71da9dd38af17dc17209cdde7987d4679a699 (diff)
userfaultfd: convert userfaultfd_ctx::refcount to refcount_t
Reference counters should use refcount_t rather than atomic_t, since the refcount_t implementation can prevent overflows, reducing the exploitability of reference leak bugs. userfaultfd_ctx::refcount is a reference counter with the usual semantics, so convert it to refcount_t. Note: I replaced the BUG() on incrementing a 0 refcount with just refcount_inc(), since part of the semantics of refcount_t is that that incrementing a 0 refcount is not allowed; with CONFIG_REFCOUNT_FULL, refcount_inc() already checks for it and warns. Link: http://lkml.kernel.org/r/20181115003916.63381-1-ebiggers@kernel.org Signed-off-by: Eric Biggers <ebiggers@google.com> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Cc: Andrea Arcangeli <aarcange@redhat.com> Reviewed-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/userfaultfd.c11
1 files changed, 5 insertions, 6 deletions
diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 59dc28047030..e211b99d33c4 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -53,7 +53,7 @@ struct userfaultfd_ctx {
53 /* a refile sequence protected by fault_pending_wqh lock */ 53 /* a refile sequence protected by fault_pending_wqh lock */
54 struct seqcount refile_seq; 54 struct seqcount refile_seq;
55 /* pseudo fd refcounting */ 55 /* pseudo fd refcounting */
56 atomic_t refcount; 56 refcount_t refcount;
57 /* userfaultfd syscall flags */ 57 /* userfaultfd syscall flags */
58 unsigned int flags; 58 unsigned int flags;
59 /* features requested from the userspace */ 59 /* features requested from the userspace */
@@ -140,8 +140,7 @@ out:
140 */ 140 */
141static void userfaultfd_ctx_get(struct userfaultfd_ctx *ctx) 141static void userfaultfd_ctx_get(struct userfaultfd_ctx *ctx)
142{ 142{
143 if (!atomic_inc_not_zero(&ctx->refcount)) 143 refcount_inc(&ctx->refcount);
144 BUG();
145} 144}
146 145
147/** 146/**
@@ -154,7 +153,7 @@ static void userfaultfd_ctx_get(struct userfaultfd_ctx *ctx)
154 */ 153 */
155static void userfaultfd_ctx_put(struct userfaultfd_ctx *ctx) 154static void userfaultfd_ctx_put(struct userfaultfd_ctx *ctx)
156{ 155{
157 if (atomic_dec_and_test(&ctx->refcount)) { 156 if (refcount_dec_and_test(&ctx->refcount)) {
158 VM_BUG_ON(spin_is_locked(&ctx->fault_pending_wqh.lock)); 157 VM_BUG_ON(spin_is_locked(&ctx->fault_pending_wqh.lock));
159 VM_BUG_ON(waitqueue_active(&ctx->fault_pending_wqh)); 158 VM_BUG_ON(waitqueue_active(&ctx->fault_pending_wqh));
160 VM_BUG_ON(spin_is_locked(&ctx->fault_wqh.lock)); 159 VM_BUG_ON(spin_is_locked(&ctx->fault_wqh.lock));
@@ -686,7 +685,7 @@ int dup_userfaultfd(struct vm_area_struct *vma, struct list_head *fcs)
686 return -ENOMEM; 685 return -ENOMEM;
687 } 686 }
688 687
689 atomic_set(&ctx->refcount, 1); 688 refcount_set(&ctx->refcount, 1);
690 ctx->flags = octx->flags; 689 ctx->flags = octx->flags;
691 ctx->state = UFFD_STATE_RUNNING; 690 ctx->state = UFFD_STATE_RUNNING;
692 ctx->features = octx->features; 691 ctx->features = octx->features;
@@ -1927,7 +1926,7 @@ SYSCALL_DEFINE1(userfaultfd, int, flags)
1927 if (!ctx) 1926 if (!ctx)
1928 return -ENOMEM; 1927 return -ENOMEM;
1929 1928
1930 atomic_set(&ctx->refcount, 1); 1929 refcount_set(&ctx->refcount, 1);
1931 ctx->flags = flags; 1930 ctx->flags = flags;
1932 ctx->features = 0; 1931 ctx->features = 0;
1933 ctx->state = UFFD_STATE_WAIT_API; 1932 ctx->state = UFFD_STATE_WAIT_API;