base: genlock: Avoid a race condition when releasing locks

Avoid a race condition if a lock gets released by all owners
but a process fails to close a lock file descriptor and tries
to reuse it.  Clearing the pointers to the data will ensure
that attaching a dead lock will return an error.

Change-Id: Ic0dedbadd693c7a22b027052cdd247370b28a7c5
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 41bbd3a..dcc1d28 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -48,11 +48,28 @@
 				     taken */
 };
 
+/*
+ * Create a spinlock to protect against a race condition when a lock gets
+ * released while another process tries to attach it
+ */
+
+static DEFINE_SPINLOCK(genlock_file_lock);
+
 static void genlock_destroy(struct kref *kref)
 {
 	struct genlock *lock = container_of(kref, struct genlock,
 			refcount);
 
+	/*
+	 * Clear the private data for the file descriptor in case the fd is
+	 * still active after the lock gets released
+	 */
+
+	spin_lock(&genlock_file_lock);
+	if (lock->file)
+		lock->file->private_data = NULL;
+	spin_unlock(&genlock_file_lock);
+
 	kfree(lock);
 }
 
@@ -63,6 +80,15 @@
 
 static int genlock_release(struct inode *inodep, struct file *file)
 {
+	struct genlock *lock = file->private_data;
+	/*
+	 * Clear the refrence back to this file structure to avoid
+	 * somehow reusing the lock after the file has been destroyed
+	 */
+
+	if (lock)
+		lock->file = NULL;
+
 	return 0;
 }
 
@@ -119,7 +145,7 @@
 {
 	int ret;
 
-	if (!lock->file)
+	if (lock->file == NULL)
 		return -EINVAL;
 
 	ret = get_unused_fd_flags(0);
@@ -149,7 +175,14 @@
 	if (file == NULL)
 		return ERR_PTR(-EBADF);
 
+	/*
+	 * take a spinlock to avoid a race condition if the lock is
+	 * released and then attached
+	 */
+
+	spin_lock(&genlock_file_lock);
 	lock = file->private_data;
+	spin_unlock(&genlock_file_lock);
 
 	fput(file);