From: Tomas Henzl <thenzl@redhat.com> Date: Mon, 1 Feb 2010 16:53:00 -0500 Subject: [scsi] megaraid: fix 32-bit apps on 64-bit kernel Message-id: <4B6706EC.8060400@redhat.com> Patchwork-id: 23054 O-Subject: Re: [RHEL5.5 PATCH] bz518243 megaraid: fix 32bit apps Bugzilla: 518243 bz#518243 This should resolve a problem introduced by the last driver update to v4.17 - also bz518243. Part of this patch in function megasas_mgmt_fw_ioctl should resolve a problem with a 64bit pointer stored in a u32. - u32 *sense_ptr; + unsigned long *sense_ptr; ... sense_ptr = - (u32 *) ((unsigned long)cmd->frame + ioc->sense_off); + (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off); *sense_ptr = sense_handle; ... - sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); + sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw + + ioc->sense_off); if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), sense, ioc->sense_len)) { ... This on the other side caused problems for 32bit programs in 64 bit os, for example Dell's 'open manage'(omsa). Patch below is tested by customer on 64bit, he also verified the omsa functionality. I've verified that there are no error messages with 32, 64, and PAE kernel. Signed-off-by: Jarod Wilson <jarod@redhat.com> diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index e48d37b..8965842 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -3966,6 +3966,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) compat_alloc_user_space(sizeof(struct megasas_iocpacket)); int i; int error = 0; + compat_uptr_t ptr; + u8 *raw_ptr; if (clear_user(ioc, sizeof(*ioc))) return -EFAULT; @@ -3978,9 +3980,14 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32))) return -EFAULT; - for (i = 0; i < MAX_IOCTL_SGE; i++) { - compat_uptr_t ptr; + if (ioc->sense_len) { + raw_ptr = ioc->frame.raw + ioc->sense_off; + if (get_user(ptr, (compat_uptr_t *)raw_ptr) || + put_user(ptr, (unsigned long *)raw_ptr)) + return -EFAULT; + } + for (i = 0; i < MAX_IOCTL_SGE; i++) { if (get_user(ptr, &cioc->sgl[i].iov_base) || put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) || copy_in_user(&ioc->sgl[i].iov_len,