diff options
author | Michael Büsch <m@bues.ch> | 2012-04-01 23:33:48 +0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-04-09 21:45:37 +0400 |
commit | b1a9599a0d228d6555ad9e5c1fe0b0dfac7c5ccb (patch) | |
tree | 1f63f9895b47be7b0e0acb544323b7df826c6247 /drivers/media/dvb | |
parent | 812fe6d9426a23ad78055f1fa955acef9bea9a93 (diff) | |
download | linux-b1a9599a0d228d6555ad9e5c1fe0b0dfac7c5ccb.tar.xz |
[media] af9035: Add USB read checksumming
This adds USB message read checksumming to protect against
device and bus errors.
It also adds a read length check to avoid returning garbage from
the buffer, if the device truncated the message.
Signed-off-by: Michael Buesch <m@bues.ch>
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r-- | drivers/media/dvb/dvb-usb/af9035.c | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c index 6a83120afcd6..92d27aa80800 100644 --- a/drivers/media/dvb/dvb-usb/af9035.c +++ b/drivers/media/dvb/dvb-usb/af9035.c @@ -36,6 +36,22 @@ static struct af9033_config af9035_af9033_config[] = { } }; +static u16 af9035_checksum(const u8 *buf, size_t len) +{ + size_t i; + u16 checksum = 0; + + for (i = 1; i < len; i++) { + if (i % 2) + checksum += buf[i] << 8; + else + checksum += buf[i]; + } + checksum = ~checksum; + + return checksum; +} + static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) { #define BUF_LEN 63 @@ -44,11 +60,11 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) #define CHECKSUM_LEN 2 #define USB_TIMEOUT 2000 - int ret, i, act_len; + int ret, act_len; u8 buf[BUF_LEN]; u32 msg_len; static u8 seq; /* packet sequence number */ - u16 checksum = 0; + u16 checksum, tmpsum; /* buffer overflow check */ if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || @@ -69,14 +85,7 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) memcpy(&buf[4], req->wbuf, req->wlen); /* calc and add checksum */ - for (i = 1; i < buf[0]-1; i++) { - if (i % 2) - checksum += buf[i] << 8; - else - checksum += buf[i]; - } - checksum = ~checksum; - + checksum = af9035_checksum(buf, buf[0] - 1); buf[buf[0]-1] = (checksum >> 8); buf[buf[0]-0] = (checksum & 0xff); @@ -106,7 +115,23 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req) ret = -EIO; goto err_mutex_unlock; } + if (act_len != msg_len) { + err("recv bulk message truncated (%d != %u)\n", + act_len, (unsigned int)msg_len); + ret = -EIO; + goto err_mutex_unlock; + } + /* verify checksum */ + checksum = af9035_checksum(buf, act_len - 2); + tmpsum = (buf[act_len - 2] << 8) | buf[act_len - 1]; + if (tmpsum != checksum) { + err("%s: command=%02X checksum mismatch (%04X != %04X)\n", + __func__, req->cmd, + (unsigned int)tmpsum, (unsigned int)checksum); + ret = -EIO; + goto err_mutex_unlock; + } /* check status */ if (buf[2]) { pr_debug("%s: command=%02x failed fw error=%d\n", __func__, |