]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fs/aio: Use RCU accessors for kioctx_table->table[]
authorTejun Heo <tj@kernel.org>
Wed, 14 Mar 2018 19:10:17 +0000 (12:10 -0700)
committerSasha Levin <alexander.levin@microsoft.com>
Wed, 23 May 2018 01:33:47 +0000 (21:33 -0400)
[ Upstream commit d0264c01e7587001a8c4608a5d1818dba9a4c11a ]

While converting ioctx index from a list to a table, db446a08c23d
("aio: convert the ioctx list to table lookup v3") missed tagging
kioctx_table->table[] as an array of RCU pointers and using the
appropriate RCU accessors.  This introduces a small window in the
lookup path where init and access may race.

Mark kioctx_table->table[] with __rcu and use the approriate RCU
accessors when using the field.

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: Jann Horn <jannh@google.com>
Fixes: db446a08c23d ("aio: convert the ioctx list to table lookup v3")
Cc: Benjamin LaHaise <bcrl@kvack.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: stable@vger.kernel.org # v3.12+
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
fs/aio.c

index 03fe14f2cd077a8facf55e8deedf5e6aea2c2b20..61ada5047da20abcd3157f93d274736d797e39be 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -68,9 +68,9 @@ struct aio_ring {
 #define AIO_RING_PAGES 8
 
 struct kioctx_table {
-       struct rcu_head rcu;
-       unsigned        nr;
-       struct kioctx   *table[];
+       struct rcu_head         rcu;
+       unsigned                nr;
+       struct kioctx __rcu     *table[];
 };
 
 struct kioctx_cpu {
@@ -328,7 +328,7 @@ static int aio_ring_remap(struct file *file, struct vm_area_struct *vma)
        for (i = 0; i < table->nr; i++) {
                struct kioctx *ctx;
 
-               ctx = table->table[i];
+               ctx = rcu_dereference(table->table[i]);
                if (ctx && ctx->aio_ring_file == file) {
                        if (!atomic_read(&ctx->dead)) {
                                ctx->user_id = ctx->mmap_base = vma->vm_start;
@@ -637,9 +637,9 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
        while (1) {
                if (table)
                        for (i = 0; i < table->nr; i++)
-                               if (!table->table[i]) {
+                               if (!rcu_access_pointer(table->table[i])) {
                                        ctx->id = i;
-                                       table->table[i] = ctx;
+                                       rcu_assign_pointer(table->table[i], ctx);
                                        spin_unlock(&mm->ioctx_lock);
 
                                        /* While kioctx setup is in progress,
@@ -814,8 +814,8 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
        }
 
        table = rcu_dereference_raw(mm->ioctx_table);
-       WARN_ON(ctx != table->table[ctx->id]);
-       table->table[ctx->id] = NULL;
+       WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
+       RCU_INIT_POINTER(table->table[ctx->id], NULL);
        spin_unlock(&mm->ioctx_lock);
 
        /* free_ioctx_reqs() will do the necessary RCU synchronization */
@@ -860,7 +860,8 @@ void exit_aio(struct mm_struct *mm)
 
        skipped = 0;
        for (i = 0; i < table->nr; ++i) {
-               struct kioctx *ctx = table->table[i];
+               struct kioctx *ctx =
+                       rcu_dereference_protected(table->table[i], true);
 
                if (!ctx) {
                        skipped++;
@@ -1049,7 +1050,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
        if (!table || id >= table->nr)
                goto out;
 
-       ctx = table->table[id];
+       ctx = rcu_dereference(table->table[id]);
        if (ctx && ctx->user_id == ctx_id) {
                percpu_ref_get(&ctx->users);
                ret = ctx;