FAILED: patch "[PATCH] io_uring: Convert personality_idr to XArray" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 61cf93700fe6359552848ed5e3becba6cd760efa Mon Sep 17 00:00:00 2001
From: "Matthew Wilcox (Oracle)" <[email protected]>
Date: Mon, 8 Mar 2021 14:16:16 +0000
Subject: [PATCH] io_uring: Convert personality_idr to XArray
You can't call idr_remove() from within a idr_for_each() callback, but you can call xa_erase() from an xa_for_each() loop, so switch the entire personality_idr from the IDR to the XArray. This manifests as a use-after-free as idr_for_each() attempts to walk the rest of the node after removing the last entry from it.
fs/io_uring.c +24 -23
@@ -406,7 +406,8 @@ struct io_ring_ctx {struct idr io_buffer_idr; -struct idr personality_idr; +struct xarray personalities; +u32 pers_next;struct {unsigned cached_cq_tail;
@@ -1137,7 +1138,7 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)init_completion (&ctx->ref_comp);init_completion (&ctx->sq_thread_comp);idr_init (&ctx->io_buffer_idr); -idr_init (&ctx->personality_idr); +xa_init_flags (&ctx->personalities,XA_FLAGS_ALLOC1 );mutex_init (&ctx->uring_lock);init_waitqueue_head (&ctx->wait);spin_lock_init (&ctx->completion_lock);
@@ -6337,7 +6338,7 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req, req->work.list.next =NULL ; personality =READ_ONCE (sqe->personality);if (personality) { - req->work.creds =idr_find (&ctx->personality_idr, personality); + req->work.creds =xa_load (&ctx->personalities, personality);if (!req->work.creds)return -EINVAL ;get_cred (req->work.creds);
@@ -8355,7 +8356,6 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)mutex_unlock (&ctx->uring_lock);io_eventfd_unregister (ctx);io_destroy_buffers (ctx); -idr_destroy (&ctx->personality_idr);#if defined(CONFIG_UNIX )if (ctx->ring_sock) {
@@ -8420,7 +8420,7 @@ static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id) {const struct cred *creds; - creds =idr_remove (&ctx->personality_idr, id); + creds =xa_erase (&ctx->personalities, id);if (creds) {put_cred (creds);return 0 ;
@@ -8429,14 +8429,6 @@ static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id)return -EINVAL ; } -static int io_remove_personalities (int id,void *p,void *data) -{ -struct io_ring_ctx *ctx = data; - -io_unregister_personality (ctx, id); -return 0 ; -} -static bool io_run_ctx_fallback (struct io_ring_ctx *ctx) {struct callback_head *work, *next;
@@ -8526,13 +8518,17 @@ static void io_ring_exit_work(struct work_struct *work)static void io_ring_ctx_wait_and_kill (struct io_ring_ctx *ctx) { +unsigned long index; +struct creds *creds; +mutex_lock (&ctx->uring_lock);percpu_ref_kill (&ctx->refs);/* if force is set, the ring is going away. always drop after that */ ctx->cq_overflow_flushed =1 ;if (ctx->rings)__io_cqring_overflow_flush (ctx, true,NULL ,NULL ); -idr_for_each (&ctx->personality_idr, io_remove_personalities, ctx); +xa_for_each (&ctx->personalities, index, creds) +io_unregister_personality (ctx, index);mutex_unlock (&ctx->uring_lock);io_kill_timeouts (ctx,NULL ,NULL );
@@ -9162,10 +9158,9 @@ SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit, }#ifdef CONFIG_PROC_FS -static int io_uring_show_cred (int id,void *p,void *data) +static int io_uring_show_cred (struct seq_file *m,unsigned int id, +const struct cred *cred) { -const struct cred *cred = p; -struct seq_file *m = data;struct user_namespace *uns =seq_user_ns (m);struct group_info *gi;kernel_cap_t cap;
@@ -9233,9 +9228,13 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)seq_printf (m,"%5u: 0x%llx/%u\n" , i, buf->ubuf, (unsigned int ) buf->len); } -if (has_lock && !idr_is_empty (&ctx->personality_idr)) { +if (has_lock && !xa_empty (&ctx->personalities)) { +unsigned long index; +const struct cred *cred; +seq_printf (m,"Personalities:\n" ); -idr_for_each (&ctx->personality_idr, io_uring_show_cred, m); +xa_for_each (&ctx->personalities, index, cred) +io_uring_show_cred (m, index, cred); }seq_printf (m,"PollList:\n" );spin_lock_irq (&ctx->completion_lock);
@@ -9564,14 +9563,16 @@ static int io_probe(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_args)static int io_register_personality (struct io_ring_ctx *ctx) {const struct cred *creds; +u32 id;int ret; creds =get_current_cred (); - ret =idr_alloc_cyclic (&ctx->personality_idr, (void *) creds,1 , -USHRT_MAX ,GFP_KERNEL ); -if (ret <0 ) -put_cred (creds); + ret =xa_alloc_cyclic (&ctx->personalities, &id, (void *)creds, +XA_LIMIT (0 ,USHRT_MAX ), &ctx->pers_next,GFP_KERNEL ); +if (!ret) +return id; +put_cred (creds);return ret; }