Skip to content

Memory access violation when using io_uring_submit_and_wait_reg() #1567

@lichrot

Description

@lichrot

I'm sorry for the mistakes I'm probably gonna make in this issue in advance, as I'm currently learning C and I'm still very new to Linux programming, in general.

When trying to use the io_uring_submit_and_wait_reg() function, given a properly setup timer and zero submitted SQEs, everything works fine. But as soon as I try to submit SQEs, I get a SIGSEGV error, specifically when not enough (or zero) SQEs have been completed before the deadline, triggering the timeout. It took me a good while to figure out what's wrong, but after stepping through in the debugger, I've found that a particular branch in the internal _io_uring_get_cqe() function tries to access memory that is... not memory at all. I'm not sure as to the specifics of this issue, but I was able to find that the culprit was this line:

// src/queue.c:106
		if (looped && data->has_ts) {
			struct io_uring_getevents_arg *arg = data->arg;

			if (!cqe && arg->ts && !err) // <== arg->ts is illegal here
				err = -ETIME;
			break;
		}

After some further digging up and down the call stack, I've found that the data->arg member field in this particular case is set not to an address, but to an offset (i.e. regular non-address integer):

// src/queue.c:338
int io_uring_submit_and_wait_reg(struct io_uring *ring,
				 struct io_uring_cqe **cqe_ptr,
				 unsigned wait_nr, int reg_index)
{
	unsigned long offset = reg_index * sizeof(struct io_uring_reg_wait);

	struct get_data data = {
		.submit		= __io_uring_flush_sq(ring),
		.wait_nr	= wait_nr,
		.get_flags	= IORING_ENTER_EXT_ARG | IORING_ENTER_EXT_ARG_REG,
		.sz		= sizeof(struct io_uring_reg_wait),
		.has_ts		= true,
		.arg		= (void *) (uintptr_t) offset, // <== Here's the offset being casted to an address
	};

	if (!(ring->features & IORING_FEAT_EXT_ARG))
		return -EINVAL;

	return _io_uring_get_cqe(ring, cqe_ptr, &data);
}

I was able to "fix" this by just removing the arg->ts check, but this most assuredly wrong:

// src/queue.c:106
		if (looped && data->has_ts) {
			struct io_uring_getevents_arg *arg = data->arg;

			if (!cqe && !err) // <== arg->ts is removed
				err = -ETIME;
			break;
		}

Is it indeed a bug, or is my liburing-jutsu lacking?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions