On Fri, 18 Oct 2019, Martin K. Petersen wrote:

>
> (Sorry, zhengbin, you opened a can of worms. This is some of our oldest
> and most arcane code in SCSI)
>

A call to set_host_byte(cmd, x) or set_msg_byte(cmd, x) when x & 0x80 is 
set clobbers the most significant bytes in cmd->result.

Avoid this implicit sign extension when shifting bits by using an
unsigned formal parameter.

This is a theoretical bug, found by inspection, so I'm sending an untested 
RFC patch.

I didn't try to find possible callers that might pass a negative parameter
and neither did I check whether the clobber might be intentional...

diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 76ed5e4acd38..ae814fa68bb8 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -306,17 +306,17 @@ static inline struct scsi_data_buffer *scsi_prot(struct 
scsi_cmnd *cmd)
 #define scsi_for_each_prot_sg(cmd, sg, nseg, __i)              \
        for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i)
 
-static inline void set_msg_byte(struct scsi_cmnd *cmd, char status)
+static inline void set_msg_byte(struct scsi_cmnd *cmd, unsigned char status)
 {
        cmd->result = (cmd->result & 0xffff00ff) | (status << 8);
 }
 
-static inline void set_host_byte(struct scsi_cmnd *cmd, char status)
+static inline void set_host_byte(struct scsi_cmnd *cmd, unsigned char status)
 {
        cmd->result = (cmd->result & 0xff00ffff) | (status << 16);
 }
 
-static inline void set_driver_byte(struct scsi_cmnd *cmd, char status)
+static inline void set_driver_byte(struct scsi_cmnd *cmd, unsigned char status)
 {
        cmd->result = (cmd->result & 0x00ffffff) | (status << 24);
 }

Reply via email to