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

xen/blkback: correctly respond to unknown, non-native requests

If the frontend is using a non-native protocol (e.g., a 64-bit
frontend with a 32-bit backend) and it sent an unrecognized request,
the request was not translated and the response would have the
incorrect ID. This may cause the frontend driver to behave
incorrectly or crash.

Since the ID field in the request is always in the same place,
regardless of the request type we can get the correct ID and make a
valid response (which will report BLKIF_RSP_EOPNOTSUPP).

This bug affected 64-bit SLES 11 guests when using a 32-bit backend.
This guest does a BLKIF_OP_RESERVED_1 (BLKIF_OP_PACKET in the SLES
source) and would crash in blkif_int() as the ID in the response would
be invalid.

Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Cc: stable@vger.kernel.org
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

authored by

David Vrabel and committed by
Konrad Rzeszutek Wilk
0e367ae4 a72d9002

+62 -4
+27 -4
drivers/block/xen-blkback/blkback.c
··· 679 679 return err; 680 680 } 681 681 682 + static int dispatch_other_io(struct xen_blkif *blkif, 683 + struct blkif_request *req, 684 + struct pending_req *pending_req) 685 + { 686 + free_req(pending_req); 687 + make_response(blkif, req->u.other.id, req->operation, 688 + BLKIF_RSP_EOPNOTSUPP); 689 + return -EIO; 690 + } 691 + 682 692 static void xen_blk_drain_io(struct xen_blkif *blkif) 683 693 { 684 694 atomic_set(&blkif->drain, 1); ··· 810 800 811 801 /* Apply all sanity checks to /private copy/ of request. */ 812 802 barrier(); 813 - if (unlikely(req.operation == BLKIF_OP_DISCARD)) { 803 + 804 + switch (req.operation) { 805 + case BLKIF_OP_READ: 806 + case BLKIF_OP_WRITE: 807 + case BLKIF_OP_WRITE_BARRIER: 808 + case BLKIF_OP_FLUSH_DISKCACHE: 809 + if (dispatch_rw_block_io(blkif, &req, pending_req)) 810 + goto done; 811 + break; 812 + case BLKIF_OP_DISCARD: 814 813 free_req(pending_req); 815 814 if (dispatch_discard_io(blkif, &req)) 816 - break; 817 - } else if (dispatch_rw_block_io(blkif, &req, pending_req)) 815 + goto done; 818 816 break; 817 + default: 818 + if (dispatch_other_io(blkif, &req, pending_req)) 819 + goto done; 820 + break; 821 + } 819 822 820 823 /* Yield point for this unbounded loop. */ 821 824 cond_resched(); 822 825 } 823 - 826 + done: 824 827 return more_to_do; 825 828 } 826 829
+25
drivers/block/xen-blkback/common.h
··· 77 77 uint64_t nr_sectors; 78 78 } __attribute__((__packed__)); 79 79 80 + struct blkif_x86_32_request_other { 81 + uint8_t _pad1; 82 + blkif_vdev_t _pad2; 83 + uint64_t id; /* private guest value, echoed in resp */ 84 + } __attribute__((__packed__)); 85 + 80 86 struct blkif_x86_32_request { 81 87 uint8_t operation; /* BLKIF_OP_??? */ 82 88 union { 83 89 struct blkif_x86_32_request_rw rw; 84 90 struct blkif_x86_32_request_discard discard; 91 + struct blkif_x86_32_request_other other; 85 92 } u; 86 93 } __attribute__((__packed__)); 87 94 ··· 120 113 uint64_t nr_sectors; 121 114 } __attribute__((__packed__)); 122 115 116 + struct blkif_x86_64_request_other { 117 + uint8_t _pad1; 118 + blkif_vdev_t _pad2; 119 + uint32_t _pad3; /* offsetof(blkif_..,u.discard.id)==8 */ 120 + uint64_t id; /* private guest value, echoed in resp */ 121 + } __attribute__((__packed__)); 122 + 123 123 struct blkif_x86_64_request { 124 124 uint8_t operation; /* BLKIF_OP_??? */ 125 125 union { 126 126 struct blkif_x86_64_request_rw rw; 127 127 struct blkif_x86_64_request_discard discard; 128 + struct blkif_x86_64_request_other other; 128 129 } u; 129 130 } __attribute__((__packed__)); 130 131 ··· 293 278 dst->u.discard.nr_sectors = src->u.discard.nr_sectors; 294 279 break; 295 280 default: 281 + /* 282 + * Don't know how to translate this op. Only get the 283 + * ID so failure can be reported to the frontend. 284 + */ 285 + dst->u.other.id = src->u.other.id; 296 286 break; 297 287 } 298 288 } ··· 329 309 dst->u.discard.nr_sectors = src->u.discard.nr_sectors; 330 310 break; 331 311 default: 312 + /* 313 + * Don't know how to translate this op. Only get the 314 + * ID so failure can be reported to the frontend. 315 + */ 316 + dst->u.other.id = src->u.other.id; 332 317 break; 333 318 } 334 319 }
+10
include/xen/interface/io/blkif.h
··· 138 138 uint8_t _pad3; 139 139 } __attribute__((__packed__)); 140 140 141 + struct blkif_request_other { 142 + uint8_t _pad1; 143 + blkif_vdev_t _pad2; /* only for read/write requests */ 144 + #ifdef CONFIG_X86_64 145 + uint32_t _pad3; /* offsetof(blkif_req..,u.other.id)==8*/ 146 + #endif 147 + uint64_t id; /* private guest value, echoed in resp */ 148 + } __attribute__((__packed__)); 149 + 141 150 struct blkif_request { 142 151 uint8_t operation; /* BLKIF_OP_??? */ 143 152 union { 144 153 struct blkif_request_rw rw; 145 154 struct blkif_request_discard discard; 155 + struct blkif_request_other other; 146 156 } u; 147 157 } __attribute__((__packed__)); 148 158