Commit 48970800 authored by Al Viro's avatar Al Viro Committed by Linus Torvalds

[PATCH] sd: fix memory corruption with broken mode page headers

There's a problem in sd where we blindly believe the length of the
headers and block descriptors.  Some devices return insane values for
these and cause our length to end up greater than the actual buffer
size, so check to make sure.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>

Also removed the buffer size magic number (512) and added DPOFUA of
zero to the defaults
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a0124d78
...@@ -89,6 +89,11 @@ ...@@ -89,6 +89,11 @@
#define SD_MAX_RETRIES 5 #define SD_MAX_RETRIES 5
#define SD_PASSTHROUGH_RETRIES 1 #define SD_PASSTHROUGH_RETRIES 1
/*
* Size of the initial data buffer for mode and read capacity data
*/
#define SD_BUF_SIZE 512
static void scsi_disk_release(struct kref *kref); static void scsi_disk_release(struct kref *kref);
struct scsi_disk { struct scsi_disk {
...@@ -1239,7 +1244,7 @@ sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage, ...@@ -1239,7 +1244,7 @@ sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage,
/* /*
* read write protect setting, if possible - called only in sd_revalidate_disk() * read write protect setting, if possible - called only in sd_revalidate_disk()
* called with buffer of length 512 * called with buffer of length SD_BUF_SIZE
*/ */
static void static void
sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
...@@ -1297,7 +1302,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, ...@@ -1297,7 +1302,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
/* /*
* sd_read_cache_type - called only from sd_revalidate_disk() * sd_read_cache_type - called only from sd_revalidate_disk()
* called with buffer of length 512 * called with buffer of length SD_BUF_SIZE
*/ */
static void static void
sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
...@@ -1342,6 +1347,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1342,6 +1347,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
/* Take headers and block descriptors into account */ /* Take headers and block descriptors into account */
len += data.header_length + data.block_descriptor_length; len += data.header_length + data.block_descriptor_length;
if (len > SD_BUF_SIZE)
goto bad_sense;
/* Get the data */ /* Get the data */
res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
...@@ -1354,6 +1361,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1354,6 +1361,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
int ct = 0; int ct = 0;
int offset = data.header_length + data.block_descriptor_length; int offset = data.header_length + data.block_descriptor_length;
if (offset >= SD_BUF_SIZE - 2) {
printk(KERN_ERR "%s: malformed MODE SENSE response",
diskname);
goto defaults;
}
if ((buffer[offset] & 0x3f) != modepage) { if ((buffer[offset] & 0x3f) != modepage) {
printk(KERN_ERR "%s: got wrong page\n", diskname); printk(KERN_ERR "%s: got wrong page\n", diskname);
goto defaults; goto defaults;
...@@ -1398,6 +1411,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ...@@ -1398,6 +1411,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
diskname); diskname);
sdkp->WCE = 0; sdkp->WCE = 0;
sdkp->RCD = 0; sdkp->RCD = 0;
sdkp->DPOFUA = 0;
} }
/** /**
...@@ -1421,7 +1435,7 @@ static int sd_revalidate_disk(struct gendisk *disk) ...@@ -1421,7 +1435,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
if (!scsi_device_online(sdp)) if (!scsi_device_online(sdp))
goto out; goto out;
buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA); buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA);
if (!buffer) { if (!buffer) {
printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
"failure.\n"); "failure.\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment