diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-02-03 16:48:51 +0100 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-02-08 21:36:01 +0100 |
commit | 0fe4c6fcacb28bda75b31f63d3629f640a6b9bf9 (patch) | |
tree | 8a9592c155aa4f11b74fcab4d79772ba527b88a6 /drivers/ieee1394/raw1394.c | |
parent | 12ba145c9406da72c8288245f352de7f37188f1f (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/raw1394.c')
-rw-r--r-- | drivers/ieee1394/raw1394.c | 48 |
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; |