diff options
author | Andres Beltran <lkmlabelt@gmail.com> | 2020-11-09 11:07:04 +0100 |
---|---|---|
committer | Wei Liu <wei.liu@kernel.org> | 2021-02-05 10:55:42 +0100 |
commit | 06caa778d8b2fbcb4ac3878751e39d116424ba9b (patch) | |
tree | f000d7887567b34e15a3193cf831589c5365c838 /drivers/hv/hv_snapshot.c | |
parent | Drivers: hv: vmbus: Copy packets sent by Hyper-V out of the ring buffer (diff) | |
download | linux-06caa778d8b2fbcb4ac3878751e39d116424ba9b.tar.xz linux-06caa778d8b2fbcb4ac3878751e39d116424ba9b.zip |
hv_utils: Add validation for untrusted Hyper-V values
For additional robustness in the face of Hyper-V errors or malicious
behavior, validate all values that originate from packets that Hyper-V
has sent to the guest in the host-to-guest ring buffer. Ensure that
invalid values cannot cause indexing off the end of the icversion_data
array in vmbus_prep_negotiate_resp().
Signed-off-by: Andres Beltran <lkmlabelt@gmail.com>
Co-developed-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Link: https://lore.kernel.org/r/20201109100704.9152-1-parri.andrea@gmail.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Diffstat (limited to 'drivers/hv/hv_snapshot.c')
-rw-r--r-- | drivers/hv/hv_snapshot.c | 89 |
1 files changed, 52 insertions, 37 deletions
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 783779e4cc1a..2267bd4c3472 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -298,49 +298,64 @@ void hv_vss_onchannelcallback(void *context) if (vss_transaction.state > HVUTIL_READY) return; - vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, - &requestid); - - if (recvlen > 0) { - icmsghdrp = (struct icmsg_hdr *)&recv_buffer[ - sizeof(struct vmbuspipe_hdr)]; - - if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { - if (vmbus_prep_negotiate_resp(icmsghdrp, - recv_buffer, fw_versions, FW_VER_COUNT, - vss_versions, VSS_VER_COUNT, - NULL, &vss_srv_version)) { - - pr_info("VSS IC version %d.%d\n", - vss_srv_version >> 16, - vss_srv_version & 0xFFFF); - } - } else { - vss_msg = (struct hv_vss_msg *)&recv_buffer[ - sizeof(struct vmbuspipe_hdr) + - sizeof(struct icmsg_hdr)]; - - /* - * Stash away this global state for completing the - * transaction; note transactions are serialized. - */ - - vss_transaction.recv_len = recvlen; - vss_transaction.recv_req_id = requestid; - vss_transaction.msg = (struct hv_vss_msg *)vss_msg; - - schedule_work(&vss_handle_request_work); + if (vmbus_recvpacket(channel, recv_buffer, HV_HYP_PAGE_SIZE * 2, &recvlen, &requestid)) { + pr_err_ratelimited("VSS request received. Could not read into recv buf\n"); + return; + } + + if (!recvlen) + return; + + /* Ensure recvlen is big enough to read header data */ + if (recvlen < ICMSG_HDR) { + pr_err_ratelimited("VSS request received. Packet length too small: %d\n", + recvlen); + return; + } + + icmsghdrp = (struct icmsg_hdr *)&recv_buffer[sizeof(struct vmbuspipe_hdr)]; + + if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { + if (vmbus_prep_negotiate_resp(icmsghdrp, + recv_buffer, recvlen, + fw_versions, FW_VER_COUNT, + vss_versions, VSS_VER_COUNT, + NULL, &vss_srv_version)) { + + pr_info("VSS IC version %d.%d\n", + vss_srv_version >> 16, + vss_srv_version & 0xFFFF); + } + } else if (icmsghdrp->icmsgtype == ICMSGTYPE_VSS) { + /* Ensure recvlen is big enough to contain hv_vss_msg */ + if (recvlen < ICMSG_HDR + sizeof(struct hv_vss_msg)) { + pr_err_ratelimited("Invalid VSS msg. Packet length too small: %u\n", + recvlen); return; } + vss_msg = (struct hv_vss_msg *)&recv_buffer[ICMSG_HDR]; + + /* + * Stash away this global state for completing the + * transaction; note transactions are serialized. + */ - icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION - | ICMSGHDRFLAG_RESPONSE; + vss_transaction.recv_len = recvlen; + vss_transaction.recv_req_id = requestid; + vss_transaction.msg = (struct hv_vss_msg *)vss_msg; - vmbus_sendpacket(channel, recv_buffer, - recvlen, requestid, - VM_PKT_DATA_INBAND, 0); + schedule_work(&vss_handle_request_work); + return; + } else { + pr_err_ratelimited("VSS request received. Invalid msg type: %d\n", + icmsghdrp->icmsgtype); + return; } + icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION | + ICMSGHDRFLAG_RESPONSE; + vmbus_sendpacket(channel, recv_buffer, recvlen, requestid, + VM_PKT_DATA_INBAND, 0); } static void vss_on_reset(void) |