Skip to content

Commit 35d2969

Browse files
Dan Carpentermchehab
authored andcommitted
media: firewire: firedtv-avc: fix a buffer overflow in avc_ca_pmt()
The bounds checking in avc_ca_pmt() is not strict enough. It should be checking "read_pos + 4" because it's reading 5 bytes. If the "es_info_length" is non-zero then it reads a 6th byte so there needs to be an additional check for that. I also added checks for the "write_pos". I don't think these are required because "read_pos" and "write_pos" are tied together so checking one ought to be enough. But they make the code easier to understand for me. The check on write_pos is: if (write_pos + 4 >= sizeof(c->operand) - 4) { The first "+ 4" is because we're writing 5 bytes and the last " - 4" is to leave space for the CRC. The other problem is that "length" can be invalid. It comes from "data_length" in fdtv_ca_pmt(). Cc: stable@vger.kernel.org Reported-by: Luo Likang <luolikang@nsfocus.com> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
1 parent 9031d6b commit 35d2969

File tree

2 files changed

+13
-3
lines changed

2 files changed

+13
-3
lines changed

drivers/media/firewire/firedtv-avc.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,11 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
11651165
read_pos += program_info_length;
11661166
write_pos += program_info_length;
11671167
}
1168-
while (read_pos < length) {
1168+
while (read_pos + 4 < length) {
1169+
if (write_pos + 4 >= sizeof(c->operand) - 4) {
1170+
ret = -EINVAL;
1171+
goto out;
1172+
}
11691173
c->operand[write_pos++] = msg[read_pos++];
11701174
c->operand[write_pos++] = msg[read_pos++];
11711175
c->operand[write_pos++] = msg[read_pos++];
@@ -1177,13 +1181,17 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
11771181
c->operand[write_pos++] = es_info_length >> 8;
11781182
c->operand[write_pos++] = es_info_length & 0xff;
11791183
if (es_info_length > 0) {
1184+
if (read_pos >= length) {
1185+
ret = -EINVAL;
1186+
goto out;
1187+
}
11801188
pmt_cmd_id = msg[read_pos++];
11811189
if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
11821190
dev_err(fdtv->device, "invalid pmt_cmd_id %d at stream level\n",
11831191
pmt_cmd_id);
11841192

1185-
if (es_info_length > sizeof(c->operand) - 4 -
1186-
write_pos) {
1193+
if (es_info_length > sizeof(c->operand) - 4 - write_pos ||
1194+
es_info_length > length - read_pos) {
11871195
ret = -EINVAL;
11881196
goto out;
11891197
}

drivers/media/firewire/firedtv-ci.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
134134
} else {
135135
data_length = msg->msg[3];
136136
}
137+
if (data_length > sizeof(msg->msg) - data_pos)
138+
return -EINVAL;
137139

138140
return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length);
139141
}

0 commit comments

Comments
 (0)