summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Nelissen <marcone@google.com>2022-06-03 16:28:12 -0700
committerJi Soo Shin <jisshin@google.com>2023-03-06 23:26:37 +0000
commit6bda453bac6190cbf254439383c770793650fa18 (patch)
tree480bfe7aef66cb8c63b3ba9c597d8dfab89153f1
parent36d7af334ec1418e1734e2370bdc0db99dbbd513 (diff)
downloadtrusty-6bda453bac6190cbf254439383c770793650fa18.tar.gz
ANDROID: trusty-log: fix potential use-after-free
Bug: 216130110 Test: unbind driver while in use Signed-off-by: Marco Nelissen <marcone@google.com> Change-Id: Ie1a43f90daea0e4c2d0cd7a1093640a26eb7dce2 (cherry picked from commit 435655cef705e1db72d44f4db05bf417eb21b54d) Signed-off-by: Will McVicker <willmcvicker@google.com>
-rw-r--r--drivers/trusty/trusty-log.c76
1 files changed, 68 insertions, 8 deletions
diff --git a/drivers/trusty/trusty-log.c b/drivers/trusty/trusty-log.c
index 8812cec..654bf0b 100644
--- a/drivers/trusty/trusty-log.c
+++ b/drivers/trusty/trusty-log.c
@@ -188,6 +188,7 @@ struct trusty_log_state {
struct device *dev;
struct device *trusty_dev;
struct trusty_log_sfile log_sfile;
+ struct kref refcount;
/*
* This lock is here to ensure only one consumer will read
@@ -209,6 +210,7 @@ struct trusty_log_state {
spinlock_t wake_up_lock;
u32 last_wake_put;
bool have_first_reader;
+ bool registered;
};
static inline u32 u32_add_overflow(u32 a, u32 b)
@@ -617,6 +619,7 @@ static int trusty_log_sfile_dev_open(struct inode *inode, struct file *file)
sfile->private = ls;
s = container_of(ls, struct trusty_log_state, log_sfile);
s->have_first_reader = true;
+ kref_get(&s->refcount);
return 0;
}
@@ -636,6 +639,12 @@ static unsigned int trusty_log_sfile_dev_poll(struct file *filp,
sfile = filp->private_data;
lb = sfile->private;
s = container_of(lb, struct trusty_log_state, log_sfile);
+
+ if (!s->registered) {
+ dev_err(s->dev, "invalid poll fd\n");
+ return -EINVAL;
+ }
+
poll_wait(filp, &s->poll_waiters, wait);
log = s->log;
@@ -656,12 +665,50 @@ static unsigned int trusty_log_sfile_dev_poll(struct file *filp,
return 0;
}
+static void trusty_log_cleanup(struct kref *ref);
+
+static int trusty_log_sfile_dev_release(struct inode *inode,
+ struct file *filp)
+{
+ struct seq_file *sfile;
+ struct trusty_log_sfile *lb;
+ struct trusty_log_state *s;
+
+ sfile = filp->private_data;
+ lb = sfile->private;
+ s = container_of(lb, struct trusty_log_state, log_sfile);
+
+ kref_put(&s->refcount, trusty_log_cleanup);
+
+ seq_release(inode, filp);
+ return 0;
+}
+
+ssize_t trusty_log_sfile_dev_read(struct file *filp, char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct seq_file *sfile;
+ struct trusty_log_sfile *lb;
+ struct trusty_log_state *s;
+
+ sfile = filp->private_data;
+ lb = sfile->private;
+ s = container_of(lb, struct trusty_log_state, log_sfile);
+
+ if (!s->registered) {
+ dev_err(s->dev, "invalid read fd\n");
+ return -EINVAL;
+ }
+
+ return seq_read(filp, buf, size, ppos);
+}
+
static const struct file_operations log_sfile_dev_operations = {
.owner = THIS_MODULE,
.open = trusty_log_sfile_dev_open,
.poll = trusty_log_sfile_dev_poll,
- .read = seq_read,
- .release = seq_release,
+ .read = trusty_log_sfile_dev_read,
+ .release = trusty_log_sfile_dev_release,
};
static int trusty_log_sfile_register(struct trusty_log_state *s)
@@ -685,6 +732,7 @@ static int trusty_log_sfile_register(struct trusty_log_state *s)
ret);
return ret;
}
+ s->registered = true;
dev_info(s->dev, "/dev/%s registered\n",
ls->device_name);
return 0;
@@ -698,6 +746,7 @@ static void trusty_log_sfile_unregister(struct trusty_log_state *s)
if (s->dev) {
dev_info(s->dev, "/dev/%s unregistered\n",
ls->misc.name);
+ s->registered = false;
}
}
@@ -826,6 +875,7 @@ static int trusty_log_init(struct platform_device *pdev)
goto error_log_sfile;
}
+ kref_init(&s->refcount);
platform_set_drvdata(pdev, s);
return 0;
@@ -877,11 +927,23 @@ static int trusty_log_probe(struct platform_device *pdev)
static int trusty_log_remove(struct platform_device *pdev)
{
- int result;
struct trusty_log_state *s = platform_get_drvdata(pdev);
- trusty_shared_mem_id_t mem_id = s->log_pages_shared_mem_id;
trusty_log_sfile_unregister(s);
+ kref_put(&s->refcount, trusty_log_cleanup);
+ return 0;
+}
+
+static void trusty_log_cleanup(struct kref *ref)
+{
+ int result;
+ struct trusty_log_state *s;
+ trusty_shared_mem_id_t mem_id;
+
+ s = container_of(ref, struct trusty_log_state, refcount);
+ dev_info(s->dev, "log_cleanup\n");
+ mem_id = s->log_pages_shared_mem_id;
+
atomic_notifier_chain_unregister(&panic_notifier_list,
&s->panic_notifier);
trusty_call_notifier_unregister(s->trusty_dev, &s->call_notifier);
@@ -889,14 +951,14 @@ static int trusty_log_remove(struct platform_device *pdev)
result = trusty_std_call32(s->trusty_dev, SMC_SC_SHARED_LOG_RM,
(u32)mem_id, (u32)(mem_id >> 32), 0);
if (result) {
- dev_err(&pdev->dev,
+ dev_err(s->dev,
"trusty std call (SMC_SC_SHARED_LOG_RM) failed: %d\n",
result);
}
result = trusty_reclaim_memory(s->trusty_dev, mem_id, s->sg,
s->log_num_pages);
if (WARN_ON(result)) {
- dev_err(&pdev->dev,
+ dev_err(s->dev,
"trusty failed to remove shared memory: %d\n", result);
} else {
/*
@@ -907,8 +969,6 @@ static int trusty_log_remove(struct platform_device *pdev)
}
kfree(s->sg);
kfree(s);
-
- return 0;
}
static const struct of_device_id trusty_test_of_match[] = {