13bdb738bSJohn Levon /* 23bdb738bSJohn Levon * vfio protocol over a UNIX socket device handling. 33bdb738bSJohn Levon * 43bdb738bSJohn Levon * Copyright © 2018, 2021 Oracle and/or its affiliates. 53bdb738bSJohn Levon * 63bdb738bSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later 73bdb738bSJohn Levon */ 83bdb738bSJohn Levon 93bdb738bSJohn Levon #include "qemu/osdep.h" 103bdb738bSJohn Levon #include "qapi/error.h" 113bdb738bSJohn Levon #include "qemu/error-report.h" 123bdb738bSJohn Levon 133bdb738bSJohn Levon #include "hw/vfio-user/device.h" 143bdb738bSJohn Levon #include "hw/vfio-user/trace.h" 153bdb738bSJohn Levon 163bdb738bSJohn Levon /* 173bdb738bSJohn Levon * These are to defend against a malign server trying 183bdb738bSJohn Levon * to force us to run out of memory. 193bdb738bSJohn Levon */ 203bdb738bSJohn Levon #define VFIO_USER_MAX_REGIONS 100 213bdb738bSJohn Levon #define VFIO_USER_MAX_IRQS 50 223bdb738bSJohn Levon 233bdb738bSJohn Levon bool vfio_user_get_device_info(VFIOUserProxy *proxy, 243bdb738bSJohn Levon struct vfio_device_info *info, Error **errp) 253bdb738bSJohn Levon { 263bdb738bSJohn Levon VFIOUserDeviceInfo msg; 273bdb738bSJohn Levon uint32_t argsz = sizeof(msg) - sizeof(msg.hdr); 283bdb738bSJohn Levon 293bdb738bSJohn Levon memset(&msg, 0, sizeof(msg)); 303bdb738bSJohn Levon vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_INFO, sizeof(msg), 0); 313bdb738bSJohn Levon msg.argsz = argsz; 323bdb738bSJohn Levon 333bdb738bSJohn Levon if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, errp)) { 343bdb738bSJohn Levon return false; 353bdb738bSJohn Levon } 363bdb738bSJohn Levon 373bdb738bSJohn Levon if (msg.hdr.flags & VFIO_USER_ERROR) { 383bdb738bSJohn Levon error_setg_errno(errp, -msg.hdr.error_reply, 393bdb738bSJohn Levon "VFIO_USER_DEVICE_GET_INFO failed"); 403bdb738bSJohn Levon return false; 413bdb738bSJohn Levon } 423bdb738bSJohn Levon 433bdb738bSJohn Levon trace_vfio_user_get_info(msg.num_regions, msg.num_irqs); 443bdb738bSJohn Levon 453bdb738bSJohn Levon memcpy(info, &msg.argsz, argsz); 463bdb738bSJohn Levon 473bdb738bSJohn Levon /* defend against a malicious server */ 483bdb738bSJohn Levon if (info->num_regions > VFIO_USER_MAX_REGIONS || 493bdb738bSJohn Levon info->num_irqs > VFIO_USER_MAX_IRQS) { 503bdb738bSJohn Levon error_setg_errno(errp, EINVAL, "invalid reply"); 513bdb738bSJohn Levon return false; 523bdb738bSJohn Levon } 533bdb738bSJohn Levon 543bdb738bSJohn Levon return true; 553bdb738bSJohn Levon } 56667866d6SJohn Levon 57667866d6SJohn Levon static int vfio_user_get_region_info(VFIOUserProxy *proxy, 58667866d6SJohn Levon struct vfio_region_info *info, 59667866d6SJohn Levon VFIOUserFDs *fds) 60667866d6SJohn Levon { 61667866d6SJohn Levon g_autofree VFIOUserRegionInfo *msgp = NULL; 62667866d6SJohn Levon Error *local_err = NULL; 63667866d6SJohn Levon uint32_t size; 64667866d6SJohn Levon 65667866d6SJohn Levon /* data returned can be larger than vfio_region_info */ 66667866d6SJohn Levon if (info->argsz < sizeof(*info)) { 67667866d6SJohn Levon error_printf("vfio_user_get_region_info argsz too small\n"); 68667866d6SJohn Levon return -E2BIG; 69667866d6SJohn Levon } 70667866d6SJohn Levon if (fds != NULL && fds->send_fds != 0) { 71667866d6SJohn Levon error_printf("vfio_user_get_region_info can't send FDs\n"); 72667866d6SJohn Levon return -EINVAL; 73667866d6SJohn Levon } 74667866d6SJohn Levon 75667866d6SJohn Levon size = info->argsz + sizeof(VFIOUserHdr); 76667866d6SJohn Levon msgp = g_malloc0(size); 77667866d6SJohn Levon 78667866d6SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_INFO, 79667866d6SJohn Levon sizeof(*msgp), 0); 80667866d6SJohn Levon msgp->argsz = info->argsz; 81667866d6SJohn Levon msgp->index = info->index; 82667866d6SJohn Levon 83667866d6SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, fds, size, &local_err)) { 84667866d6SJohn Levon error_prepend(&local_err, "%s: ", __func__); 85667866d6SJohn Levon error_report_err(local_err); 86667866d6SJohn Levon return -EFAULT; 87667866d6SJohn Levon } 88667866d6SJohn Levon 89667866d6SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 90667866d6SJohn Levon return -msgp->hdr.error_reply; 91667866d6SJohn Levon } 92667866d6SJohn Levon trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size); 93667866d6SJohn Levon 94667866d6SJohn Levon memcpy(info, &msgp->argsz, info->argsz); 95667866d6SJohn Levon return 0; 96667866d6SJohn Levon } 97667866d6SJohn Levon 98667866d6SJohn Levon 99667866d6SJohn Levon static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev, 100667866d6SJohn Levon struct vfio_region_info *info, 101667866d6SJohn Levon int *fd) 102667866d6SJohn Levon { 103667866d6SJohn Levon VFIOUserFDs fds = { 0, 1, fd}; 104667866d6SJohn Levon int ret; 105667866d6SJohn Levon 106667866d6SJohn Levon if (info->index > vbasedev->num_regions) { 107667866d6SJohn Levon return -EINVAL; 108667866d6SJohn Levon } 109667866d6SJohn Levon 110667866d6SJohn Levon ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds); 111667866d6SJohn Levon if (ret) { 112667866d6SJohn Levon return ret; 113667866d6SJohn Levon } 114667866d6SJohn Levon 115667866d6SJohn Levon /* cap_offset in valid area */ 116667866d6SJohn Levon if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) && 117667866d6SJohn Levon (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) { 118667866d6SJohn Levon return -EINVAL; 119667866d6SJohn Levon } 120667866d6SJohn Levon 121667866d6SJohn Levon return 0; 122667866d6SJohn Levon } 123667866d6SJohn Levon 124*ca1add16SJohn Levon static int vfio_user_device_io_get_irq_info(VFIODevice *vbasedev, 125*ca1add16SJohn Levon struct vfio_irq_info *info) 126*ca1add16SJohn Levon { 127*ca1add16SJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 128*ca1add16SJohn Levon Error *local_err = NULL; 129*ca1add16SJohn Levon VFIOUserIRQInfo msg; 130*ca1add16SJohn Levon 131*ca1add16SJohn Levon memset(&msg, 0, sizeof(msg)); 132*ca1add16SJohn Levon vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_IRQ_INFO, 133*ca1add16SJohn Levon sizeof(msg), 0); 134*ca1add16SJohn Levon msg.argsz = info->argsz; 135*ca1add16SJohn Levon msg.index = info->index; 136*ca1add16SJohn Levon 137*ca1add16SJohn Levon if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, &local_err)) { 138*ca1add16SJohn Levon error_prepend(&local_err, "%s: ", __func__); 139*ca1add16SJohn Levon error_report_err(local_err); 140*ca1add16SJohn Levon return -EFAULT; 141*ca1add16SJohn Levon } 142*ca1add16SJohn Levon 143*ca1add16SJohn Levon if (msg.hdr.flags & VFIO_USER_ERROR) { 144*ca1add16SJohn Levon return -msg.hdr.error_reply; 145*ca1add16SJohn Levon } 146*ca1add16SJohn Levon trace_vfio_user_get_irq_info(msg.index, msg.flags, msg.count); 147*ca1add16SJohn Levon 148*ca1add16SJohn Levon memcpy(info, &msg.argsz, sizeof(*info)); 149*ca1add16SJohn Levon return 0; 150*ca1add16SJohn Levon } 151*ca1add16SJohn Levon 152*ca1add16SJohn Levon static int irq_howmany(int *fdp, uint32_t cur, uint32_t max) 153*ca1add16SJohn Levon { 154*ca1add16SJohn Levon int n = 0; 155*ca1add16SJohn Levon 156*ca1add16SJohn Levon if (fdp[cur] != -1) { 157*ca1add16SJohn Levon do { 158*ca1add16SJohn Levon n++; 159*ca1add16SJohn Levon } while (n < max && fdp[cur + n] != -1); 160*ca1add16SJohn Levon } else { 161*ca1add16SJohn Levon do { 162*ca1add16SJohn Levon n++; 163*ca1add16SJohn Levon } while (n < max && fdp[cur + n] == -1); 164*ca1add16SJohn Levon } 165*ca1add16SJohn Levon 166*ca1add16SJohn Levon return n; 167*ca1add16SJohn Levon } 168*ca1add16SJohn Levon 169*ca1add16SJohn Levon static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev, 170*ca1add16SJohn Levon struct vfio_irq_set *irq) 171*ca1add16SJohn Levon { 172*ca1add16SJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 173*ca1add16SJohn Levon g_autofree VFIOUserIRQSet *msgp = NULL; 174*ca1add16SJohn Levon uint32_t size, nfds, send_fds, sent_fds, max; 175*ca1add16SJohn Levon Error *local_err = NULL; 176*ca1add16SJohn Levon 177*ca1add16SJohn Levon if (irq->argsz < sizeof(*irq)) { 178*ca1add16SJohn Levon error_printf("vfio_user_set_irqs argsz too small\n"); 179*ca1add16SJohn Levon return -EINVAL; 180*ca1add16SJohn Levon } 181*ca1add16SJohn Levon 182*ca1add16SJohn Levon /* 183*ca1add16SJohn Levon * Handle simple case 184*ca1add16SJohn Levon */ 185*ca1add16SJohn Levon if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) { 186*ca1add16SJohn Levon size = sizeof(VFIOUserHdr) + irq->argsz; 187*ca1add16SJohn Levon msgp = g_malloc0(size); 188*ca1add16SJohn Levon 189*ca1add16SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0); 190*ca1add16SJohn Levon msgp->argsz = irq->argsz; 191*ca1add16SJohn Levon msgp->flags = irq->flags; 192*ca1add16SJohn Levon msgp->index = irq->index; 193*ca1add16SJohn Levon msgp->start = irq->start; 194*ca1add16SJohn Levon msgp->count = irq->count; 195*ca1add16SJohn Levon trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count, 196*ca1add16SJohn Levon msgp->flags); 197*ca1add16SJohn Levon 198*ca1add16SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) { 199*ca1add16SJohn Levon error_prepend(&local_err, "%s: ", __func__); 200*ca1add16SJohn Levon error_report_err(local_err); 201*ca1add16SJohn Levon return -EFAULT; 202*ca1add16SJohn Levon } 203*ca1add16SJohn Levon 204*ca1add16SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 205*ca1add16SJohn Levon return -msgp->hdr.error_reply; 206*ca1add16SJohn Levon } 207*ca1add16SJohn Levon 208*ca1add16SJohn Levon return 0; 209*ca1add16SJohn Levon } 210*ca1add16SJohn Levon 211*ca1add16SJohn Levon /* 212*ca1add16SJohn Levon * Calculate the number of FDs to send 213*ca1add16SJohn Levon * and adjust argsz 214*ca1add16SJohn Levon */ 215*ca1add16SJohn Levon nfds = (irq->argsz - sizeof(*irq)) / sizeof(int); 216*ca1add16SJohn Levon irq->argsz = sizeof(*irq); 217*ca1add16SJohn Levon msgp = g_malloc0(sizeof(*msgp)); 218*ca1add16SJohn Levon /* 219*ca1add16SJohn Levon * Send in chunks if over max_send_fds 220*ca1add16SJohn Levon */ 221*ca1add16SJohn Levon for (sent_fds = 0; nfds > sent_fds; sent_fds += send_fds) { 222*ca1add16SJohn Levon VFIOUserFDs *arg_fds, loop_fds; 223*ca1add16SJohn Levon 224*ca1add16SJohn Levon /* must send all valid FDs or all invalid FDs in single msg */ 225*ca1add16SJohn Levon max = nfds - sent_fds; 226*ca1add16SJohn Levon if (max > proxy->max_send_fds) { 227*ca1add16SJohn Levon max = proxy->max_send_fds; 228*ca1add16SJohn Levon } 229*ca1add16SJohn Levon send_fds = irq_howmany((int *)irq->data, sent_fds, max); 230*ca1add16SJohn Levon 231*ca1add16SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, 232*ca1add16SJohn Levon sizeof(*msgp), 0); 233*ca1add16SJohn Levon msgp->argsz = irq->argsz; 234*ca1add16SJohn Levon msgp->flags = irq->flags; 235*ca1add16SJohn Levon msgp->index = irq->index; 236*ca1add16SJohn Levon msgp->start = irq->start + sent_fds; 237*ca1add16SJohn Levon msgp->count = send_fds; 238*ca1add16SJohn Levon trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count, 239*ca1add16SJohn Levon msgp->flags); 240*ca1add16SJohn Levon 241*ca1add16SJohn Levon loop_fds.send_fds = send_fds; 242*ca1add16SJohn Levon loop_fds.recv_fds = 0; 243*ca1add16SJohn Levon loop_fds.fds = (int *)irq->data + sent_fds; 244*ca1add16SJohn Levon arg_fds = loop_fds.fds[0] != -1 ? &loop_fds : NULL; 245*ca1add16SJohn Levon 246*ca1add16SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, arg_fds, 0, &local_err)) { 247*ca1add16SJohn Levon error_prepend(&local_err, "%s: ", __func__); 248*ca1add16SJohn Levon error_report_err(local_err); 249*ca1add16SJohn Levon return -EFAULT; 250*ca1add16SJohn Levon } 251*ca1add16SJohn Levon 252*ca1add16SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 253*ca1add16SJohn Levon return -msgp->hdr.error_reply; 254*ca1add16SJohn Levon } 255*ca1add16SJohn Levon } 256*ca1add16SJohn Levon 257*ca1add16SJohn Levon return 0; 258*ca1add16SJohn Levon } 259*ca1add16SJohn Levon 2601ed50fcbSJohn Levon static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index, 2611ed50fcbSJohn Levon off_t off, uint32_t count, 2621ed50fcbSJohn Levon void *data) 2631ed50fcbSJohn Levon { 2641ed50fcbSJohn Levon g_autofree VFIOUserRegionRW *msgp = NULL; 2651ed50fcbSJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 2661ed50fcbSJohn Levon int size = sizeof(*msgp) + count; 2671ed50fcbSJohn Levon Error *local_err = NULL; 2681ed50fcbSJohn Levon 2691ed50fcbSJohn Levon if (count > proxy->max_xfer_size) { 2701ed50fcbSJohn Levon return -EINVAL; 2711ed50fcbSJohn Levon } 2721ed50fcbSJohn Levon 2731ed50fcbSJohn Levon msgp = g_malloc0(size); 2741ed50fcbSJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0); 2751ed50fcbSJohn Levon msgp->offset = off; 2761ed50fcbSJohn Levon msgp->region = index; 2771ed50fcbSJohn Levon msgp->count = count; 2781ed50fcbSJohn Levon trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count); 2791ed50fcbSJohn Levon 2801ed50fcbSJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) { 2811ed50fcbSJohn Levon error_prepend(&local_err, "%s: ", __func__); 2821ed50fcbSJohn Levon error_report_err(local_err); 2831ed50fcbSJohn Levon return -EFAULT; 2841ed50fcbSJohn Levon } 2851ed50fcbSJohn Levon 2861ed50fcbSJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 2871ed50fcbSJohn Levon return -msgp->hdr.error_reply; 2881ed50fcbSJohn Levon } else if (msgp->count > count) { 2891ed50fcbSJohn Levon return -E2BIG; 2901ed50fcbSJohn Levon } else { 2911ed50fcbSJohn Levon memcpy(data, &msgp->data, msgp->count); 2921ed50fcbSJohn Levon } 2931ed50fcbSJohn Levon 2941ed50fcbSJohn Levon return msgp->count; 2951ed50fcbSJohn Levon } 2961ed50fcbSJohn Levon 2971ed50fcbSJohn Levon static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index, 2981ed50fcbSJohn Levon off_t off, unsigned count, 2991ed50fcbSJohn Levon void *data, bool post) 3001ed50fcbSJohn Levon { 3011ed50fcbSJohn Levon g_autofree VFIOUserRegionRW *msgp = NULL; 3021ed50fcbSJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 3031ed50fcbSJohn Levon int size = sizeof(*msgp) + count; 3041ed50fcbSJohn Levon Error *local_err = NULL; 3051ed50fcbSJohn Levon int ret; 3061ed50fcbSJohn Levon 3071ed50fcbSJohn Levon if (count > proxy->max_xfer_size) { 3081ed50fcbSJohn Levon return -EINVAL; 3091ed50fcbSJohn Levon } 3101ed50fcbSJohn Levon 3111ed50fcbSJohn Levon msgp = g_malloc0(size); 3121ed50fcbSJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, 0); 3131ed50fcbSJohn Levon msgp->offset = off; 3141ed50fcbSJohn Levon msgp->region = index; 3151ed50fcbSJohn Levon msgp->count = count; 3161ed50fcbSJohn Levon memcpy(&msgp->data, data, count); 3171ed50fcbSJohn Levon trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count); 3181ed50fcbSJohn Levon 3191ed50fcbSJohn Levon /* Ignore post: all writes are synchronous/non-posted. */ 3201ed50fcbSJohn Levon 3211ed50fcbSJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) { 3221ed50fcbSJohn Levon error_prepend(&local_err, "%s: ", __func__); 3231ed50fcbSJohn Levon error_report_err(local_err); 3241ed50fcbSJohn Levon return -EFAULT; 3251ed50fcbSJohn Levon } 3261ed50fcbSJohn Levon 3271ed50fcbSJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 3281ed50fcbSJohn Levon ret = -msgp->hdr.error_reply; 3291ed50fcbSJohn Levon } else { 3301ed50fcbSJohn Levon ret = count; 3311ed50fcbSJohn Levon } 3321ed50fcbSJohn Levon 3331ed50fcbSJohn Levon return ret; 3341ed50fcbSJohn Levon } 3351ed50fcbSJohn Levon 336667866d6SJohn Levon /* 337667866d6SJohn Levon * Socket-based io_ops 338667866d6SJohn Levon */ 339667866d6SJohn Levon VFIODeviceIOOps vfio_user_device_io_ops_sock = { 340667866d6SJohn Levon .get_region_info = vfio_user_device_io_get_region_info, 341*ca1add16SJohn Levon .get_irq_info = vfio_user_device_io_get_irq_info, 342*ca1add16SJohn Levon .set_irqs = vfio_user_device_io_set_irqs, 3431ed50fcbSJohn Levon .region_read = vfio_user_device_io_region_read, 3441ed50fcbSJohn Levon .region_write = vfio_user_device_io_region_write, 3451ed50fcbSJohn Levon 346667866d6SJohn Levon }; 347