Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Jan 2010 20:56:23 +0000 (12:56 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Jan 2010 20:56:23 +0000 (12:56 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6:
  firewire: ohci: fix crashes with TSB43AB23 on 64bit systems
  firewire: core: fix use-after-free regression in FCP handler
  firewire: cdev: add_descriptor documentation fix
  firewire: core: add_descriptor size check

drivers/firewire/core-card.c
drivers/firewire/core-cdev.c
drivers/firewire/ohci.c
include/linux/firewire-cdev.h

index 7083bcc1b9c7c282fe1a56c7a7dba65e1ea9543e..5045156c5313b0c59114850f003f17ef46945c36 100644 (file)
@@ -57,6 +57,8 @@ static LIST_HEAD(descriptor_list);
 static int descriptor_count;
 
 static __be32 tmp_config_rom[256];
+/* ROM header, bus info block, root dir header, capabilities = 7 quadlets */
+static size_t config_rom_length = 1 + 4 + 1 + 1;
 
 #define BIB_CRC(v)             ((v) <<  0)
 #define BIB_CRC_LENGTH(v)      ((v) << 16)
@@ -73,7 +75,7 @@ static __be32 tmp_config_rom[256];
 #define BIB_CMC                        ((1) << 30)
 #define BIB_IMC                        ((1) << 31)
 
-static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
+static void generate_config_rom(struct fw_card *card, __be32 *config_rom)
 {
        struct fw_descriptor *desc;
        int i, j, k, length;
@@ -130,23 +132,30 @@ static size_t generate_config_rom(struct fw_card *card, __be32 *config_rom)
        for (i = 0; i < j; i += length + 1)
                length = fw_compute_block_crc(config_rom + i);
 
-       return j;
+       WARN_ON(j != config_rom_length);
 }
 
 static void update_config_roms(void)
 {
        struct fw_card *card;
-       size_t length;
 
        list_for_each_entry (card, &card_list, link) {
-               length = generate_config_rom(card, tmp_config_rom);
-               card->driver->set_config_rom(card, tmp_config_rom, length);
+               generate_config_rom(card, tmp_config_rom);
+               card->driver->set_config_rom(card, tmp_config_rom,
+                                            config_rom_length);
        }
 }
 
+static size_t required_space(struct fw_descriptor *desc)
+{
+       /* descriptor + entry into root dir + optional immediate entry */
+       return desc->length + 1 + (desc->immediate > 0 ? 1 : 0);
+}
+
 int fw_core_add_descriptor(struct fw_descriptor *desc)
 {
        size_t i;
+       int ret;
 
        /*
         * Check descriptor is valid; the length of all blocks in the
@@ -162,15 +171,21 @@ int fw_core_add_descriptor(struct fw_descriptor *desc)
 
        mutex_lock(&card_mutex);
 
-       list_add_tail(&desc->link, &descriptor_list);
-       descriptor_count++;
-       if (desc->immediate > 0)
+       if (config_rom_length + required_space(desc) > 256) {
+               ret = -EBUSY;
+       } else {
+               list_add_tail(&desc->link, &descriptor_list);
+               config_rom_length += required_space(desc);
                descriptor_count++;
-       update_config_roms();
+               if (desc->immediate > 0)
+                       descriptor_count++;
+               update_config_roms();
+               ret = 0;
+       }
 
        mutex_unlock(&card_mutex);
 
-       return 0;
+       return ret;
 }
 EXPORT_SYMBOL(fw_core_add_descriptor);
 
@@ -179,6 +194,7 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
        mutex_lock(&card_mutex);
 
        list_del(&desc->link);
+       config_rom_length -= required_space(desc);
        descriptor_count--;
        if (desc->immediate > 0)
                descriptor_count--;
@@ -428,7 +444,6 @@ EXPORT_SYMBOL(fw_card_initialize);
 int fw_card_add(struct fw_card *card,
                u32 max_receive, u32 link_speed, u64 guid)
 {
-       size_t length;
        int ret;
 
        card->max_receive = max_receive;
@@ -437,8 +452,8 @@ int fw_card_add(struct fw_card *card,
 
        mutex_lock(&card_mutex);
 
-       length = generate_config_rom(card, tmp_config_rom);
-       ret = card->driver->enable(card, tmp_config_rom, length);
+       generate_config_rom(card, tmp_config_rom);
+       ret = card->driver->enable(card, tmp_config_rom, config_rom_length);
        if (ret == 0)
                list_add_tail(&card->link, &card_list);
 
index e6d63849e78ee44302e436c26f871e5b3dd3eef7..4eeaed57e2197a0dd5f0cab7cffa4713eaf2ec96 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/preempt.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 #include <linux/time.h>
 #include <linux/uaccess.h>
 #include <linux/vmalloc.h>
@@ -595,13 +596,20 @@ static int ioctl_send_request(struct client *client, void *buffer)
                            client->device->max_speed);
 }
 
+static inline bool is_fcp_request(struct fw_request *request)
+{
+       return request == NULL;
+}
+
 static void release_request(struct client *client,
                            struct client_resource *resource)
 {
        struct inbound_transaction_resource *r = container_of(resource,
                        struct inbound_transaction_resource, resource);
 
-       if (r->request)
+       if (is_fcp_request(r->request))
+               kfree(r->data);
+       else
                fw_send_response(client->device->card, r->request,
                                 RCODE_CONFLICT_ERROR);
        kfree(r);
@@ -616,6 +624,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
        struct address_handler_resource *handler = callback_data;
        struct inbound_transaction_resource *r;
        struct inbound_transaction_event *e;
+       void *fcp_frame = NULL;
        int ret;
 
        r = kmalloc(sizeof(*r), GFP_ATOMIC);
@@ -627,6 +636,18 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
        r->data    = payload;
        r->length  = length;
 
+       if (is_fcp_request(request)) {
+               /*
+                * FIXME: Let core-transaction.c manage a
+                * single reference-counted copy?
+                */
+               fcp_frame = kmemdup(payload, length, GFP_ATOMIC);
+               if (fcp_frame == NULL)
+                       goto failed;
+
+               r->data = fcp_frame;
+       }
+
        r->resource.release = release_request;
        ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
        if (ret < 0)
@@ -640,13 +661,15 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
        e->request.closure = handler->closure;
 
        queue_event(handler->client, &e->event,
-                   &e->request, sizeof(e->request), payload, length);
+                   &e->request, sizeof(e->request), r->data, length);
        return;
 
  failed:
        kfree(r);
        kfree(e);
-       if (request)
+       kfree(fcp_frame);
+
+       if (!is_fcp_request(request))
                fw_send_response(card, request, RCODE_CONFLICT_ERROR);
 }
 
@@ -717,18 +740,17 @@ static int ioctl_send_response(struct client *client, void *buffer)
 
        r = container_of(resource, struct inbound_transaction_resource,
                         resource);
-       if (r->request) {
-               if (request->length < r->length)
-                       r->length = request->length;
-               if (copy_from_user(r->data, u64_to_uptr(request->data),
-                                  r->length)) {
-                       ret = -EFAULT;
-                       kfree(r->request);
-                       goto out;
-               }
-               fw_send_response(client->device->card, r->request,
-                                request->rcode);
+       if (is_fcp_request(r->request))
+               goto out;
+
+       if (request->length < r->length)
+               r->length = request->length;
+       if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
+               ret = -EFAULT;
+               kfree(r->request);
+               goto out;
        }
+       fw_send_response(client->device->card, r->request, request->rcode);
  out:
        kfree(r);
 
index a61571c63c595161f1aceb004a3d99677971b403..2345d4103fe6b3c3a62d7f8fc67bd1db049083b2 100644 (file)
@@ -2420,6 +2420,7 @@ static void ohci_pmac_off(struct pci_dev *dev)
 
 #define PCI_VENDOR_ID_AGERE            PCI_VENDOR_ID_ATT
 #define PCI_DEVICE_ID_AGERE_FW643      0x5901
+#define PCI_DEVICE_ID_TI_TSB43AB23     0x8024
 
 static int __devinit pci_probe(struct pci_dev *dev,
                               const struct pci_device_id *ent)
@@ -2488,7 +2489,8 @@ static int __devinit pci_probe(struct pci_dev *dev,
 #if !defined(CONFIG_X86_32)
        /* dual-buffer mode is broken with descriptor addresses above 2G */
        if (dev->vendor == PCI_VENDOR_ID_TI &&
-           dev->device == PCI_DEVICE_ID_TI_TSB43AB22)
+           (dev->device == PCI_DEVICE_ID_TI_TSB43AB22 ||
+            dev->device == PCI_DEVICE_ID_TI_TSB43AB23))
                ohci->use_dualbuffer = false;
 #endif
 
index 1f716d9f714b05b00d949891fd0b550e48fbee36..520ecf86cbb37b00bc7ec893bac4843b452fdeed 100644 (file)
@@ -380,7 +380,7 @@ struct fw_cdev_initiate_bus_reset {
  * @immediate: If non-zero, immediate key to insert before pointer
  * @key:       Upper 8 bits of root directory pointer
  * @data:      Userspace pointer to contents of descriptor block
- * @length:    Length of descriptor block data, in bytes
+ * @length:    Length of descriptor block data, in quadlets
  * @handle:    Handle to the descriptor, written by the kernel
  *
  * Add a descriptor block and optionally a preceding immediate key to the local
@@ -394,6 +394,8 @@ struct fw_cdev_initiate_bus_reset {
  * If not 0, the @immediate field specifies an immediate key which will be
  * inserted before the root directory pointer.
  *
+ * @immediate, @key, and @data array elements are CPU-endian quadlets.
+ *
  * If successful, the kernel adds the descriptor and writes back a handle to the
  * kernel-side object to be used for later removal of the descriptor block and
  * immediate key.