On 12.08.26 13:29, Denis V. Lunev wrote:
nbd_receive_replies() reads a reply header into s->reply and, when the header turns out to be unusable, reports a channel error and returns without touching it. The cookie stays there until the request which owns the reply clears it, and until then the waiters are explicitly allowed to look at a cookie which is not theirs:if (s->reply.cookie != 0) { ind2 = COOKIE_TO_INDEX(s->reply.cookie); assert(!s->requests[ind2].receiving); Two of the error paths leave a value chosen by the server behind: one returns before the cookie is validated at all, the other returns because that validation has failed. A waiter which picks such a cookie up turns it into an index which is not in requests[] and accesses the array out of bounds, at an offset the server controls. The reply is of no use to anybody at this point, so clear the cookie before the mutex is released and keep the invariant that a non-zero s->reply.cookie is always an index of a live request. Observing the stale cookie takes a second thread, which a multiqueue configuration provides. Within one AioContext there is no yield point between the failed read and the clearing done by the owner in nbd_co_receive_one_chunk(), so nothing else of this node runs in between. The parked waiters cannot see it either, as they are woken only after the cookie has been cleared. What can get in is a request entering nbd_receive_replies() afresh, one just sent or one back for its next reply chunk, because that path takes the mutex without looking at the state. Signed-off-by: Denis V. Lunev<[email protected]> Cc: Eric Blake<[email protected]> Cc: Vladimir Sementsov-Ogievskiy<[email protected]>
Reviewed-by: Vladimir Sementsov-Ogievskiy <[email protected]> -- Best regards, Vladimir
