forked from mirrors/linux
		
	io_uring/net: save msghdr->msg_control for retries
If the application sets ->msg_control and we have to later retry this command, or if it got queued with IOSQE_ASYNC to begin with, then we need to retain the original msg_control value. This is due to the net stack overwriting this field with an in-kernel pointer, to copy it in. Hitting that path for the second time will now fail the copy from user, as it's attempting to copy from a non-user address. Cc: stable@vger.kernel.org # 5.10+ Link: https://github.com/axboe/liburing/issues/880 Reported-and-tested-by: Marek Majkowski <marek@cloudflare.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
		
							parent
							
								
									b6dad5178c
								
							
						
					
					
						commit
						cac9e4418f
					
				
					 1 changed files with 7 additions and 1 deletions
				
			
		| 
						 | 
					@ -65,6 +65,7 @@ struct io_sr_msg {
 | 
				
			||||||
	u16				addr_len;
 | 
						u16				addr_len;
 | 
				
			||||||
	u16				buf_group;
 | 
						u16				buf_group;
 | 
				
			||||||
	void __user			*addr;
 | 
						void __user			*addr;
 | 
				
			||||||
 | 
						void __user			*msg_control;
 | 
				
			||||||
	/* used only for send zerocopy */
 | 
						/* used only for send zerocopy */
 | 
				
			||||||
	struct io_kiocb 		*notif;
 | 
						struct io_kiocb 		*notif;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -195,11 +196,15 @@ static int io_sendmsg_copy_hdr(struct io_kiocb *req,
 | 
				
			||||||
			       struct io_async_msghdr *iomsg)
 | 
								       struct io_async_msghdr *iomsg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 | 
						struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	iomsg->msg.msg_name = &iomsg->addr;
 | 
						iomsg->msg.msg_name = &iomsg->addr;
 | 
				
			||||||
	iomsg->free_iov = iomsg->fast_iov;
 | 
						iomsg->free_iov = iomsg->fast_iov;
 | 
				
			||||||
	return sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
 | 
						ret = sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
 | 
				
			||||||
					&iomsg->free_iov);
 | 
										&iomsg->free_iov);
 | 
				
			||||||
 | 
						/* save msg_control as sys_sendmsg() overwrites it */
 | 
				
			||||||
 | 
						sr->msg_control = iomsg->msg.msg_control;
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int io_send_prep_async(struct io_kiocb *req)
 | 
					int io_send_prep_async(struct io_kiocb *req)
 | 
				
			||||||
| 
						 | 
					@ -297,6 +302,7 @@ int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (req_has_async_data(req)) {
 | 
						if (req_has_async_data(req)) {
 | 
				
			||||||
		kmsg = req->async_data;
 | 
							kmsg = req->async_data;
 | 
				
			||||||
 | 
							kmsg->msg.msg_control = sr->msg_control;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		ret = io_sendmsg_copy_hdr(req, &iomsg);
 | 
							ret = io_sendmsg_copy_hdr(req, &iomsg);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue