summaryrefslogtreecommitdiff
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2007-02-03 16:48:51 +0100
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-02-08 21:36:01 +0100
commit0fe4c6fcacb28bda75b31f63d3629f640a6b9bf9 (patch)
tree8a9592c155aa4f11b74fcab4d79772ba527b88a6 /drivers/ieee1394
parent12ba145c9406da72c8288245f352de7f37188f1f (diff)
ieee1394: raw1394: prevent unloading of low-level driver
Unloading the low-level driver module of a FireWire host can lead to all sorts of trouble if a raw1394 userspace client is using the host. Just disallow it by incrementing the LLD's module reference count on a RAW1394_REQ_SET_CARD write operation. Decrement it when the file is closed. This feature wouldn't be relevant if "modprobe -r video1394" or "modprobe -r dv1394" didn't automatically unload ohci1394 too. http://bugzilla.kernel.org/show_bug.cgi?id=7701 Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Dan Dennedy <dan@dennedy.org>
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r--drivers/ieee1394/raw1394.c48
1 files changed, 29 insertions, 19 deletions
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index ad2108f27a04..a77a832828c8 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -636,27 +636,32 @@ static int state_initialized(struct file_info *fi, struct pending_request *req)
case RAW1394_REQ_SET_CARD:
spin_lock_irqsave(&host_info_lock, flags);
- if (req->req.misc < host_count) {
- list_for_each_entry(hi, &host_info_list, list) {
- if (!req->req.misc--)
- break;
- }
- get_device(&hi->host->device); // XXX Need to handle failure case
- list_add_tail(&fi->list, &hi->file_info_list);
- fi->host = hi->host;
- fi->state = connected;
-
- req->req.error = RAW1394_ERROR_NONE;
- req->req.generation = get_hpsb_generation(fi->host);
- req->req.misc = (fi->host->node_id << 16)
- | fi->host->node_count;
- if (fi->protocol_version > 3) {
- req->req.misc |=
- NODEID_TO_NODE(fi->host->irm_id) << 8;
- }
- } else {
+ if (req->req.misc >= host_count) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
+ goto out_set_card;
}
+ list_for_each_entry(hi, &host_info_list, list)
+ if (!req->req.misc--)
+ break;
+ get_device(&hi->host->device); /* FIXME handle failure case */
+ list_add_tail(&fi->list, &hi->file_info_list);
+
+ /* prevent unloading of the host's low-level driver */
+ if (!try_module_get(hi->host->driver->owner)) {
+ req->req.error = RAW1394_ERROR_ABORTED;
+ goto out_set_card;
+ }
+ WARN_ON(fi->host);
+ fi->host = hi->host;
+ fi->state = connected;
+
+ req->req.error = RAW1394_ERROR_NONE;
+ req->req.generation = get_hpsb_generation(fi->host);
+ req->req.misc = (fi->host->node_id << 16)
+ | fi->host->node_count;
+ if (fi->protocol_version > 3)
+ req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
+out_set_card:
spin_unlock_irqrestore(&host_info_lock, flags);
req->req.length = 0;
@@ -2955,6 +2960,11 @@ static int raw1394_release(struct inode *inode, struct file *file)
put_device(&fi->host->device);
}
+ spin_lock_irqsave(&host_info_lock, flags);
+ if (fi->host)
+ module_put(fi->host->driver->owner);
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
kfree(fi);
return 0;