diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-04-25 11:54:28 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-04-27 03:33:39 -0400 |
commit | 532c34b5fbf1687df63b3fcd5b2846312ac943c6 (patch) | |
tree | 3bc98a98c96a419d250e46dc7b0426b73ed65d58 | |
parent | 723cacbd9dc79582e562c123a0bacf8bfc69e72a (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.c | 12 |
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); |