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);