Commit a46393ab authored by Jacob von Chorus's avatar Jacob von Chorus Committed by Greg Kroah-Hartman

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: default avatarJacob von Chorus <jacobvonchorus@cwphoto.ca>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ee714b80
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <asm/unaligned.h>
#include "gs_fpgaboot.h" #include "gs_fpgaboot.h"
#include "io.h" #include "io.h"
...@@ -47,7 +48,7 @@ static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize) ...@@ -47,7 +48,7 @@ static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize)
*offset += 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]; char tbuf[64];
s32 len; s32 len;
...@@ -58,10 +59,16 @@ static void readinfo_bitstream(char *bitdata, char *buf, int *offset) ...@@ -58,10 +59,16 @@ static void readinfo_bitstream(char *bitdata, char *buf, int *offset)
/* read length */ /* read length */
read_bitstream(bitdata, tbuf, offset, 2); 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); read_bitstream(bitdata, buf, offset, len);
buf[len] = '\0'; buf[len] = '\0';
return 0;
} }
/* /*
...@@ -83,8 +90,7 @@ static int readlength_bitstream(char *bitdata, int *lendata, int *offset) ...@@ -83,8 +90,7 @@ static int readlength_bitstream(char *bitdata, int *lendata, int *offset)
/* read 4bytes length */ /* read 4bytes length */
read_bitstream(bitdata, tbuf, offset, 4); read_bitstream(bitdata, tbuf, offset, 4);
*lendata = tbuf[0] << 24 | tbuf[1] << 16 | *lendata = get_unaligned_be32(tbuf);
tbuf[2] << 8 | tbuf[3];
return 0; return 0;
} }
...@@ -113,7 +119,7 @@ static int readmagic_bitstream(char *bitdata, int *offset) ...@@ -113,7 +119,7 @@ static int readmagic_bitstream(char *bitdata, int *offset)
/* /*
* NOTE: supports only bitstream format * NOTE: supports only bitstream format
*/ */
static enum fmt_image get_imageformat(struct fpgaimage *fimage) static enum fmt_image get_imageformat(void)
{ {
return f_bit; return f_bit;
} }
...@@ -127,34 +133,54 @@ static void gs_print_header(struct fpgaimage *fimage) ...@@ -127,34 +133,54 @@ static void gs_print_header(struct fpgaimage *fimage)
pr_info("lendata: %d\n", fimage->lendata); 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; char *bitdata;
int offset; int offset;
int err;
offset = 0; offset = 0;
bitdata = (char *)fimage->fw_entry->data; bitdata = (char *)fimage->fw_entry->data;
readmagic_bitstream(bitdata, &offset); err = readmagic_bitstream(bitdata, &offset);
readinfo_bitstream(bitdata, fimage->filename, &offset); if (err)
readinfo_bitstream(bitdata, fimage->part, &offset); return err;
readinfo_bitstream(bitdata, fimage->date, &offset);
readinfo_bitstream(bitdata, fimage->time, &offset); err = readinfo_bitstream(bitdata, fimage->filename, MAX_STR, &offset);
readlength_bitstream(bitdata, &fimage->lendata, &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; fimage->fpgadata = bitdata + offset;
return 0;
} }
static int gs_read_image(struct fpgaimage *fimage) static int gs_read_image(struct fpgaimage *fimage)
{ {
int img_fmt; int img_fmt;
int err;
img_fmt = get_imageformat(fimage); img_fmt = get_imageformat();
switch (img_fmt) { switch (img_fmt) {
case f_bit: case f_bit:
pr_info("image is bitstream format\n"); pr_info("image is bitstream format\n");
gs_read_bitstream(fimage); err = gs_read_bitstream(fimage);
if (err)
return err;
break; break;
default: default:
pr_err("unsupported fpga image format\n"); pr_err("unsupported fpga image format\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment