summaryrefslogtreecommitdiffstats
path: root/drivers/fsi/fsi-master.h
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2018-02-12 15:45:47 +1030
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-03-14 19:11:01 +0100
commite0c24bddf07c7735860fe654061938218732c92d (patch)
treea9b2deb85f7c3a08e2a7f4eeba99e0a471136a66 /drivers/fsi/fsi-master.h
parent638bd9ac847e8cb25f59b6bdca29830ece477ed6 (diff)
downloadlinux-e0c24bddf07c7735860fe654061938218732c92d.tar.bz2
fsi: master: Clarify master lifetimes & fix use-after-free in hub master
Once we call fsi_master_unregister, the core will put_device, potentially freeing the hub master. This change adds a comment explaining the lifetime of an allocated fsi_master. We then add a reference from the driver to the hub master, so it stays around until we've finished ->remove(). Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Tested-by: Christopher Bostic <cbostic@linux.vnet.ibm.com> Signed-off-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/fsi/fsi-master.h')
-rw-r--r--drivers/fsi/fsi-master.h15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 18bd4ad79356..ee0b46086026 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -37,6 +37,21 @@ struct fsi_master {
#define dev_to_fsi_master(d) container_of(d, struct fsi_master, dev)
+/**
+ * fsi_master registration & lifetime: the fsi_master_register() and
+ * fsi_master_unregister() functions will take ownership of the master, and
+ * ->dev in particular. The registration path performs a get_device(), which
+ * takes the first reference on the device. Similarly, the unregistration path
+ * performs a put_device(), which may well drop the last reference.
+ *
+ * This means that master implementations *may* need to hold their own
+ * reference (via get_device()) on master->dev. In particular, if the device's
+ * ->release callback frees the fsi_master, then fsi_master_unregister will
+ * invoke this free if no other reference is held.
+ *
+ * The same applies for the error path of fsi_master_register; if the call
+ * fails, dev->release will have been invoked.
+ */
extern int fsi_master_register(struct fsi_master *master);
extern void fsi_master_unregister(struct fsi_master *master);