aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-05-19 02:28:32 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-06-09 13:42:18 -0400
commita10c0ce76098857b899505d05de9f2e13ddf7a7a (patch)
tree130592c6baaff2e38dd813448337dded1ee1645b /drivers
parent262444eecce40950af19ea4d75a3dc03b3c07283 (diff)
firewire: check cdev response length
Add a check that the data length in the SEND_RESPONSE ioctl is correct. Incidentally, this also fixes the previously wrong response length of software-handled lock requests. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firewire/core-cdev.c9
-rw-r--r--drivers/firewire/core-transaction.c38
-rw-r--r--drivers/firewire/core.h1
3 files changed, 44 insertions, 4 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 9d1a1a1a83c9..50332b84f49a 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -756,9 +756,12 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
756 if (is_fcp_request(r->request)) 756 if (is_fcp_request(r->request))
757 goto out; 757 goto out;
758 758
759 if (a->length < r->length) 759 if (a->length != fw_get_response_length(r->request)) {
760 r->length = a->length; 760 ret = -EINVAL;
761 if (copy_from_user(r->data, u64_to_uptr(a->data), r->length)) { 761 kfree(r->request);
762 goto out;
763 }
764 if (copy_from_user(r->data, u64_to_uptr(a->data), a->length)) {
762 ret = -EFAULT; 765 ret = -EFAULT;
763 kfree(r->request); 766 kfree(r->request);
764 goto out; 767 goto out;
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index fdc33ff06dc1..4fd5c3b2128e 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -580,6 +580,41 @@ static void free_response_callback(struct fw_packet *packet,
580 kfree(request); 580 kfree(request);
581} 581}
582 582
583int fw_get_response_length(struct fw_request *r)
584{
585 int tcode, ext_tcode, data_length;
586
587 tcode = HEADER_GET_TCODE(r->request_header[0]);
588
589 switch (tcode) {
590 case TCODE_WRITE_QUADLET_REQUEST:
591 case TCODE_WRITE_BLOCK_REQUEST:
592 return 0;
593
594 case TCODE_READ_QUADLET_REQUEST:
595 return 4;
596
597 case TCODE_READ_BLOCK_REQUEST:
598 data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
599 return data_length;
600
601 case TCODE_LOCK_REQUEST:
602 ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);
603 data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
604 switch (ext_tcode) {
605 case EXTCODE_FETCH_ADD:
606 case EXTCODE_LITTLE_ADD:
607 return data_length;
608 default:
609 return data_length / 2;
610 }
611
612 default:
613 WARN(1, KERN_ERR "wrong tcode %d", tcode);
614 return 0;
615 }
616}
617
583void fw_fill_response(struct fw_packet *response, u32 *request_header, 618void fw_fill_response(struct fw_packet *response, u32 *request_header,
584 int rcode, void *payload, size_t length) 619 int rcode, void *payload, size_t length)
585{ 620{
@@ -713,7 +748,8 @@ void fw_send_response(struct fw_card *card,
713 748
714 if (rcode == RCODE_COMPLETE) 749 if (rcode == RCODE_COMPLETE)
715 fw_fill_response(&request->response, request->request_header, 750 fw_fill_response(&request->response, request->request_header,
716 rcode, request->data, request->length); 751 rcode, request->data,
752 fw_get_response_length(request));
717 else 753 else
718 fw_fill_response(&request->response, request->request_header, 754 fw_fill_response(&request->response, request->request_header,
719 rcode, NULL, 0); 755 rcode, NULL, 0);
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 0ecfcd95f4c5..25a72e57a0cd 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -218,6 +218,7 @@ static inline bool is_next_generation(int new_generation, int old_generation)
218 218
219void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); 219void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
220void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); 220void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
221int fw_get_response_length(struct fw_request *request);
221void fw_fill_response(struct fw_packet *response, u32 *request_header, 222void fw_fill_response(struct fw_packet *response, u32 *request_header,
222 int rcode, void *payload, size_t length); 223 int rcode, void *payload, size_t length);
223void fw_send_phy_config(struct fw_card *card, 224void fw_send_phy_config(struct fw_card *card,