Thread (60 messages) 60 messages, 6 authors, 2019-02-01

Re: [PATCH 05/18] Add io_uring IO interface

flat view

From: Jens Axboe <axboe@kernel.dk>
Date: 2019-01-29 02:21:33
Also in: linux-block, linux-man

On 1/28/19 6:07 PM, Jann Horn wrote:
On Mon, Jan 28, 2019 at 10:35 PM Jens Axboe [off-list ref] wrote:
quoted
The submission queue (SQ) and completion queue (CQ) rings are shared
between the application and the kernel. This eliminates the need to
copy data back and forth to submit and complete IO.
[...]
quoted
+static bool io_get_sqring(struct io_ring_ctx *ctx, struct sqe_submit *s)
+{
+       struct io_sq_ring *ring = ctx->sq_ring;
+       unsigned head;
+
+       /*
+        * The cached sq head (or cq tail) serves two purposes:
+        *
+        * 1) allows us to batch the cost of updating the user visible
+        *    head updates.
+        * 2) allows the kernel side to track the head on its own, even
+        *    though the application is the one updating it.
+        */
+       head = ctx->cached_sq_head;
+       smp_rmb();
+       if (head == READ_ONCE(ring->r.tail))
+               return false;
+
+       head = ring->array[head & ctx->sq_mask];
+       if (head < ctx->sq_entries) {
+               s->index = head;
+               s->sqe = &ctx->sq_sqes[head];
ring->array can be mapped writable into userspace, right? If so: This
looks like a double-read issue; the compiler might assume that
ring->array is not modified concurrently and perform separate memory
accesses for the "if (head < ctx->sq_entries)" check and the
"&ctx->sq_sqes[head]" computation. Please use READ_ONCE()/WRITE_ONCE()
for all accesses to memory that userspace could concurrently modify in
a malicious way.

There have been some pretty severe security bugs caused by missing
READ_ONCE() annotations around accesses to shared memory; see, for
example, https://www.blackhat.com/docs/us-16/materials/us-16-Wilhelm-Xenpwn-Breaking-Paravirtualized-Devices.pdf
. Slides 35-48 show how the code "switch (op->cmd)", where "op" is a
pointer to shared memory, allowed an attacker to break out of a Xen
virtual machine because the compiler generated multiple memory
accesses.
Thanks, I'll update these to use READ/WRITE_ONCE.
quoted
+               ctx->cached_sq_head++;
+               return true;
+       }
+
+       /* drop invalid entries */
+       ctx->cached_sq_head++;
+       ring->dropped++;
+       smp_wmb();
+       return false;
+}
[...]
quoted
+SYSCALL_DEFINE6(io_uring_enter, unsigned int, fd, u32, to_submit,
+               u32, min_complete, u32, flags, const sigset_t __user *, sig,
+               size_t, sigsz)
+{
+       struct io_ring_ctx *ctx;
+       long ret = -EBADF;
+       struct fd f;
+
+       f = fdget(fd);
+       if (!f.file)
+               return -EBADF;
+
+       ret = -EOPNOTSUPP;
+       if (f.file->f_op != &io_uring_fops)
+               goto out_fput;
Oh, by the way: If you feel like it, maybe you could add a helper
fdget_typed(int fd, struct file_operations *f_op), or something like
that, so that there is less boilerplate code for first doing fdget(),
then checking ->f_op, and then coding an extra bailout path for that?
But that doesn't really have much to do with your patchset, feel free
to ignore this comment.
That's not a bad idea, I think this is a fairly common code pattern.
I'll look into it.

-- 
Jens Axboe

--
To unsubscribe, send a message with 'unsubscribe linux-aio' in
the body to majordomo@kvack.org.  For more info on Linux AIO,
see: http://www.kvack.org/aio/
Don't email: <a href=mailto:"aart@kvack.org">aart@kvack.org</a>
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help