summaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/ipl.c
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.vnet.ibm.com>2015-11-06 09:58:06 +0100
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-11-11 09:07:06 +0100
commite0bedada3a497d0640dd5db93e7ad0735f487492 (patch)
tree1fa92c6b1d86812f47d80a593941d8d8abdc1805 /arch/s390/kernel/ipl.c
parent52d43d8184b1840c7cf6136724223585f51a1074 (diff)
downloadlinux-e0bedada3a497d0640dd5db93e7ad0735f487492.tar.gz
linux-e0bedada3a497d0640dd5db93e7ad0735f487492.tar.bz2
linux-e0bedada3a497d0640dd5db93e7ad0735f487492.zip
s390/ipl: fix out of bounds access in scpdata_write
The input buffer in reipl_fcp_scpdata_write is accessed out of bounds when an offset is specified. The problem is that the offset refers to the data we should write to and not to the buffer we read from. So instead of memcpy(scp_data, buf + off, count); we could just do memcpy(scp_data + off, buf, count); However we not only modify the data but also store its length. For this to work we'd need to remember a state per open FH. Since that's not possible with sysfs callbacks let's just fail when an offset is specified. Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com> Acked-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/ipl.c')
-rw-r--r--arch/s390/kernel/ipl.c17
1 files changed, 5 insertions, 12 deletions
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index f6d8acd7e136..9f80f65c3d97 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -687,21 +687,14 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
+ size_t scpdata_len = count;
size_t padding;
- size_t scpdata_len;
- if (off < 0)
- return -EINVAL;
-
- if (off >= DIAG308_SCPDATA_SIZE)
- return -ENOSPC;
- if (count > DIAG308_SCPDATA_SIZE - off)
- count = DIAG308_SCPDATA_SIZE - off;
-
- memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count);
- scpdata_len = off + count;
+ if (off)
+ return -EINVAL;
+ memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf, count);
if (scpdata_len % 8) {
padding = 8 - (scpdata_len % 8);
memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len,
@@ -717,7 +710,7 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
}
static struct bin_attribute sys_reipl_fcp_scp_data_attr =
__BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_fcp_scpdata_read,
- reipl_fcp_scpdata_write, PAGE_SIZE);
+ reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_fcp_bin_attrs[] = {
&sys_reipl_fcp_scp_data_attr,