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@xxxxxxxxxx> --- v3: - use >= to prevent an integer overflow in the comparison - use get_unaligned_be functions to interpret length fields - fix remainder of file to use valid error codes v2: - char arrays converted to u8 arrays - replace error return value with proper error code in gs_read_bitstream drivers/staging/gs_fpgaboot/gs_fpgaboot.c | 54 +++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c index 19b550fff0..a49019af60 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"); -- 2.11.0 _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel