USB: usb-storage: don't access beyond the end of the sg buffer
This patch (as1035) fixes a bug in usb_stor_access_xfer_buf() (the bug was originally found by Boaz Harrosh): The routine must not attempt to write beyond the end of a scatter-gather list or beyond the number of bytes requested. It also fixes up the formatting of a few comments and similar whitespace issues. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
274399d14f
commit
7084191d53
|
@ -150,13 +150,14 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
|
|||
|
||||
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
|
||||
* Update the **sgptr and *offset variables so that the next copy will
|
||||
* pick up from where this one left off. */
|
||||
|
||||
* pick up from where this one left off.
|
||||
*/
|
||||
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
|
||||
unsigned int *offset, enum xfer_buf_dir dir)
|
||||
{
|
||||
unsigned int cnt;
|
||||
struct scatterlist *sg = *sgptr;
|
||||
|
||||
/* We have to go through the list one entry
|
||||
* at a time. Each s-g entry contains some number of pages, and
|
||||
|
@ -164,22 +165,23 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
|
|||
* in kernel-addressable memory then kmap() will return its address.
|
||||
* If the page is not directly accessible -- such as a user buffer
|
||||
* located in high memory -- then kmap() will map it to a temporary
|
||||
* position in the kernel's virtual address space. */
|
||||
struct scatterlist *sg = *sgptr;
|
||||
* position in the kernel's virtual address space.
|
||||
*/
|
||||
|
||||
if (!sg)
|
||||
sg = scsi_sglist(srb);
|
||||
buflen = min(buflen, scsi_bufflen(srb));
|
||||
|
||||
/* This loop handles a single s-g list entry, which may
|
||||
* include multiple pages. Find the initial page structure
|
||||
* and the starting offset within the page, and update
|
||||
* the *offset and **sgptr values for the next loop. */
|
||||
* include multiple pages. Find the initial page structure
|
||||
* and the starting offset within the page, and update
|
||||
* the *offset and **sgptr values for the next loop.
|
||||
*/
|
||||
cnt = 0;
|
||||
while (cnt < buflen) {
|
||||
while (cnt < buflen && sg) {
|
||||
struct page *page = sg_page(sg) +
|
||||
((sg->offset + *offset) >> PAGE_SHIFT);
|
||||
unsigned int poff =
|
||||
(sg->offset + *offset) & (PAGE_SIZE-1);
|
||||
unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
|
||||
unsigned int sglen = sg->length - *offset;
|
||||
|
||||
if (sglen > buflen - cnt) {
|
||||
|
@ -222,14 +224,15 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
|
|||
}
|
||||
|
||||
/* Store the contents of buffer into srb's transfer buffer and set the
|
||||
* SCSI residue. */
|
||||
* SCSI residue.
|
||||
*/
|
||||
void usb_stor_set_xfer_buf(unsigned char *buffer,
|
||||
unsigned int buflen, struct scsi_cmnd *srb)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
struct scatterlist *sg = NULL;
|
||||
|
||||
usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
|
||||
buflen = usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,
|
||||
TO_XFER_BUF);
|
||||
if (buflen < scsi_bufflen(srb))
|
||||
scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
|
||||
|
|
Loading…
Reference in New Issue