aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2016-04-25 11:54:28 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2016-04-27 03:33:39 -0400
commit532c34b5fbf1687df63b3fcd5b2846312ac943c6 (patch)
tree3bc98a98c96a419d250e46dc7b0426b73ed65d58
parent723cacbd9dc79582e562c123a0bacf8bfc69e72a (diff)
s390/sclp_ctl: fix potential information leak with /dev/sclp
The sclp_ctl_ioctl_sccb function uses two copy_from_user calls to retrieve the sclp request from user space. The first copy_from_user fetches the length of the request which is stored in the first two bytes of the request. The second copy_from_user gets the complete sclp request, but this copies the length field a second time. A malicious user may have changed the length in the meantime. Reported-by: Pengfei Wang <wpengfeinudt@gmail.com> Reviewed-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/char/sclp_ctl.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/s390/char/sclp_ctl.c b/drivers/s390/char/sclp_ctl.c
index 648cb86afd42..ea607a4a1bdd 100644
--- a/drivers/s390/char/sclp_ctl.c
+++ b/drivers/s390/char/sclp_ctl.c
@@ -56,6 +56,7 @@ static int sclp_ctl_ioctl_sccb(void __user *user_area)
56{ 56{
57 struct sclp_ctl_sccb ctl_sccb; 57 struct sclp_ctl_sccb ctl_sccb;
58 struct sccb_header *sccb; 58 struct sccb_header *sccb;
59 unsigned long copied;
59 int rc; 60 int rc;
60 61
61 if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb))) 62 if (copy_from_user(&ctl_sccb, user_area, sizeof(ctl_sccb)))
@@ -65,14 +66,15 @@ static int sclp_ctl_ioctl_sccb(void __user *user_area)
65 sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 66 sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
66 if (!sccb) 67 if (!sccb)
67 return -ENOMEM; 68 return -ENOMEM;
68 if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sizeof(*sccb))) { 69 copied = PAGE_SIZE -
70 copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), PAGE_SIZE);
71 if (offsetof(struct sccb_header, length) +
72 sizeof(sccb->length) > copied || sccb->length > copied) {
69 rc = -EFAULT; 73 rc = -EFAULT;
70 goto out_free; 74 goto out_free;
71 } 75 }
72 if (sccb->length > PAGE_SIZE || sccb->length < 8) 76 if (sccb->length < 8) {
73 return -EINVAL; 77 rc = -EINVAL;
74 if (copy_from_user(sccb, u64_to_uptr(ctl_sccb.sccb), sccb->length)) {
75 rc = -EFAULT;
76 goto out_free; 78 goto out_free;
77 } 79 }
78 rc = sclp_sync_request(ctl_sccb.cmdw, sccb); 80 rc = sclp_sync_request(ctl_sccb.cmdw, sccb);