firewire: cdev: address handler input validation
authorStefan Richter <stefanr@s5r6.in-berlin.de>
Sun, 14 Dec 2008 18:21:01 +0000 (19:21 +0100)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Tue, 24 Mar 2009 19:56:38 +0000 (20:56 +0100)
Like before my commit 1415d9189e8c59aa9c77a3bba419dcea062c145f,
fw_core_add_address_handler() does not align the address region now.
Instead the caller is required to pass valid parameters.

Since one of the callers of fw_core_add_address_handler() is the cdev
userspace interface, we now check for valid input.  If the client is
buggy, we give it a hint with -EINVAL.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
drivers/firewire/fw-cdev.c
drivers/firewire/fw-transaction.c

index 094aee5..44af452 100644 (file)
@@ -591,9 +591,10 @@ static int ioctl_allocate(struct client *client, void *buffer)
        handler->closure = request->closure;
        handler->client = client;
 
-       if (fw_core_add_address_handler(&handler->handler, &region) < 0) {
+       ret = fw_core_add_address_handler(&handler->handler, &region);
+       if (ret < 0) {
                kfree(handler);
-               return -EBUSY;
+               return ret;
        }
 
        handler->resource.release = release_address_handler;
index 699ac04..12a6cdc 100644 (file)
@@ -449,16 +449,19 @@ const struct fw_address_region fw_unit_space_region =
 #endif  /*  0  */
 
 /**
- * Allocate a range of addresses in the node space of the OHCI
- * controller.  When a request is received that falls within the
- * specified address range, the specified callback is invoked.  The
- * parameters passed to the callback give the details of the
- * particular request.
+ * fw_core_add_address_handler - register for incoming requests
+ * @handler: callback
+ * @region: region in the IEEE 1212 node space address range
+ *
+ * region->start, ->end, and handler->length have to be quadlet-aligned.
+ *
+ * When a request is received that falls within the specified address range,
+ * the specified callback is invoked.  The parameters passed to the callback
+ * give the details of the particular request.
  *
  * Return value:  0 on success, non-zero otherwise.
  * The start offset of the handler's address region is determined by
  * fw_core_add_address_handler() and is returned in handler->offset.
- * The offset is quadlet-aligned.
  */
 int
 fw_core_add_address_handler(struct fw_address_handler *handler,
@@ -468,17 +471,23 @@ fw_core_add_address_handler(struct fw_address_handler *handler,
        unsigned long flags;
        int ret = -EBUSY;
 
+       if (region->start & 0xffff000000000003ULL ||
+           region->end   & 0xffff000000000003ULL ||
+           region->start >= region->end ||
+           handler->length & 3 ||
+           handler->length == 0)
+               return -EINVAL;
+
        spin_lock_irqsave(&address_handler_lock, flags);
 
-       handler->offset = roundup(region->start, 4);
+       handler->offset = region->start;
        while (handler->offset + handler->length <= region->end) {
                other =
                    lookup_overlapping_address_handler(&address_handler_list,
                                                       handler->offset,
                                                       handler->length);
                if (other != NULL) {
-                       handler->offset =
-                           roundup(other->offset + other->length, 4);
+                       handler->offset += other->length;
                } else {
                        list_add_tail(&handler->link, &address_handler_list);
                        ret = 0;