Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost

Pull vhost/virtio fixes from Michael Tsirkin:
"A couple of last-minute fixes"

* tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost:
vhost/vsock: fix use-after-free in network stack callers
virtio/s390: fix race in ccw_io_helper()
virtio/s390: avoid race on vcdev->config
vhost/vsock: fix reset orphans race with close timeout

+62 -34
+14 -3
drivers/s390/virtio/virtio_ccw.c
··· 56 56 unsigned int revision; /* Transport revision */ 57 57 wait_queue_head_t wait_q; 58 58 spinlock_t lock; 59 + struct mutex io_lock; /* Serializes I/O requests */ 59 60 struct list_head virtqueues; 60 61 unsigned long indicators; 61 62 unsigned long indicators2; ··· 297 296 unsigned long flags; 298 297 int flag = intparm & VIRTIO_CCW_INTPARM_MASK; 299 298 299 + mutex_lock(&vcdev->io_lock); 300 300 do { 301 301 spin_lock_irqsave(get_ccwdev_lock(vcdev->cdev), flags); 302 302 ret = ccw_device_start(vcdev->cdev, ccw, intparm, 0, 0); ··· 310 308 cpu_relax(); 311 309 } while (ret == -EBUSY); 312 310 wait_event(vcdev->wait_q, doing_io(vcdev, flag) == 0); 313 - return ret ? ret : vcdev->err; 311 + ret = ret ? ret : vcdev->err; 312 + mutex_unlock(&vcdev->io_lock); 313 + return ret; 314 314 } 315 315 316 316 static void virtio_ccw_drop_indicator(struct virtio_ccw_device *vcdev, ··· 832 828 int ret; 833 829 struct ccw1 *ccw; 834 830 void *config_area; 831 + unsigned long flags; 835 832 836 833 ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); 837 834 if (!ccw) ··· 851 846 if (ret) 852 847 goto out_free; 853 848 849 + spin_lock_irqsave(&vcdev->lock, flags); 854 850 memcpy(vcdev->config, config_area, offset + len); 855 - if (buf) 856 - memcpy(buf, &vcdev->config[offset], len); 857 851 if (vcdev->config_ready < offset + len) 858 852 vcdev->config_ready = offset + len; 853 + spin_unlock_irqrestore(&vcdev->lock, flags); 854 + if (buf) 855 + memcpy(buf, config_area + offset, len); 859 856 860 857 out_free: 861 858 kfree(config_area); ··· 871 864 struct virtio_ccw_device *vcdev = to_vc_device(vdev); 872 865 struct ccw1 *ccw; 873 866 void *config_area; 867 + unsigned long flags; 874 868 875 869 ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); 876 870 if (!ccw) ··· 884 876 /* Make sure we don't overwrite fields. */ 885 877 if (vcdev->config_ready < offset) 886 878 virtio_ccw_get_config(vdev, 0, NULL, offset); 879 + spin_lock_irqsave(&vcdev->lock, flags); 887 880 memcpy(&vcdev->config[offset], buf, len); 888 881 /* Write the config area to the host. */ 889 882 memcpy(config_area, vcdev->config, sizeof(vcdev->config)); 883 + spin_unlock_irqrestore(&vcdev->lock, flags); 890 884 ccw->cmd_code = CCW_CMD_WRITE_CONF; 891 885 ccw->flags = 0; 892 886 ccw->count = offset + len; ··· 1257 1247 init_waitqueue_head(&vcdev->wait_q); 1258 1248 INIT_LIST_HEAD(&vcdev->virtqueues); 1259 1249 spin_lock_init(&vcdev->lock); 1250 + mutex_init(&vcdev->io_lock); 1260 1251 1261 1252 spin_lock_irqsave(get_ccwdev_lock(cdev), flags); 1262 1253 dev_set_drvdata(&cdev->dev, vcdev);
+48 -31
drivers/vhost/vsock.c
··· 15 15 #include <net/sock.h> 16 16 #include <linux/virtio_vsock.h> 17 17 #include <linux/vhost.h> 18 + #include <linux/hashtable.h> 18 19 19 20 #include <net/af_vsock.h> 20 21 #include "vhost.h" ··· 28 27 29 28 /* Used to track all the vhost_vsock instances on the system. */ 30 29 static DEFINE_SPINLOCK(vhost_vsock_lock); 31 - static LIST_HEAD(vhost_vsock_list); 30 + static DEFINE_READ_MOSTLY_HASHTABLE(vhost_vsock_hash, 8); 32 31 33 32 struct vhost_vsock { 34 33 struct vhost_dev dev; 35 34 struct vhost_virtqueue vqs[2]; 36 35 37 - /* Link to global vhost_vsock_list, protected by vhost_vsock_lock */ 38 - struct list_head list; 36 + /* Link to global vhost_vsock_hash, writes use vhost_vsock_lock */ 37 + struct hlist_node hash; 39 38 40 39 struct vhost_work send_pkt_work; 41 40 spinlock_t send_pkt_list_lock; ··· 51 50 return VHOST_VSOCK_DEFAULT_HOST_CID; 52 51 } 53 52 54 - static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid) 53 + /* Callers that dereference the return value must hold vhost_vsock_lock or the 54 + * RCU read lock. 55 + */ 56 + static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) 55 57 { 56 58 struct vhost_vsock *vsock; 57 59 58 - list_for_each_entry(vsock, &vhost_vsock_list, list) { 60 + hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid) { 59 61 u32 other_cid = vsock->guest_cid; 60 62 61 63 /* Skip instances that have no CID yet */ ··· 71 67 } 72 68 73 69 return NULL; 74 - } 75 - 76 - static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) 77 - { 78 - struct vhost_vsock *vsock; 79 - 80 - spin_lock_bh(&vhost_vsock_lock); 81 - vsock = __vhost_vsock_get(guest_cid); 82 - spin_unlock_bh(&vhost_vsock_lock); 83 - 84 - return vsock; 85 70 } 86 71 87 72 static void ··· 203 210 struct vhost_vsock *vsock; 204 211 int len = pkt->len; 205 212 213 + rcu_read_lock(); 214 + 206 215 /* Find the vhost_vsock according to guest context id */ 207 216 vsock = vhost_vsock_get(le64_to_cpu(pkt->hdr.dst_cid)); 208 217 if (!vsock) { 218 + rcu_read_unlock(); 209 219 virtio_transport_free_pkt(pkt); 210 220 return -ENODEV; 211 221 } ··· 221 225 spin_unlock_bh(&vsock->send_pkt_list_lock); 222 226 223 227 vhost_work_queue(&vsock->dev, &vsock->send_pkt_work); 228 + 229 + rcu_read_unlock(); 224 230 return len; 225 231 } 226 232 ··· 232 234 struct vhost_vsock *vsock; 233 235 struct virtio_vsock_pkt *pkt, *n; 234 236 int cnt = 0; 237 + int ret = -ENODEV; 235 238 LIST_HEAD(freeme); 239 + 240 + rcu_read_lock(); 236 241 237 242 /* Find the vhost_vsock according to guest context id */ 238 243 vsock = vhost_vsock_get(vsk->remote_addr.svm_cid); 239 244 if (!vsock) 240 - return -ENODEV; 245 + goto out; 241 246 242 247 spin_lock_bh(&vsock->send_pkt_list_lock); 243 248 list_for_each_entry_safe(pkt, n, &vsock->send_pkt_list, list) { ··· 266 265 vhost_poll_queue(&tx_vq->poll); 267 266 } 268 267 269 - return 0; 268 + ret = 0; 269 + out: 270 + rcu_read_unlock(); 271 + return ret; 270 272 } 271 273 272 274 static struct virtio_vsock_pkt * ··· 537 533 spin_lock_init(&vsock->send_pkt_list_lock); 538 534 INIT_LIST_HEAD(&vsock->send_pkt_list); 539 535 vhost_work_init(&vsock->send_pkt_work, vhost_transport_send_pkt_work); 540 - 541 - spin_lock_bh(&vhost_vsock_lock); 542 - list_add_tail(&vsock->list, &vhost_vsock_list); 543 - spin_unlock_bh(&vhost_vsock_lock); 544 536 return 0; 545 537 546 538 out: ··· 563 563 * executing. 564 564 */ 565 565 566 - if (!vhost_vsock_get(vsk->remote_addr.svm_cid)) { 567 - sock_set_flag(sk, SOCK_DONE); 568 - vsk->peer_shutdown = SHUTDOWN_MASK; 569 - sk->sk_state = SS_UNCONNECTED; 570 - sk->sk_err = ECONNRESET; 571 - sk->sk_error_report(sk); 572 - } 566 + /* If the peer is still valid, no need to reset connection */ 567 + if (vhost_vsock_get(vsk->remote_addr.svm_cid)) 568 + return; 569 + 570 + /* If the close timeout is pending, let it expire. This avoids races 571 + * with the timeout callback. 572 + */ 573 + if (vsk->close_work_scheduled) 574 + return; 575 + 576 + sock_set_flag(sk, SOCK_DONE); 577 + vsk->peer_shutdown = SHUTDOWN_MASK; 578 + sk->sk_state = SS_UNCONNECTED; 579 + sk->sk_err = ECONNRESET; 580 + sk->sk_error_report(sk); 573 581 } 574 582 575 583 static int vhost_vsock_dev_release(struct inode *inode, struct file *file) ··· 585 577 struct vhost_vsock *vsock = file->private_data; 586 578 587 579 spin_lock_bh(&vhost_vsock_lock); 588 - list_del(&vsock->list); 580 + if (vsock->guest_cid) 581 + hash_del_rcu(&vsock->hash); 589 582 spin_unlock_bh(&vhost_vsock_lock); 583 + 584 + /* Wait for other CPUs to finish using vsock */ 585 + synchronize_rcu(); 590 586 591 587 /* Iterating over all connections for all CIDs to find orphans is 592 588 * inefficient. Room for improvement here. */ ··· 632 620 633 621 /* Refuse if CID is already in use */ 634 622 spin_lock_bh(&vhost_vsock_lock); 635 - other = __vhost_vsock_get(guest_cid); 623 + other = vhost_vsock_get(guest_cid); 636 624 if (other && other != vsock) { 637 625 spin_unlock_bh(&vhost_vsock_lock); 638 626 return -EADDRINUSE; 639 627 } 628 + 629 + if (vsock->guest_cid) 630 + hash_del_rcu(&vsock->hash); 631 + 640 632 vsock->guest_cid = guest_cid; 633 + hash_add_rcu(vhost_vsock_hash, &vsock->hash, guest_cid); 641 634 spin_unlock_bh(&vhost_vsock_lock); 642 635 643 636 return 0;