summaryrefslogtreecommitdiffstats
path: root/drivers/staging/gs_fpgaboot
diff options
context:
space:
mode:
authorJacob von Chorus <jacobvonchorus@cwphoto.ca>2017-07-28 17:06:16 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-07-28 17:07:37 -0700
commita46393aba77c870ef73beb417c48af4df43cb342 (patch)
tree084fe9dd76bfe0e49ef22e436adb528b86a73dde /drivers/staging/gs_fpgaboot
parentee714b80eaf7da35d82d663546c22d8cd016e8aa (diff)
downloadlinux-a46393aba77c870ef73beb417c48af4df43cb342.tar.gz
linux-a46393aba77c870ef73beb417c48af4df43cb342.tar.bz2
linux-a46393aba77c870ef73beb417c48af4df43cb342.zip
staging: gs_fpgaboot: add buffer overflow checks
Four fields in struct fpgaimage are char arrays of length MAX_STR (256). The amount of data read into these buffers is controlled by a length field in the bitstream file read from userspace. If a corrupt or malicious firmware file was supplied, kernel data beyond these buffers can be overwritten arbitrarily. This patch adds a check of the bitstream's length value to ensure it fits within the bounds of the allocated buffers. An error condition is returned from gs_read_bitstream if any of the reads fail. Signed-off-by: Jacob von Chorus <jacobvonchorus@cwphoto.ca> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/gs_fpgaboot')
-rw-r--r--drivers/staging/gs_fpgaboot/gs_fpgaboot.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
index 19b550fff04b..a49019af601e 100644
--- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
+++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/firmware.h>
+#include <asm/unaligned.h>
#include "gs_fpgaboot.h"
#include "io.h"
@@ -47,7 +48,7 @@ static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize)
*offset += rdsize;
}
-static void readinfo_bitstream(char *bitdata, char *buf, int *offset)
+static int readinfo_bitstream(char *bitdata, char *buf, int size, int *offset)
{
char tbuf[64];
s32 len;
@@ -58,10 +59,16 @@ static void readinfo_bitstream(char *bitdata, char *buf, int *offset)
/* read length */
read_bitstream(bitdata, tbuf, offset, 2);
- len = tbuf[0] << 8 | tbuf[1];
+ len = get_unaligned_be16(tbuf);
+ if (len >= size) {
+ pr_err("error: readinfo buffer too small\n");
+ return -EINVAL;
+ }
read_bitstream(bitdata, buf, offset, len);
buf[len] = '\0';
+
+ return 0;
}
/*
@@ -83,8 +90,7 @@ static int readlength_bitstream(char *bitdata, int *lendata, int *offset)
/* read 4bytes length */
read_bitstream(bitdata, tbuf, offset, 4);
- *lendata = tbuf[0] << 24 | tbuf[1] << 16 |
- tbuf[2] << 8 | tbuf[3];
+ *lendata = get_unaligned_be32(tbuf);
return 0;
}
@@ -113,7 +119,7 @@ static int readmagic_bitstream(char *bitdata, int *offset)
/*
* NOTE: supports only bitstream format
*/
-static enum fmt_image get_imageformat(struct fpgaimage *fimage)
+static enum fmt_image get_imageformat(void)
{
return f_bit;
}
@@ -127,34 +133,54 @@ static void gs_print_header(struct fpgaimage *fimage)
pr_info("lendata: %d\n", fimage->lendata);
}
-static void gs_read_bitstream(struct fpgaimage *fimage)
+static int gs_read_bitstream(struct fpgaimage *fimage)
{
char *bitdata;
int offset;
+ int err;
offset = 0;
bitdata = (char *)fimage->fw_entry->data;
- readmagic_bitstream(bitdata, &offset);
- readinfo_bitstream(bitdata, fimage->filename, &offset);
- readinfo_bitstream(bitdata, fimage->part, &offset);
- readinfo_bitstream(bitdata, fimage->date, &offset);
- readinfo_bitstream(bitdata, fimage->time, &offset);
- readlength_bitstream(bitdata, &fimage->lendata, &offset);
+ err = readmagic_bitstream(bitdata, &offset);
+ if (err)
+ return err;
+
+ err = readinfo_bitstream(bitdata, fimage->filename, MAX_STR, &offset);
+ if (err)
+ return err;
+ err = readinfo_bitstream(bitdata, fimage->part, MAX_STR, &offset);
+ if (err)
+ return err;
+ err = readinfo_bitstream(bitdata, fimage->date, MAX_STR, &offset);
+ if (err)
+ return err;
+ err = readinfo_bitstream(bitdata, fimage->time, MAX_STR, &offset);
+ if (err)
+ return err;
+
+ err = readlength_bitstream(bitdata, &fimage->lendata, &offset);
+ if (err)
+ return err;
fimage->fpgadata = bitdata + offset;
+
+ return 0;
}
static int gs_read_image(struct fpgaimage *fimage)
{
int img_fmt;
+ int err;
- img_fmt = get_imageformat(fimage);
+ img_fmt = get_imageformat();
switch (img_fmt) {
case f_bit:
pr_info("image is bitstream format\n");
- gs_read_bitstream(fimage);
+ err = gs_read_bitstream(fimage);
+ if (err)
+ return err;
break;
default:
pr_err("unsupported fpga image format\n");