Hello Alan Stern: in drivers/usb/host/uhci-debug.c, for function uhci_sprint_schedule: we are not check the len of buf (not like another static functions in this file). the buffer len is MAX_OUTPUT: 64 * 1024 (line 491, line 517) the buffer may not be enough: we may loop UHCI_NUMFRAMES times (line 383..433) UHCI_NUMFRAMES is 1024 (drivers/usb/host/uhci-hcd.h:87) each time of loop may get more than 64 bytes (line 383..433) it seems we have noticed len checking when call uhci_show_td (line 411) but we not check it outside of uhci_show_td (line 400..414) so I suggest to add checking len when use buf (although it seems a little complex) I find it by code review, please help checking this suggestion, thanks. if this suggestion is valid: please help sending patch. better to mark me as Reported-by. not need cc to me (I am not reviewer) Regards. gchen. drivers/usb/host/uhci-hcd.h:87:#define UHCI_NUMFRAMES 1024 /* in the frame list [array] */ drivers/usb/host/uhci-debug.c 347 static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) 348 { 349 char *out = buf; 350 int i, j; 351 struct uhci_qh *qh; 352 struct uhci_td *td; 353 struct list_head *tmp, *head; 354 int nframes, nerrs; 355 __hc32 link; 356 __hc32 fsbr_link; 357 358 static const char * const qh_names[] = { 359 "unlink", "iso", "int128", "int64", "int32", "int16", 360 "int8", "int4", "int2", "async", "term" 361 }; 362 363 out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); 364 out += sprintf(out, "HC status\n"); 365 out += uhci_show_status(uhci, out, len - (out - buf)); 366 367 out += sprintf(out, "Periodic load table\n"); 368 for (i = 0; i < MAX_PHASE; ++i) { 369 out += sprintf(out, "\t%d", uhci->load[i]); 370 if (i % 8 == 7) 371 *out++ = '\n'; 372 } 373 out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n", 374 uhci->total_load, 375 uhci_to_hcd(uhci)->self.bandwidth_int_reqs, 376 uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs); 377 if (debug <= 1) 378 return out - buf; 379 380 out += sprintf(out, "Frame List\n"); 381 nframes = 10; 382 nerrs = 0; 383 for (i = 0; i < UHCI_NUMFRAMES; ++i) { 384 __hc32 qh_dma; 385 386 j = 0; 387 td = uhci->frame_cpu[i]; 388 link = uhci->frame[i]; 389 if (!td) 390 goto check_link; 391 392 if (nframes > 0) { 393 out += sprintf(out, "- Frame %d -> (%08x)\n", 394 i, hc32_to_cpu(uhci, link)); 395 j = 1; 396 } 397 398 head = &td->fl_list; 399 tmp = head; 400 do { 401 td = list_entry(tmp, struct uhci_td, fl_list); 402 tmp = tmp->next; 403 if (link != LINK_TO_TD(uhci, td)) { 404 if (nframes > 0) 405 out += sprintf(out, " link does " 406 "not match list entry!\n"); 407 else 408 ++nerrs; 409 } 410 if (nframes > 0) 411 out += uhci_show_td(uhci, td, out, 412 len - (out - buf), 4); 413 link = td->link; 414 } while (tmp != head); 415 416 check_link: 417 qh_dma = uhci_frame_skel_link(uhci, i); 418 if (link != qh_dma) { 419 if (nframes > 0) { 420 if (!j) { 421 out += sprintf(out, 422 "- Frame %d -> (%08x)\n", 423 i, hc32_to_cpu(uhci, link)); 424 j = 1; 425 } 426 out += sprintf(out, " link does not match " 427 "QH (%08x)!\n", 428 hc32_to_cpu(uhci, qh_dma)); 429 } else 430 ++nerrs; 431 } 432 nframes -= j; 433 } 434 if (nerrs > 0) 435 out += sprintf(out, "Skipped %d bad links\n", nerrs); 436 437 out += sprintf(out, "Skeleton QHs\n"); 438 439 fsbr_link = 0; 440 for (i = 0; i < UHCI_NUM_SKELQH; ++i) { 441 int cnt = 0; 442 443 qh = uhci->skelqh[i]; 444 out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \ 445 out += uhci_show_qh(uhci, qh, out, len - (out - buf), 4); 446 447 /* Last QH is the Terminating QH, it's different */ 448 if (i == SKEL_TERM) { 449 if (qh_element(qh) != LINK_TO_TD(uhci, uhci->term_td)) 450 out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); 451 link = fsbr_link; 452 if (!link) 453 link = LINK_TO_QH(uhci, uhci->skel_term_qh); 454 goto check_qh_link; 455 } 456 457 head = &qh->node; 458 tmp = head->next; 459 460 while (tmp != head) { 461 qh = list_entry(tmp, struct uhci_qh, node); 462 tmp = tmp->next; 463 if (++cnt <= 10) 464 out += uhci_show_qh(uhci, qh, out, 465 len - (out - buf), 4); 466 if (!fsbr_link && qh->skel >= SKEL_FSBR) 467 fsbr_link = LINK_TO_QH(uhci, qh); 468 } 469 if ((cnt -= 10) > 0) 470 out += sprintf(out, " Skipped %d QHs\n", cnt); 471 472 link = UHCI_PTR_TERM(uhci); 473 if (i <= SKEL_ISO) 474 ; 475 else if (i < SKEL_ASYNC) 476 link = LINK_TO_QH(uhci, uhci->skel_async_qh); 477 else if (!uhci->fsbr_is_on) 478 ; 479 else 480 link = LINK_TO_QH(uhci, uhci->skel_term_qh); 481 check_qh_link: 482 if (qh->link != link) 483 out += sprintf(out, " last QH not linked to next skeleton!\n"); 484 } 485 486 return out - buf; 487 } 488 489 #ifdef CONFIG_DEBUG_FS 490 491 #define MAX_OUTPUT (64 * 1024) 492 493 struct uhci_debug { 494 int size; 495 char *data; 496 }; 497 498 static int uhci_debug_open(struct inode *inode, struct file *file) 499 { 500 struct uhci_hcd *uhci = inode->i_private; 501 struct uhci_debug *up; 502 unsigned long flags; 503 504 up = kmalloc(sizeof(*up), GFP_KERNEL); 505 if (!up) 506 return -ENOMEM; 507 508 up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); 509 if (!up->data) { 510 kfree(up); 511 return -ENOMEM; 512 } 513 514 up->size = 0; 515 spin_lock_irqsave(&uhci->lock, flags); 516 if (uhci->is_initialized) 517 up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT); 518 spin_unlock_irqrestore(&uhci->lock, flags); 519 520 file->private_data = up; 521 522 return 0; 523 } 524 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html