| .. | .. |
|---|
| 30 | 30 | hdr->endpoint_id = epid; |
|---|
| 31 | 31 | hdr->flags = flags; |
|---|
| 32 | 32 | hdr->payload_len = cpu_to_be16(len); |
|---|
| 33 | + memset(hdr->control, 0, sizeof(hdr->control)); |
|---|
| 33 | 34 | |
|---|
| 34 | 35 | status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb); |
|---|
| 35 | 36 | |
|---|
| .. | .. |
|---|
| 113 | 114 | |
|---|
| 114 | 115 | if (svc_rspmsg->status == HTC_SERVICE_SUCCESS) { |
|---|
| 115 | 116 | epid = svc_rspmsg->endpoint_id; |
|---|
| 116 | | - if (epid < 0 || epid >= ENDPOINT_MAX) |
|---|
| 117 | + |
|---|
| 118 | + /* Check that the received epid for the endpoint to attach |
|---|
| 119 | + * a new service is valid. ENDPOINT0 can't be used here as it |
|---|
| 120 | + * is already reserved for HTC_CTRL_RSVD_SVC service and thus |
|---|
| 121 | + * should not be modified. |
|---|
| 122 | + */ |
|---|
| 123 | + if (epid <= ENDPOINT0 || epid >= ENDPOINT_MAX) |
|---|
| 117 | 124 | return; |
|---|
| 118 | 125 | |
|---|
| 119 | 126 | service_id = be16_to_cpu(svc_rspmsg->service_id); |
|---|
| .. | .. |
|---|
| 173 | 180 | time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); |
|---|
| 174 | 181 | if (!time_left) { |
|---|
| 175 | 182 | dev_err(target->dev, "HTC credit config timeout\n"); |
|---|
| 176 | | - kfree_skb(skb); |
|---|
| 177 | 183 | return -ETIMEDOUT; |
|---|
| 178 | 184 | } |
|---|
| 179 | 185 | |
|---|
| .. | .. |
|---|
| 209 | 215 | time_left = wait_for_completion_timeout(&target->cmd_wait, HZ); |
|---|
| 210 | 216 | if (!time_left) { |
|---|
| 211 | 217 | dev_err(target->dev, "HTC start timeout\n"); |
|---|
| 212 | | - kfree_skb(skb); |
|---|
| 213 | 218 | return -ETIMEDOUT; |
|---|
| 214 | 219 | } |
|---|
| 215 | 220 | |
|---|
| .. | .. |
|---|
| 274 | 279 | conn_msg->dl_pipeid = endpoint->dl_pipeid; |
|---|
| 275 | 280 | conn_msg->ul_pipeid = endpoint->ul_pipeid; |
|---|
| 276 | 281 | |
|---|
| 282 | + /* To prevent infoleak */ |
|---|
| 283 | + conn_msg->svc_meta_len = 0; |
|---|
| 284 | + conn_msg->pad = 0; |
|---|
| 285 | + |
|---|
| 277 | 286 | ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0); |
|---|
| 278 | 287 | if (ret) |
|---|
| 279 | 288 | goto err; |
|---|
| .. | .. |
|---|
| 282 | 291 | if (!time_left) { |
|---|
| 283 | 292 | dev_err(target->dev, "Service connection timeout for: %d\n", |
|---|
| 284 | 293 | service_connreq->service_id); |
|---|
| 285 | | - kfree_skb(skb); |
|---|
| 286 | 294 | return -ETIMEDOUT; |
|---|
| 287 | 295 | } |
|---|
| 288 | 296 | |
|---|
| .. | .. |
|---|
| 362 | 370 | } |
|---|
| 363 | 371 | |
|---|
| 364 | 372 | static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle, |
|---|
| 365 | | - struct sk_buff *skb) |
|---|
| 373 | + struct sk_buff *skb, u32 len) |
|---|
| 366 | 374 | { |
|---|
| 367 | 375 | uint32_t *pattern = (uint32_t *)skb->data; |
|---|
| 368 | 376 | |
|---|
| 369 | | - switch (*pattern) { |
|---|
| 370 | | - case 0x33221199: |
|---|
| 371 | | - { |
|---|
| 377 | + if (*pattern == 0x33221199 && len >= sizeof(struct htc_panic_bad_vaddr)) { |
|---|
| 372 | 378 | struct htc_panic_bad_vaddr *htc_panic; |
|---|
| 373 | 379 | htc_panic = (struct htc_panic_bad_vaddr *) skb->data; |
|---|
| 374 | 380 | dev_err(htc_handle->dev, "ath: firmware panic! " |
|---|
| 375 | 381 | "exccause: 0x%08x; pc: 0x%08x; badvaddr: 0x%08x.\n", |
|---|
| 376 | 382 | htc_panic->exccause, htc_panic->pc, |
|---|
| 377 | 383 | htc_panic->badvaddr); |
|---|
| 378 | | - break; |
|---|
| 379 | | - } |
|---|
| 380 | | - case 0x33221299: |
|---|
| 381 | | - { |
|---|
| 384 | + return; |
|---|
| 385 | + } |
|---|
| 386 | + if (*pattern == 0x33221299) { |
|---|
| 382 | 387 | struct htc_panic_bad_epid *htc_panic; |
|---|
| 383 | 388 | htc_panic = (struct htc_panic_bad_epid *) skb->data; |
|---|
| 384 | 389 | dev_err(htc_handle->dev, "ath: firmware panic! " |
|---|
| 385 | 390 | "bad epid: 0x%08x\n", htc_panic->epid); |
|---|
| 386 | | - break; |
|---|
| 387 | | - } |
|---|
| 388 | | - default: |
|---|
| 389 | | - dev_err(htc_handle->dev, "ath: unknown panic pattern!\n"); |
|---|
| 390 | | - break; |
|---|
| 391 | + return; |
|---|
| 391 | 392 | } |
|---|
| 393 | + dev_err(htc_handle->dev, "ath: unknown panic pattern!\n"); |
|---|
| 392 | 394 | } |
|---|
| 393 | 395 | |
|---|
| 394 | 396 | /* |
|---|
| 395 | 397 | * HTC Messages are handled directly here and the obtained SKB |
|---|
| 396 | 398 | * is freed. |
|---|
| 397 | 399 | * |
|---|
| 398 | | - * Service messages (Data, WMI) passed to the corresponding |
|---|
| 400 | + * Service messages (Data, WMI) are passed to the corresponding |
|---|
| 399 | 401 | * endpoint RX handlers, which have to free the SKB. |
|---|
| 400 | 402 | */ |
|---|
| 401 | 403 | void ath9k_htc_rx_msg(struct htc_target *htc_handle, |
|---|
| .. | .. |
|---|
| 409 | 411 | if (!htc_handle || !skb) |
|---|
| 410 | 412 | return; |
|---|
| 411 | 413 | |
|---|
| 414 | + /* A valid message requires len >= 8. |
|---|
| 415 | + * |
|---|
| 416 | + * sizeof(struct htc_frame_hdr) == 8 |
|---|
| 417 | + * sizeof(struct htc_ready_msg) == 8 |
|---|
| 418 | + * sizeof(struct htc_panic_bad_vaddr) == 16 |
|---|
| 419 | + * sizeof(struct htc_panic_bad_epid) == 8 |
|---|
| 420 | + */ |
|---|
| 421 | + if (unlikely(len < sizeof(struct htc_frame_hdr))) |
|---|
| 422 | + goto invalid; |
|---|
| 412 | 423 | htc_hdr = (struct htc_frame_hdr *) skb->data; |
|---|
| 413 | 424 | epid = htc_hdr->endpoint_id; |
|---|
| 414 | 425 | |
|---|
| 415 | 426 | if (epid == 0x99) { |
|---|
| 416 | | - ath9k_htc_fw_panic_report(htc_handle, skb); |
|---|
| 427 | + ath9k_htc_fw_panic_report(htc_handle, skb, len); |
|---|
| 417 | 428 | kfree_skb(skb); |
|---|
| 418 | 429 | return; |
|---|
| 419 | 430 | } |
|---|
| 420 | 431 | |
|---|
| 421 | 432 | if (epid < 0 || epid >= ENDPOINT_MAX) { |
|---|
| 433 | +invalid: |
|---|
| 422 | 434 | if (pipe_id != USB_REG_IN_PIPE) |
|---|
| 423 | 435 | dev_kfree_skb_any(skb); |
|---|
| 424 | 436 | else |
|---|
| .. | .. |
|---|
| 430 | 442 | |
|---|
| 431 | 443 | /* Handle trailer */ |
|---|
| 432 | 444 | if (htc_hdr->flags & HTC_FLAGS_RECV_TRAILER) { |
|---|
| 433 | | - if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) |
|---|
| 445 | + if (be32_to_cpu(*(__be32 *) skb->data) == 0x00C60000) { |
|---|
| 434 | 446 | /* Move past the Watchdog pattern */ |
|---|
| 435 | 447 | htc_hdr = (struct htc_frame_hdr *)(skb->data + 4); |
|---|
| 448 | + len -= 4; |
|---|
| 449 | + } |
|---|
| 436 | 450 | } |
|---|
| 437 | 451 | |
|---|
| 438 | 452 | /* Get the message ID */ |
|---|
| 453 | + if (unlikely(len < sizeof(struct htc_frame_hdr) + sizeof(__be16))) |
|---|
| 454 | + goto invalid; |
|---|
| 439 | 455 | msg_id = (__be16 *) ((void *) htc_hdr + |
|---|
| 440 | 456 | sizeof(struct htc_frame_hdr)); |
|---|
| 441 | 457 | |
|---|
| 442 | 458 | /* Now process HTC messages */ |
|---|
| 443 | 459 | switch (be16_to_cpu(*msg_id)) { |
|---|
| 444 | 460 | case HTC_MSG_READY_ID: |
|---|
| 461 | + if (unlikely(len < sizeof(struct htc_ready_msg))) |
|---|
| 462 | + goto invalid; |
|---|
| 445 | 463 | htc_process_target_rdy(htc_handle, htc_hdr); |
|---|
| 446 | 464 | break; |
|---|
| 447 | 465 | case HTC_MSG_CONNECT_SERVICE_RESPONSE_ID: |
|---|
| 466 | + if (unlikely(len < sizeof(struct htc_frame_hdr) + |
|---|
| 467 | + sizeof(struct htc_conn_svc_rspmsg))) |
|---|
| 468 | + goto invalid; |
|---|
| 448 | 469 | htc_process_conn_rsp(htc_handle, htc_hdr); |
|---|
| 449 | 470 | break; |
|---|
| 450 | 471 | default: |
|---|
| .. | .. |
|---|
| 463 | 484 | if (endpoint->ep_callbacks.rx) |
|---|
| 464 | 485 | endpoint->ep_callbacks.rx(endpoint->ep_callbacks.priv, |
|---|
| 465 | 486 | skb, epid); |
|---|
| 487 | + else |
|---|
| 488 | + goto invalid; |
|---|
| 466 | 489 | } |
|---|
| 467 | 490 | } |
|---|
| 468 | 491 | |
|---|