@@ -1178,20 +1178,39 @@ static int netvsc_receive(struct net_device *ndev,
1178
1178
}
1179
1179
1180
1180
static void netvsc_send_table (struct net_device * ndev ,
1181
- const struct nvsp_message * nvmsg )
1181
+ struct netvsc_device * nvscdev ,
1182
+ const struct nvsp_message * nvmsg ,
1183
+ u32 msglen )
1182
1184
{
1183
1185
struct net_device_context * net_device_ctx = netdev_priv (ndev );
1184
- u32 count , * tab ;
1186
+ u32 count , offset , * tab ;
1185
1187
int i ;
1186
1188
1187
1189
count = nvmsg -> msg .v5_msg .send_table .count ;
1190
+ offset = nvmsg -> msg .v5_msg .send_table .offset ;
1191
+
1188
1192
if (count != VRSS_SEND_TAB_SIZE ) {
1189
1193
netdev_err (ndev , "Received wrong send-table size:%u\n" , count );
1190
1194
return ;
1191
1195
}
1192
1196
1193
- tab = (u32 * )((unsigned long )& nvmsg -> msg .v5_msg .send_table +
1194
- nvmsg -> msg .v5_msg .send_table .offset );
1197
+ /* If negotiated version <= NVSP_PROTOCOL_VERSION_6, the offset may be
1198
+ * wrong due to a host bug. So fix the offset here.
1199
+ */
1200
+ if (nvscdev -> nvsp_version <= NVSP_PROTOCOL_VERSION_6 &&
1201
+ msglen >= sizeof (struct nvsp_message_header ) +
1202
+ sizeof (union nvsp_6_message_uber ) + count * sizeof (u32 ))
1203
+ offset = sizeof (struct nvsp_message_header ) +
1204
+ sizeof (union nvsp_6_message_uber );
1205
+
1206
+ /* Boundary check for all versions */
1207
+ if (offset > msglen - count * sizeof (u32 )) {
1208
+ netdev_err (ndev , "Received send-table offset too big:%u\n" ,
1209
+ offset );
1210
+ return ;
1211
+ }
1212
+
1213
+ tab = (void * )nvmsg + offset ;
1195
1214
1196
1215
for (i = 0 ; i < count ; i ++ )
1197
1216
net_device_ctx -> tx_table [i ] = tab [i ];
@@ -1209,12 +1228,14 @@ static void netvsc_send_vf(struct net_device *ndev,
1209
1228
net_device_ctx -> vf_alloc ? "added" : "removed" );
1210
1229
}
1211
1230
1212
- static void netvsc_receive_inband (struct net_device * ndev ,
1213
- const struct nvsp_message * nvmsg )
1231
+ static void netvsc_receive_inband (struct net_device * ndev ,
1232
+ struct netvsc_device * nvscdev ,
1233
+ const struct nvsp_message * nvmsg ,
1234
+ u32 msglen )
1214
1235
{
1215
1236
switch (nvmsg -> hdr .msg_type ) {
1216
1237
case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE :
1217
- netvsc_send_table (ndev , nvmsg );
1238
+ netvsc_send_table (ndev , nvscdev , nvmsg , msglen );
1218
1239
break ;
1219
1240
1220
1241
case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION :
@@ -1232,6 +1253,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
1232
1253
{
1233
1254
struct vmbus_channel * channel = nvchan -> channel ;
1234
1255
const struct nvsp_message * nvmsg = hv_pkt_data (desc );
1256
+ u32 msglen = hv_pkt_datalen (desc );
1235
1257
1236
1258
trace_nvsp_recv (ndev , channel , nvmsg );
1237
1259
@@ -1247,7 +1269,7 @@ static int netvsc_process_raw_pkt(struct hv_device *device,
1247
1269
break ;
1248
1270
1249
1271
case VM_PKT_DATA_INBAND :
1250
- netvsc_receive_inband (ndev , nvmsg );
1272
+ netvsc_receive_inband (ndev , net_device , nvmsg , msglen );
1251
1273
break ;
1252
1274
1253
1275
default :
0 commit comments