diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-02-03 10:48:51 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-02-08 15:36:01 -0500 |
commit | 0fe4c6fcacb28bda75b31f63d3629f640a6b9bf9 (patch) | |
tree | 8a9592c155aa4f11b74fcab4d79772ba527b88a6 | |
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>
-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) | |||
636 | 636 | ||
637 | case RAW1394_REQ_SET_CARD: | 637 | case RAW1394_REQ_SET_CARD: |
638 | spin_lock_irqsave(&host_info_lock, flags); | 638 | spin_lock_irqsave(&host_info_lock, flags); |
639 | if (req->req.misc < host_count) { | 639 | if (req->req.misc >= host_count) { |
640 | list_for_each_entry(hi, &host_info_list, list) { | ||
641 | if (!req->req.misc--) | ||
642 | break; | ||
643 | } | ||
644 | get_device(&hi->host->device); // XXX Need to handle failure case | ||
645 | list_add_tail(&fi->list, &hi->file_info_list); | ||
646 | fi->host = hi->host; | ||
647 | fi->state = connected; | ||
648 | |||
649 | req->req.error = RAW1394_ERROR_NONE; | ||
650 | req->req.generation = get_hpsb_generation(fi->host); | ||
651 | req->req.misc = (fi->host->node_id << 16) | ||
652 | | fi->host->node_count; | ||
653 | if (fi->protocol_version > 3) { | ||
654 | req->req.misc |= | ||
655 | NODEID_TO_NODE(fi->host->irm_id) << 8; | ||
656 | } | ||
657 | } else { | ||
658 | req->req.error = RAW1394_ERROR_INVALID_ARG; | 640 | req->req.error = RAW1394_ERROR_INVALID_ARG; |
641 | goto out_set_card; | ||
659 | } | 642 | } |
643 | list_for_each_entry(hi, &host_info_list, list) | ||
644 | if (!req->req.misc--) | ||
645 | break; | ||
646 | get_device(&hi->host->device); /* FIXME handle failure case */ | ||
647 | list_add_tail(&fi->list, &hi->file_info_list); | ||
648 | |||
649 | /* prevent unloading of the host's low-level driver */ | ||
650 | if (!try_module_get(hi->host->driver->owner)) { | ||
651 | req->req.error = RAW1394_ERROR_ABORTED; | ||
652 | goto out_set_card; | ||
653 | } | ||
654 | WARN_ON(fi->host); | ||
655 | fi->host = hi->host; | ||
656 | fi->state = connected; | ||
657 | |||
658 | req->req.error = RAW1394_ERROR_NONE; | ||
659 | req->req.generation = get_hpsb_generation(fi->host); | ||
660 | req->req.misc = (fi->host->node_id << 16) | ||
661 | | fi->host->node_count; | ||
662 | if (fi->protocol_version > 3) | ||
663 | req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8; | ||
664 | out_set_card: | ||
660 | spin_unlock_irqrestore(&host_info_lock, flags); | 665 | spin_unlock_irqrestore(&host_info_lock, flags); |
661 | 666 | ||
662 | req->req.length = 0; | 667 | req->req.length = 0; |
@@ -2955,6 +2960,11 @@ static int raw1394_release(struct inode *inode, struct file *file) | |||
2955 | put_device(&fi->host->device); | 2960 | put_device(&fi->host->device); |
2956 | } | 2961 | } |
2957 | 2962 | ||
2963 | spin_lock_irqsave(&host_info_lock, flags); | ||
2964 | if (fi->host) | ||
2965 | module_put(fi->host->driver->owner); | ||
2966 | spin_unlock_irqrestore(&host_info_lock, flags); | ||
2967 | |||
2958 | kfree(fi); | 2968 | kfree(fi); |
2959 | 2969 | ||
2960 | return 0; | 2970 | return 0; |