Skip to content
Snippets Groups Projects
Commit e67b79e9 authored by dpgilbert's avatar dpgilbert
Browse files

bail out early (before VPD INQUIRY + LOG SENSE) if MODE SENSE response

malformed (heuristic to skip USB devices before we lock them up)


git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@1247 4ea69e1a-61f1-4043-bf83-b5c94c648137
parent e60e450e
No related branches found
No related tags found
No related merge requests found
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define GBUF_SIZE 65535 #define GBUF_SIZE 65535
const char* scsiprint_c_cvsid="$Id: scsiprint.c,v 1.61 2003/11/17 03:10:40 ballen4705 Exp $" const char* scsiprint_c_cvsid="$Id: scsiprint.c,v 1.62 2003/11/17 11:54:32 dpgilbert Exp $"
EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
// control block which points to external global control variables // control block which points to external global control variables
...@@ -69,6 +69,33 @@ static int gIecMPage = 1; /* N.B. assume it until we know otherwise */ ...@@ -69,6 +69,33 @@ static int gIecMPage = 1; /* N.B. assume it until we know otherwise */
static int modese_len = 0; static int modese_len = 0;
// Compares failure type to policy in effect, and either exits or
// simply returns to the calling routine.
static void failuretest(int type, int returnvalue)
{
// If this is an error in an "optional" SMART command
if (type == OPTIONAL_CMD) {
if (con->conservative) {
pout("An optional SMART command has failed: exiting.\n"
"To continue, set the tolerance level to something other "
"than 'conservative'\n");
EXIT(returnvalue);
}
return;
}
// If this is an error in a "mandatory" SMART command
if (type==MANDATORY_CMD) {
if (con->permissive)
return;
pout("A mandatory SMART command has failed: exiting. To continue, "
"use the -T option to set the tolerance level to 'permissive'\n");
exit(returnvalue);
}
pout("Smartctl internal error in failuretest(type=%d). Please contact "
"%s\n",type,PROJECTHOME);
exit(returnvalue|FAILCMD);
}
static void scsiGetSupportedLogPages(int device) static void scsiGetSupportedLogPages(int device)
{ {
int i, err; int i, err;
...@@ -572,6 +599,25 @@ static const char * peripheral_dt_arr[] = { ...@@ -572,6 +599,25 @@ static const char * peripheral_dt_arr[] = {
"optical card reader" "optical card reader"
}; };
static const char * transport_proto_arr[] = {
"Fibre channel (FCP-2)",
"Parallel SCSI (SPI-4)",
"SSA",
"IEEE 1394 (SBP-2)",
"RDMA (SRP)",
"iSCSI",
"SAS",
"ADT",
"0x8",
"0x9",
"0xa",
"0xb",
"0xc",
"0xd",
"0xe",
"0xf"
};
/* Returns 0 on success */ /* Returns 0 on success */
static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
{ {
...@@ -580,7 +626,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -580,7 +626,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
char revision[5]; char revision[5];
char timedatetz[64]; char timedatetz[64];
struct scsi_iec_mode_page iec; struct scsi_iec_mode_page iec;
int err, len; int err, iec_err, len, val;
int is_tape = 0; int is_tape = 0;
int peri_dt = 0; int peri_dt = 0;
...@@ -598,7 +644,12 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -598,7 +644,12 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
if (! all) if (! all)
return 0; return 0;
if (len >= 36) { if (len < 36) {
QUIETON(con);
pout("Short INQUIRY response, skip product id\n");
QUIETOFF(con);
return 1;
}
memset(manufacturer, 0, sizeof(manufacturer)); memset(manufacturer, 0, sizeof(manufacturer));
strncpy(manufacturer, (char *)&gBuf[8], 8); strncpy(manufacturer, (char *)&gBuf[8], 8);
...@@ -609,21 +660,19 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -609,21 +660,19 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
strncpy(revision, (char *)&gBuf[32], 4); strncpy(revision, (char *)&gBuf[32], 4);
pout("Device: %s %s Version: %s\n", manufacturer, product, revision); pout("Device: %s %s Version: %s\n", manufacturer, product, revision);
/* /* Do this here to try and detect badly conforming devices (some USB
Doug: for a bad USB device, the code hangs in the following keys) that will lock up on a InquiryVpd or log sense or ... */
line within scsiInquiryVpd(): if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
if (SIMPLE_ERR_BAD_RESP == iec_err) {
status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); pout(">> Terminate command early due to bad response to IEC "
"mode page\n");
and within do_scsi_cmnd_io() it hangs in the line: QUIETOFF(con);
gIecMPage = 0;
status = ioctl(dev_fd, SCSI_IOCTL_SEND_COMMAND , &wrk); return 1;
}
which never returns. Would it be possible to put in a } else
sanity check to detect such devices and exit with an error modese_len = iec.modese_len;
message, before calling scsiInquiryVpd()?
*/
if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) { if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) {
/* should use VPD page 0x83 and fall back to this page (0x80) /* should use VPD page 0x83 and fall back to this page (0x80)
* if 0x83 not supported. NAA requires a lot of decoding code */ * if 0x83 not supported. NAA requires a lot of decoding code */
...@@ -639,11 +688,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -639,11 +688,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err); pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
QUIETOFF(con); QUIETOFF(con);
} }
} else {
QUIETON(con);
pout("Short INQUIRY response, skip product id\n");
QUIETOFF(con);
}
// print SCSI peripheral device type // print SCSI peripheral device type
if (peri_dt < (int)(sizeof(peripheral_dt_arr) / if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
sizeof(peripheral_dt_arr[0]))) sizeof(peripheral_dt_arr[0])))
...@@ -651,6 +696,11 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -651,6 +696,11 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
else else
pout("Device type: <%d>\n", peri_dt); pout("Device type: <%d>\n", peri_dt);
// See if transport protocol is known
val = scsiFetchTransportProtocol(device, modese_len);
if ((val >= 0) && (val <= 0xf))
pout("Transport protocol: %s\n", transport_proto_arr[val]);
// print current time and date and timezone // print current time and date and timezone
dateandtimezone(timedatetz); dateandtimezone(timedatetz);
pout("Local Time is: %s\n", timedatetz); pout("Local Time is: %s\n", timedatetz);
...@@ -672,27 +722,20 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -672,27 +722,20 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
return 0; return 0;
} }
if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { if (iec_err) {
if (!is_tape) { if (!is_tape) {
QUIETON(con); QUIETON(con);
pout("Device does not support SMART"); pout("Device does not support SMART");
if (con->reportscsiioctl > 0) if (con->reportscsiioctl > 0)
pout(" [%s]\n", scsiErrString(err)); pout(" [%s]\n", scsiErrString(iec_err));
else else
pout("\n"); pout("\n");
if (SIMPLE_ERR_BAD_RESP == err) {
pout(">> Terminate command early due to bad response to IEC "
"mode page\n");
QUIETOFF(con);
gIecMPage = 0;
return 1;
}
QUIETOFF(con); QUIETOFF(con);
} }
gIecMPage = 0; gIecMPage = 0;
return 0; return 0;
} else }
modese_len = iec.modese_len;
if (!is_tape) if (!is_tape)
pout("Device supports SMART and is %s\n", pout("Device supports SMART and is %s\n",
(scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled"); (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
...@@ -792,33 +835,6 @@ void scsiPrintTemp(int device) ...@@ -792,33 +835,6 @@ void scsiPrintTemp(int device)
pout("Drive Trip Temperature: %d C\n", trip); pout("Drive Trip Temperature: %d C\n", trip);
} }
// Compares failure type to policy in effect, and either exits or
// simply returns to the calling routine.
static void failuretest(int type, int returnvalue)
{
// If this is an error in an "optional" SMART command
if (type == OPTIONAL_CMD) {
if (con->conservative) {
pout("An optional SMART command has failed: exiting.\n"
"To continue, set the tolerance level to something other "
"than 'conservative'\n");
EXIT(returnvalue);
}
return;
}
// If this is an error in a "mandatory" SMART command
if (type==MANDATORY_CMD) {
if (con->permissive)
return;
pout("A mandatory SMART command has failed: exiting. To continue, "
"use the -T option to set the tolerance level to 'permissive'\n");
exit(returnvalue);
}
pout("Smartctl internal error in failuretest(type=%d). Please contact "
"%s\n",type,PROJECTHOME);
exit(returnvalue|FAILCMD);
}
/* Main entry point used by smartctl command. Return 0 for success */ /* Main entry point used by smartctl command. Return 0 for success */
int scsiPrintMain(int fd) int scsiPrintMain(int fd)
{ {
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define GBUF_SIZE 65535 #define GBUF_SIZE 65535
const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.61 2003/11/17 03:10:40 ballen4705 Exp $" const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.62 2003/11/17 11:54:32 dpgilbert Exp $"
EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
// control block which points to external global control variables // control block which points to external global control variables
...@@ -69,6 +69,33 @@ static int gIecMPage = 1; /* N.B. assume it until we know otherwise */ ...@@ -69,6 +69,33 @@ static int gIecMPage = 1; /* N.B. assume it until we know otherwise */
static int modese_len = 0; static int modese_len = 0;
// Compares failure type to policy in effect, and either exits or
// simply returns to the calling routine.
static void failuretest(int type, int returnvalue)
{
// If this is an error in an "optional" SMART command
if (type == OPTIONAL_CMD) {
if (con->conservative) {
pout("An optional SMART command has failed: exiting.\n"
"To continue, set the tolerance level to something other "
"than 'conservative'\n");
EXIT(returnvalue);
}
return;
}
// If this is an error in a "mandatory" SMART command
if (type==MANDATORY_CMD) {
if (con->permissive)
return;
pout("A mandatory SMART command has failed: exiting. To continue, "
"use the -T option to set the tolerance level to 'permissive'\n");
exit(returnvalue);
}
pout("Smartctl internal error in failuretest(type=%d). Please contact "
"%s\n",type,PROJECTHOME);
exit(returnvalue|FAILCMD);
}
static void scsiGetSupportedLogPages(int device) static void scsiGetSupportedLogPages(int device)
{ {
int i, err; int i, err;
...@@ -572,6 +599,25 @@ static const char * peripheral_dt_arr[] = { ...@@ -572,6 +599,25 @@ static const char * peripheral_dt_arr[] = {
"optical card reader" "optical card reader"
}; };
static const char * transport_proto_arr[] = {
"Fibre channel (FCP-2)",
"Parallel SCSI (SPI-4)",
"SSA",
"IEEE 1394 (SBP-2)",
"RDMA (SRP)",
"iSCSI",
"SAS",
"ADT",
"0x8",
"0x9",
"0xa",
"0xb",
"0xc",
"0xd",
"0xe",
"0xf"
};
/* Returns 0 on success */ /* Returns 0 on success */
static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
{ {
...@@ -580,7 +626,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -580,7 +626,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
char revision[5]; char revision[5];
char timedatetz[64]; char timedatetz[64];
struct scsi_iec_mode_page iec; struct scsi_iec_mode_page iec;
int err, len; int err, iec_err, len, val;
int is_tape = 0; int is_tape = 0;
int peri_dt = 0; int peri_dt = 0;
...@@ -598,7 +644,12 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -598,7 +644,12 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
if (! all) if (! all)
return 0; return 0;
if (len >= 36) { if (len < 36) {
QUIETON(con);
pout("Short INQUIRY response, skip product id\n");
QUIETOFF(con);
return 1;
}
memset(manufacturer, 0, sizeof(manufacturer)); memset(manufacturer, 0, sizeof(manufacturer));
strncpy(manufacturer, (char *)&gBuf[8], 8); strncpy(manufacturer, (char *)&gBuf[8], 8);
...@@ -609,21 +660,19 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -609,21 +660,19 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
strncpy(revision, (char *)&gBuf[32], 4); strncpy(revision, (char *)&gBuf[32], 4);
pout("Device: %s %s Version: %s\n", manufacturer, product, revision); pout("Device: %s %s Version: %s\n", manufacturer, product, revision);
/* /* Do this here to try and detect badly conforming devices (some USB
Doug: for a bad USB device, the code hangs in the following keys) that will lock up on a InquiryVpd or log sense or ... */
line within scsiInquiryVpd(): if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) {
if (SIMPLE_ERR_BAD_RESP == iec_err) {
status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); pout(">> Terminate command early due to bad response to IEC "
"mode page\n");
and within do_scsi_cmnd_io() it hangs in the line: QUIETOFF(con);
gIecMPage = 0;
status = ioctl(dev_fd, SCSI_IOCTL_SEND_COMMAND , &wrk); return 1;
}
which never returns. Would it be possible to put in a } else
sanity check to detect such devices and exit with an error modese_len = iec.modese_len;
message, before calling scsiInquiryVpd()?
*/
if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) { if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) {
/* should use VPD page 0x83 and fall back to this page (0x80) /* should use VPD page 0x83 and fall back to this page (0x80)
* if 0x83 not supported. NAA requires a lot of decoding code */ * if 0x83 not supported. NAA requires a lot of decoding code */
...@@ -639,11 +688,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -639,11 +688,7 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err); pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err);
QUIETOFF(con); QUIETOFF(con);
} }
} else {
QUIETON(con);
pout("Short INQUIRY response, skip product id\n");
QUIETOFF(con);
}
// print SCSI peripheral device type // print SCSI peripheral device type
if (peri_dt < (int)(sizeof(peripheral_dt_arr) / if (peri_dt < (int)(sizeof(peripheral_dt_arr) /
sizeof(peripheral_dt_arr[0]))) sizeof(peripheral_dt_arr[0])))
...@@ -651,6 +696,11 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -651,6 +696,11 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
else else
pout("Device type: <%d>\n", peri_dt); pout("Device type: <%d>\n", peri_dt);
// See if transport protocol is known
val = scsiFetchTransportProtocol(device, modese_len);
if ((val >= 0) && (val <= 0xf))
pout("Transport protocol: %s\n", transport_proto_arr[val]);
// print current time and date and timezone // print current time and date and timezone
dateandtimezone(timedatetz); dateandtimezone(timedatetz);
pout("Local Time is: %s\n", timedatetz); pout("Local Time is: %s\n", timedatetz);
...@@ -672,27 +722,20 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) ...@@ -672,27 +722,20 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all)
return 0; return 0;
} }
if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { if (iec_err) {
if (!is_tape) { if (!is_tape) {
QUIETON(con); QUIETON(con);
pout("Device does not support SMART"); pout("Device does not support SMART");
if (con->reportscsiioctl > 0) if (con->reportscsiioctl > 0)
pout(" [%s]\n", scsiErrString(err)); pout(" [%s]\n", scsiErrString(iec_err));
else else
pout("\n"); pout("\n");
if (SIMPLE_ERR_BAD_RESP == err) {
pout(">> Terminate command early due to bad response to IEC "
"mode page\n");
QUIETOFF(con);
gIecMPage = 0;
return 1;
}
QUIETOFF(con); QUIETOFF(con);
} }
gIecMPage = 0; gIecMPage = 0;
return 0; return 0;
} else }
modese_len = iec.modese_len;
if (!is_tape) if (!is_tape)
pout("Device supports SMART and is %s\n", pout("Device supports SMART and is %s\n",
(scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled"); (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled");
...@@ -792,33 +835,6 @@ void scsiPrintTemp(int device) ...@@ -792,33 +835,6 @@ void scsiPrintTemp(int device)
pout("Drive Trip Temperature: %d C\n", trip); pout("Drive Trip Temperature: %d C\n", trip);
} }
// Compares failure type to policy in effect, and either exits or
// simply returns to the calling routine.
static void failuretest(int type, int returnvalue)
{
// If this is an error in an "optional" SMART command
if (type == OPTIONAL_CMD) {
if (con->conservative) {
pout("An optional SMART command has failed: exiting.\n"
"To continue, set the tolerance level to something other "
"than 'conservative'\n");
EXIT(returnvalue);
}
return;
}
// If this is an error in a "mandatory" SMART command
if (type==MANDATORY_CMD) {
if (con->permissive)
return;
pout("A mandatory SMART command has failed: exiting. To continue, "
"use the -T option to set the tolerance level to 'permissive'\n");
exit(returnvalue);
}
pout("Smartctl internal error in failuretest(type=%d). Please contact "
"%s\n",type,PROJECTHOME);
exit(returnvalue|FAILCMD);
}
/* Main entry point used by smartctl command. Return 0 for success */ /* Main entry point used by smartctl command. Return 0 for success */
int scsiPrintMain(int fd) int scsiPrintMain(int fd)
{ {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment