[patch 21/22] V4L/DVB (9621): Avoid writing outside shadow.bytes[] array

Greg KH
2008-12-17T00:13:01Z

[-- Attachment #1: v4l-dvb-avoid-writing-outside-shadow.bytes-array.patch --]
[-- Type: text/plain, Size: 2549 bytes --]

2.6.27-stable review patch. If anyone has any objections, please let us know.

------------------

From: Mauro Carvalho Chehab <mchehab@redhat.com>

commit 494264379d186bf806613d27aafb7d88d42f4212 upstream.

There were no check about the limits of shadow.bytes array. This offers
a risk of writing values outside the limits, overriding other data
areas.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
drivers/media/video/tvaudio.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)

--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -152,7 +152,7 @@ static int chip_write(struct CHIPSTATE *
{
unsigned char buffer[2];

- if (-1 == subaddr) {
+ if (subaddr < 0) {
v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n",
chip->c->name, val);
chip->shadow.bytes[1] = val;
@@ -163,6 +163,13 @@ static int chip_write(struct CHIPSTATE *
return -1;
}
} else {
+ if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+ v4l_info(chip->c,
+ "Tried to access a non-existent register: %d\n",
+ subaddr);
+ return -EINVAL;
+ }
+
v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n",
chip->c->name, subaddr, val);
chip->shadow.bytes[subaddr+1] = val;
@@ -177,12 +184,20 @@ static int chip_write(struct CHIPSTATE *
return 0;
}

-static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
+static int chip_write_masked(struct CHIPSTATE *chip,
+ int subaddr, int val, int mask)
{
if (mask != 0) {
- if (-1 == subaddr) {
+ if (subaddr < 0) {
val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
} else {
+ if (subaddr + 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+ v4l_info(chip->c,
+ "Tried to access a non-existent register: %d\n",
+ subaddr);
+ return -EINVAL;
+ }
+
val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
}
}
@@ -228,6 +243,15 @@ static int chip_cmd(struct CHIPSTATE *ch
if (0 == cmd->count)
return 0;

+ if (cmd->count + cmd->bytes[0] - 1 >= ARRAY_SIZE(chip->shadow.bytes)) {
+ v4l_info(chip->c,
+ "Tried to access a non-existent register range: %d to %d\n",
+ cmd->bytes[0] + 1, cmd->bytes[0] + cmd->count - 1);
+ return -EINVAL;
+ }
+
+ /* FIXME: it seems that the shadow bytes are wrong bellow !*/
+
/* update our shadow register set; print bytes if (debug > 0) */
v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:",
chip->c->name, name,cmd->bytes[0]);