@@ -131,66 +131,84 @@ static void dump_rndis_message(struct net_device *netdev,
131
131
{
132
132
switch (rndis_msg -> ndis_msg_type ) {
133
133
case RNDIS_MSG_PACKET :
134
- netdev_dbg (netdev , "RNDIS_MSG_PACKET (len %u, "
135
- "data offset %u data len %u, # oob %u, "
136
- "oob offset %u, oob len %u, pkt offset %u, "
137
- "pkt len %u\n" ,
138
- rndis_msg -> msg_len ,
139
- rndis_msg -> msg .pkt .data_offset ,
140
- rndis_msg -> msg .pkt .data_len ,
141
- rndis_msg -> msg .pkt .num_oob_data_elements ,
142
- rndis_msg -> msg .pkt .oob_data_offset ,
143
- rndis_msg -> msg .pkt .oob_data_len ,
144
- rndis_msg -> msg .pkt .per_pkt_info_offset ,
145
- rndis_msg -> msg .pkt .per_pkt_info_len );
134
+ if (rndis_msg -> msg_len - RNDIS_HEADER_SIZE >= sizeof (struct rndis_packet )) {
135
+ const struct rndis_packet * pkt = & rndis_msg -> msg .pkt ;
136
+ netdev_dbg (netdev , "RNDIS_MSG_PACKET (len %u, "
137
+ "data offset %u data len %u, # oob %u, "
138
+ "oob offset %u, oob len %u, pkt offset %u, "
139
+ "pkt len %u\n" ,
140
+ rndis_msg -> msg_len ,
141
+ pkt -> data_offset ,
142
+ pkt -> data_len ,
143
+ pkt -> num_oob_data_elements ,
144
+ pkt -> oob_data_offset ,
145
+ pkt -> oob_data_len ,
146
+ pkt -> per_pkt_info_offset ,
147
+ pkt -> per_pkt_info_len );
148
+ }
146
149
break ;
147
150
148
151
case RNDIS_MSG_INIT_C :
149
- netdev_dbg (netdev , "RNDIS_MSG_INIT_C "
150
- "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
151
- "device flags %d, max xfer size 0x%x, max pkts %u, "
152
- "pkt aligned %u)\n" ,
153
- rndis_msg -> msg_len ,
154
- rndis_msg -> msg .init_complete .req_id ,
155
- rndis_msg -> msg .init_complete .status ,
156
- rndis_msg -> msg .init_complete .major_ver ,
157
- rndis_msg -> msg .init_complete .minor_ver ,
158
- rndis_msg -> msg .init_complete .dev_flags ,
159
- rndis_msg -> msg .init_complete .max_xfer_size ,
160
- rndis_msg -> msg .init_complete .
161
- max_pkt_per_msg ,
162
- rndis_msg -> msg .init_complete .
163
- pkt_alignment_factor );
152
+ if (rndis_msg -> msg_len - RNDIS_HEADER_SIZE >=
153
+ sizeof (struct rndis_initialize_complete )) {
154
+ const struct rndis_initialize_complete * init_complete =
155
+ & rndis_msg -> msg .init_complete ;
156
+ netdev_dbg (netdev , "RNDIS_MSG_INIT_C "
157
+ "(len %u, id 0x%x, status 0x%x, major %d, minor %d, "
158
+ "device flags %d, max xfer size 0x%x, max pkts %u, "
159
+ "pkt aligned %u)\n" ,
160
+ rndis_msg -> msg_len ,
161
+ init_complete -> req_id ,
162
+ init_complete -> status ,
163
+ init_complete -> major_ver ,
164
+ init_complete -> minor_ver ,
165
+ init_complete -> dev_flags ,
166
+ init_complete -> max_xfer_size ,
167
+ init_complete -> max_pkt_per_msg ,
168
+ init_complete -> pkt_alignment_factor );
169
+ }
164
170
break ;
165
171
166
172
case RNDIS_MSG_QUERY_C :
167
- netdev_dbg (netdev , "RNDIS_MSG_QUERY_C "
168
- "(len %u, id 0x%x, status 0x%x, buf len %u, "
169
- "buf offset %u)\n" ,
170
- rndis_msg -> msg_len ,
171
- rndis_msg -> msg .query_complete .req_id ,
172
- rndis_msg -> msg .query_complete .status ,
173
- rndis_msg -> msg .query_complete .
174
- info_buflen ,
175
- rndis_msg -> msg .query_complete .
176
- info_buf_offset );
173
+ if (rndis_msg -> msg_len - RNDIS_HEADER_SIZE >=
174
+ sizeof (struct rndis_query_complete )) {
175
+ const struct rndis_query_complete * query_complete =
176
+ & rndis_msg -> msg .query_complete ;
177
+ netdev_dbg (netdev , "RNDIS_MSG_QUERY_C "
178
+ "(len %u, id 0x%x, status 0x%x, buf len %u, "
179
+ "buf offset %u)\n" ,
180
+ rndis_msg -> msg_len ,
181
+ query_complete -> req_id ,
182
+ query_complete -> status ,
183
+ query_complete -> info_buflen ,
184
+ query_complete -> info_buf_offset );
185
+ }
177
186
break ;
178
187
179
188
case RNDIS_MSG_SET_C :
180
- netdev_dbg (netdev ,
181
- "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n" ,
182
- rndis_msg -> msg_len ,
183
- rndis_msg -> msg .set_complete .req_id ,
184
- rndis_msg -> msg .set_complete .status );
189
+ if (rndis_msg -> msg_len - RNDIS_HEADER_SIZE + sizeof (struct rndis_set_complete )) {
190
+ const struct rndis_set_complete * set_complete =
191
+ & rndis_msg -> msg .set_complete ;
192
+ netdev_dbg (netdev ,
193
+ "RNDIS_MSG_SET_C (len %u, id 0x%x, status 0x%x)\n" ,
194
+ rndis_msg -> msg_len ,
195
+ set_complete -> req_id ,
196
+ set_complete -> status );
197
+ }
185
198
break ;
186
199
187
200
case RNDIS_MSG_INDICATE :
188
- netdev_dbg (netdev , "RNDIS_MSG_INDICATE "
189
- "(len %u, status 0x%x, buf len %u, buf offset %u)\n" ,
190
- rndis_msg -> msg_len ,
191
- rndis_msg -> msg .indicate_status .status ,
192
- rndis_msg -> msg .indicate_status .status_buflen ,
193
- rndis_msg -> msg .indicate_status .status_buf_offset );
201
+ if (rndis_msg -> msg_len - RNDIS_HEADER_SIZE >=
202
+ sizeof (struct rndis_indicate_status )) {
203
+ const struct rndis_indicate_status * indicate_status =
204
+ & rndis_msg -> msg .indicate_status ;
205
+ netdev_dbg (netdev , "RNDIS_MSG_INDICATE "
206
+ "(len %u, status 0x%x, buf len %u, buf offset %u)\n" ,
207
+ rndis_msg -> msg_len ,
208
+ indicate_status -> status ,
209
+ indicate_status -> status_buflen ,
210
+ indicate_status -> status_buf_offset );
211
+ }
194
212
break ;
195
213
196
214
default :
@@ -246,11 +264,20 @@ static void rndis_set_link_state(struct rndis_device *rdev,
246
264
{
247
265
u32 link_status ;
248
266
struct rndis_query_complete * query_complete ;
267
+ u32 msg_len = request -> response_msg .msg_len ;
268
+
269
+ /* Ensure the packet is big enough to access its fields */
270
+ if (msg_len - RNDIS_HEADER_SIZE < sizeof (struct rndis_query_complete ))
271
+ return ;
249
272
250
273
query_complete = & request -> response_msg .msg .query_complete ;
251
274
252
275
if (query_complete -> status == RNDIS_STATUS_SUCCESS &&
253
- query_complete -> info_buflen == sizeof (u32 )) {
276
+ query_complete -> info_buflen >= sizeof (u32 ) &&
277
+ query_complete -> info_buf_offset >= sizeof (* query_complete ) &&
278
+ msg_len - RNDIS_HEADER_SIZE >= query_complete -> info_buf_offset &&
279
+ msg_len - RNDIS_HEADER_SIZE - query_complete -> info_buf_offset
280
+ >= query_complete -> info_buflen ) {
254
281
memcpy (& link_status , (void * )((unsigned long )query_complete +
255
282
query_complete -> info_buf_offset ), sizeof (u32 ));
256
283
rdev -> link_state = link_status != 0 ;
@@ -343,7 +370,8 @@ static void rndis_filter_receive_response(struct net_device *ndev,
343
370
*/
344
371
static inline void * rndis_get_ppi (struct net_device * ndev ,
345
372
struct rndis_packet * rpkt ,
346
- u32 rpkt_len , u32 type , u8 internal )
373
+ u32 rpkt_len , u32 type , u8 internal ,
374
+ u32 ppi_size )
347
375
{
348
376
struct rndis_per_packet_info * ppi ;
349
377
int len ;
@@ -359,7 +387,8 @@ static inline void *rndis_get_ppi(struct net_device *ndev,
359
387
return NULL ;
360
388
}
361
389
362
- if (rpkt -> per_pkt_info_len > rpkt_len - rpkt -> per_pkt_info_offset ) {
390
+ if (rpkt -> per_pkt_info_len < sizeof (* ppi ) ||
391
+ rpkt -> per_pkt_info_len > rpkt_len - rpkt -> per_pkt_info_offset ) {
363
392
netdev_err (ndev , "Invalid per_pkt_info_len: %u\n" ,
364
393
rpkt -> per_pkt_info_len );
365
394
return NULL ;
@@ -381,8 +410,15 @@ static inline void *rndis_get_ppi(struct net_device *ndev,
381
410
continue ;
382
411
}
383
412
384
- if (ppi -> type == type && ppi -> internal == internal )
413
+ if (ppi -> type == type && ppi -> internal == internal ) {
414
+ /* ppi->size should be big enough to hold the returned object. */
415
+ if (ppi -> size - ppi -> ppi_offset < ppi_size ) {
416
+ netdev_err (ndev , "Invalid ppi: size %u ppi_offset %u\n" ,
417
+ ppi -> size , ppi -> ppi_offset );
418
+ continue ;
419
+ }
385
420
return (void * )((ulong )ppi + ppi -> ppi_offset );
421
+ }
386
422
len -= ppi -> size ;
387
423
ppi = (struct rndis_per_packet_info * )((ulong )ppi + ppi -> size );
388
424
}
@@ -461,13 +497,16 @@ static int rndis_filter_receive_data(struct net_device *ndev,
461
497
return NVSP_STAT_FAIL ;
462
498
}
463
499
464
- vlan = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , IEEE_8021Q_INFO , 0 );
500
+ vlan = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , IEEE_8021Q_INFO , 0 , sizeof ( * vlan ) );
465
501
466
- csum_info = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , TCPIP_CHKSUM_PKTINFO , 0 );
502
+ csum_info = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , TCPIP_CHKSUM_PKTINFO , 0 ,
503
+ sizeof (* csum_info ));
467
504
468
- hash_info = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , NBL_HASH_VALUE , 0 );
505
+ hash_info = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , NBL_HASH_VALUE , 0 ,
506
+ sizeof (* hash_info ));
469
507
470
- pktinfo_id = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , RNDIS_PKTINFO_ID , 1 );
508
+ pktinfo_id = rndis_get_ppi (ndev , rndis_pkt , rpkt_len , RNDIS_PKTINFO_ID , 1 ,
509
+ sizeof (* pktinfo_id ));
471
510
472
511
data = (void * )msg + data_offset ;
473
512
@@ -522,9 +561,6 @@ int rndis_filter_receive(struct net_device *ndev,
522
561
struct net_device_context * net_device_ctx = netdev_priv (ndev );
523
562
struct rndis_message * rndis_msg = data ;
524
563
525
- if (netif_msg_rx_status (net_device_ctx ))
526
- dump_rndis_message (ndev , rndis_msg );
527
-
528
564
/* Validate incoming rndis_message packet */
529
565
if (buflen < RNDIS_HEADER_SIZE || rndis_msg -> msg_len < RNDIS_HEADER_SIZE ||
530
566
buflen < rndis_msg -> msg_len ) {
@@ -533,6 +569,9 @@ int rndis_filter_receive(struct net_device *ndev,
533
569
return NVSP_STAT_FAIL ;
534
570
}
535
571
572
+ if (netif_msg_rx_status (net_device_ctx ))
573
+ dump_rndis_message (ndev , rndis_msg );
574
+
536
575
switch (rndis_msg -> ndis_msg_type ) {
537
576
case RNDIS_MSG_PACKET :
538
577
return rndis_filter_receive_data (ndev , net_dev , nvchan ,
@@ -567,6 +606,7 @@ static int rndis_filter_query_device(struct rndis_device *dev,
567
606
u32 inresult_size = * result_size ;
568
607
struct rndis_query_request * query ;
569
608
struct rndis_query_complete * query_complete ;
609
+ u32 msg_len ;
570
610
int ret = 0 ;
571
611
572
612
if (!result )
@@ -634,8 +674,19 @@ static int rndis_filter_query_device(struct rndis_device *dev,
634
674
635
675
/* Copy the response back */
636
676
query_complete = & request -> response_msg .msg .query_complete ;
677
+ msg_len = request -> response_msg .msg_len ;
678
+
679
+ /* Ensure the packet is big enough to access its fields */
680
+ if (msg_len - RNDIS_HEADER_SIZE < sizeof (struct rndis_query_complete )) {
681
+ ret = -1 ;
682
+ goto cleanup ;
683
+ }
637
684
638
- if (query_complete -> info_buflen > inresult_size ) {
685
+ if (query_complete -> info_buflen > inresult_size ||
686
+ query_complete -> info_buf_offset < sizeof (* query_complete ) ||
687
+ msg_len - RNDIS_HEADER_SIZE < query_complete -> info_buf_offset ||
688
+ msg_len - RNDIS_HEADER_SIZE - query_complete -> info_buf_offset
689
+ < query_complete -> info_buflen ) {
639
690
ret = -1 ;
640
691
goto cleanup ;
641
692
}
0 commit comments