mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	vhost: fix ubuf_info cleanup
vhost_net_clear_ubuf_info didn't clear ubuf_info after kfree, this could trigger double free. Fix this and simplify this code to make it more robust: make sure ubuf info is always freed through vhost_net_clear_ubuf_info. Reported-by: Tommi Rantala <tt.rantala@gmail.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									05c0535194
								
							
						
					
					
						commit
						288cfe78c8
					
				
					 1 changed files with 7 additions and 15 deletions
				
			
		| 
						 | 
					@ -155,14 +155,11 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void vhost_net_clear_ubuf_info(struct vhost_net *n)
 | 
					static void vhost_net_clear_ubuf_info(struct vhost_net *n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					 | 
				
			||||||
	bool zcopy;
 | 
					 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n->dev.nvqs; ++i) {
 | 
						for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
 | 
				
			||||||
		zcopy = vhost_net_zcopy_mask & (0x1 << i);
 | 
					 | 
				
			||||||
		if (zcopy)
 | 
					 | 
				
			||||||
		kfree(n->vqs[i].ubuf_info);
 | 
							kfree(n->vqs[i].ubuf_info);
 | 
				
			||||||
 | 
							n->vqs[i].ubuf_info = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,7 +168,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n)
 | 
				
			||||||
	bool zcopy;
 | 
						bool zcopy;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n->dev.nvqs; ++i) {
 | 
						for (i = 0; i < VHOST_NET_VQ_MAX; ++i) {
 | 
				
			||||||
		zcopy = vhost_net_zcopy_mask & (0x1 << i);
 | 
							zcopy = vhost_net_zcopy_mask & (0x1 << i);
 | 
				
			||||||
		if (!zcopy)
 | 
							if (!zcopy)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
| 
						 | 
					@ -183,12 +180,7 @@ int vhost_net_set_ubuf_info(struct vhost_net *n)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err:
 | 
					err:
 | 
				
			||||||
	while (i--) {
 | 
						vhost_net_clear_ubuf_info(n);
 | 
				
			||||||
		zcopy = vhost_net_zcopy_mask & (0x1 << i);
 | 
					 | 
				
			||||||
		if (!zcopy)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		kfree(n->vqs[i].ubuf_info);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return -ENOMEM;
 | 
						return -ENOMEM;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -196,12 +188,12 @@ void vhost_net_vq_reset(struct vhost_net *n)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vhost_net_clear_ubuf_info(n);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < VHOST_NET_VQ_MAX; i++) {
 | 
						for (i = 0; i < VHOST_NET_VQ_MAX; i++) {
 | 
				
			||||||
		n->vqs[i].done_idx = 0;
 | 
							n->vqs[i].done_idx = 0;
 | 
				
			||||||
		n->vqs[i].upend_idx = 0;
 | 
							n->vqs[i].upend_idx = 0;
 | 
				
			||||||
		n->vqs[i].ubufs = NULL;
 | 
							n->vqs[i].ubufs = NULL;
 | 
				
			||||||
		kfree(n->vqs[i].ubuf_info);
 | 
					 | 
				
			||||||
		n->vqs[i].ubuf_info = NULL;
 | 
					 | 
				
			||||||
		n->vqs[i].vhost_hlen = 0;
 | 
							n->vqs[i].vhost_hlen = 0;
 | 
				
			||||||
		n->vqs[i].sock_hlen = 0;
 | 
							n->vqs[i].sock_hlen = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue