mptfusion: buffer overflow in mptctl_do_mpt_command()
Subsystems (3)
PATCH 1/1 mptfusion: buffer overflow in mptctl_do_mpt_command()
The main problem is that this copy can overflow:
if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) {We try to prevent an overflow by checking "if (sz > ioc->req_sz) {" but the problem is that "sz" is signed so the test can underflow or their could be an integer overflow.
A second problem was this check which could underflow if "maxSenseBytes" was negative.
if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE)
I made the variables unsigned to prevent underflow and I added a new test to prevent integer overflows. I had to update a call to printk() and change some min() usages to min_t() as part of the fallout from the type changes.
Signed-off-by Dan Carpenter <[email protected]>
---
Static checker stuff, and not tested but I think it is safe.
drivers/message/fusion/mptctl.h +5 -5
@@ -324,11 +324,11 @@ struct mpt_ioctl_command {char __user *dataInBufPtr;char __user *dataOutBufPtr;char __user *senseDataPtr; -int maxReplyBytes; -int dataInSize; -int dataOutSize; -int maxSenseBytes; -int dataSgeOffset; +unsigned int maxReplyBytes; +unsigned int dataInSize; +unsigned int dataOutSize; +unsigned int maxSenseBytes; +unsigned int dataSgeOffset;char MF [1 ]; };
drivers/message/fusion/mptctl.c +9 -5
@@ -1829,7 +1829,8 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)dma_addr_t dma_addr_out;int sgSize =0 ;/* Num SG elements */ int iocnum, flagsLength; -int sz, rc =0 ; +size_t sz; +int rc =0 ;int msgContext;u16 req_idx;ulong timeout;
@@ -1861,6 +1862,9 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)/* Verify that the final request frame will not be too large. */ +if (karg.dataSgeOffset > ioc->req_sz) +return -EFAULT ; + sz = karg.dataSgeOffset *4 ;if (karg.dataInSize >0 ) sz += ioc->SGE_size;
@@ -1869,7 +1873,7 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr)if (sz > ioc->req_sz) {printk (MYIOC_s_ERR_FMT"%s@%d::mptctl_do_mpt_command - " -"Request frame too large (%d) maximum (%d)\n" , +"Request frame too large (%ld) maximum (%d)\n" , ioc->name, __FILE__, __LINE__, sz, ioc->req_sz);return -EFAULT ; }
@@ -2316,8 +2320,8 @@ retry_wait:*/ if (ioc->ioctl_cmds.status &MPT_MGMT_STATUS_RF_VALID ) {if (karg.maxReplyBytes < ioc->reply_sz) { - sz =min (karg.maxReplyBytes, -4 *ioc->ioctl_cmds.reply[2 ]); + sz =min_t (size_t, karg.maxReplyBytes, +4 *ioc->ioctl_cmds.reply[2 ]); }else { sz =min (ioc->reply_sz,4 *ioc->ioctl_cmds.reply[2 ]); }
@@ -2337,7 +2341,7 @@ retry_wait:/* If valid sense data, copy to user. */ if (ioc->ioctl_cmds.status &MPT_MGMT_STATUS_SENSE_VALID ) { - sz =min (karg.maxSenseBytes,MPT_SENSE_BUFFER_SIZE ); + sz =min_t (size_t, karg.maxSenseBytes,MPT_SENSE_BUFFER_SIZE );if (sz >0 ) {if (copy_to_user (karg.senseDataPtr, ioc->ioctl_cmds.sense, sz)) {