summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChase Wu <chasewu@google.com>2023-01-12 15:31:04 +0800
committerChase Wu <chasewu@google.com>2023-01-12 17:44:26 +0800
commit31ef461089e795b4347499e792a6a5c88425aeae (patch)
tree4c639713c3c5888832275c2e9be269b5239f8fd0
parent35d385c24c28edeeab94483ee9beb423b5eee3c1 (diff)
downloadamplifiers-31ef461089e795b4347499e792a6a5c88425aeae.tar.gz
Use strscpy to write to the buffer in cs40l2x_cp_trigger_queue_show to avoid writing incorrect addresses using snprintf. Also, checking to see if the input trigger queue string is too large. Bug: 224000736 Test: push a poc file and check the log Change-Id: Id46d8a0dbe8eea188362e4f2ca54ccbd720d2bc8 Signed-off-by: Paul Handrigan <Paul.Handrigan@cirrus.com> Signed-off-by: Chase Wu <chasewu@google.com>
-rw-r--r--cs40l25/cs40l2x.c36
-rw-r--r--cs40l25/include/linux/mfd/cs40l2x.h1
2 files changed, 30 insertions, 7 deletions
diff --git a/cs40l25/cs40l2x.c b/cs40l25/cs40l2x.c
index c4dadf5..940b5a2 100644
--- a/cs40l25/cs40l2x.c
+++ b/cs40l25/cs40l2x.c
@@ -1393,41 +1393,56 @@ static ssize_t cs40l2x_cp_trigger_queue_show(struct device *dev,
{
struct cs40l2x_private *cs40l2x = cs40l2x_get_private(dev);
struct wt_type10_comp_section *section = cs40l2x->pbq_comp.sections;
+ char *pbq_str;
int i, len = 0;
+ if (!cs40l2x->pbq_str_size) {
+ dev_err(dev, "PBQ string is not set\n");
+ return -EPERM;
+ }
+
+ pbq_str = kzalloc(cs40l2x->pbq_str_size + 1, GFP_KERNEL);
+ if (!pbq_str)
+ return -ENOMEM;
+
mutex_lock(&cs40l2x->lock);
for (i = 0; i < cs40l2x->pbq_comp.nsections; i++, section++) {
if (section->repeat == WT_REPEAT_LOOP_MARKER)
- len += snprintf(buf + len, PAGE_SIZE - len, "!!, ");
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "!!, ");
if (section->amplitude)
- len += snprintf(buf + len, PAGE_SIZE - len, "%d.%d, ",
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "%d.%d, ",
section->index, section->amplitude);
if (section->delay)
- len += snprintf(buf + len, PAGE_SIZE - len, "%d, ",
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "%d, ",
section->delay);
if (section->repeat && section->repeat != WT_REPEAT_LOOP_MARKER)
- len += snprintf(buf + len, PAGE_SIZE - len, "%d!!, ",
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "%d!!, ",
section->repeat);
}
switch (cs40l2x->pbq_comp.repeat) {
case WT_REPEAT_LOOP_MARKER:
- len += snprintf(buf + len, PAGE_SIZE - len, "~\n");
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "~\n");
break;
case 0:
len -= 2; // Remove ", " from end of string
- len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "\n");
break;
default:
- len += snprintf(buf + len, PAGE_SIZE - len, "%d!\n",
+ len += snprintf(pbq_str + len, PAGE_SIZE - len, "%d!\n",
cs40l2x->pbq_comp.repeat);
}
+ len = strscpy(buf, pbq_str, PAGE_SIZE);
+ if (len == -E2BIG)
+ dev_err(dev, "String too large for buffer\n");
+
mutex_unlock(&cs40l2x->lock);
+ kfree(pbq_str);
return len;
}
@@ -1493,10 +1508,17 @@ static ssize_t cs40l2x_cp_trigger_queue_store(struct device *dev,
bool inner_loop = false;
int ret;
+ if (count >= PAGE_SIZE) {
+ dev_err(dev, "Trigger queue string too large\n");
+ return -E2BIG;
+ }
+
pbq_str = kstrndup(buf, count, GFP_KERNEL);
if (!pbq_str)
return -ENOMEM;
+ cs40l2x->pbq_str_size = count;
+
disable_irq(i2c_client->irq);
mutex_lock(&cs40l2x->lock);
diff --git a/cs40l25/include/linux/mfd/cs40l2x.h b/cs40l25/include/linux/mfd/cs40l2x.h
index 97bc1f4..58eb4f8 100644
--- a/cs40l25/include/linux/mfd/cs40l2x.h
+++ b/cs40l25/include/linux/mfd/cs40l2x.h
@@ -1460,6 +1460,7 @@ struct cs40l2x_private {
struct wt_type10_comp pbq_comp;
unsigned int pbq_index;
unsigned int pbq_state;
+ size_t pbq_str_size;
int pbq_inner_mark;
int pbq_inner_loop;
int pbq_outer_loop;