qcacmn: Fix for read and write operations in wmi_recording
With linux4.4 definition of seq_printf is changed. New definition
updated in driver applies va_start twice which causes incorrect
output hence definition is updated to make sure va_start is applied
only once. For write operations using copy_from_user to avoid
crash due to accessing user space area.
CRs-Fixed: 2042210
IRs-Fixed: 201729
Change-Id: I4043ab027411d42e15adaf53e6e92ae57aa987c7
diff --git a/wmi_unified.c b/wmi_unified.c
index f886fb2..5c19580 100644
--- a/wmi_unified.c
+++ b/wmi_unified.c
@@ -98,18 +98,18 @@
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0))
/* TODO Cleanup this backported function */
-static int qcacld_bp_seq_printf(struct seq_file *m, const char *f, ...)
+static int wmi_bp_seq_printf(struct seq_file *m, const char *f, ...)
{
va_list args;
va_start(args, f);
- seq_printf(m, f, args);
+ seq_vprintf(m, f, args);
va_end(args);
- return m->count;
+ return 0;
}
-
-#define seq_printf(m, fmt, ...) qcacld_bp_seq_printf((m), fmt, ##__VA_ARGS__)
+#else
+#define wmi_bp_seq_printf(m, fmt, ...) seq_printf((m), fmt, ##__VA_ARGS__)
#endif
#define WMI_MIN_HEAD_ROOM 64
@@ -758,7 +758,7 @@
qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock); \
if (!wmi_log->length) { \
qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);\
- return seq_printf(m, \
+ return wmi_bp_seq_printf(m, \
"no elements to read from ring buffer!\n"); \
} \
\
@@ -773,28 +773,27 @@
else \
pos = *(wmi_log->p_buf_tail_idx) - 1; \
\
- outlen = seq_printf(m, "Length = %d\n", wmi_log->length);\
+ outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\
qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock); \
while (nread--) { \
struct wmi_command_debug *wmi_record; \
\
wmi_record = (struct wmi_command_debug *) \
&(((struct wmi_command_debug *)wmi_log->buf)[pos]);\
- outlen += seq_printf(m, "CMD ID = %x\n", \
+ outlen += wmi_bp_seq_printf(m, "CMD ID = %x\n", \
(wmi_record->command)); \
- outlen += seq_printf(m, "CMD = "); \
+ outlen += wmi_bp_seq_printf(m, "CMD = "); \
for (i = 0; i < (wmi_record_max_length/ \
sizeof(uint32_t)); i++) \
- outlen += seq_printf(m, "%x ", \
+ outlen += wmi_bp_seq_printf(m, "%x ", \
wmi_record->data[i]); \
- outlen += seq_printf(m, "\n"); \
+ outlen += wmi_bp_seq_printf(m, "\n"); \
\
if (pos == 0) \
pos = wmi_ring_size - 1; \
else \
pos--; \
} \
- \
return outlen; \
} \
@@ -811,7 +810,7 @@
qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock); \
if (!wmi_log->length) { \
qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock);\
- return seq_printf(m, \
+ return wmi_bp_seq_printf(m, \
"no elements to read from ring buffer!\n"); \
} \
\
@@ -826,28 +825,27 @@
else \
pos = *(wmi_log->p_buf_tail_idx) - 1; \
\
- outlen = seq_printf(m, "Length = %d\n", wmi_log->length);\
+ outlen = wmi_bp_seq_printf(m, "Length = %d\n", wmi_log->length);\
qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock); \
while (nread--) { \
struct wmi_event_debug *wmi_record; \
\
wmi_record = (struct wmi_event_debug *) \
&(((struct wmi_event_debug *)wmi_log->buf)[pos]);\
- outlen += seq_printf(m, "Event ID = %x\n", \
+ outlen += wmi_bp_seq_printf(m, "Event ID = %x\n",\
(wmi_record->event)); \
- outlen += seq_printf(m, "CMD = "); \
+ outlen += wmi_bp_seq_printf(m, "CMD = "); \
for (i = 0; i < (wmi_record_max_length/ \
sizeof(uint32_t)); i++) \
- outlen += seq_printf(m, "%x ", \
+ outlen += wmi_bp_seq_printf(m, "%x ", \
wmi_record->data[i]); \
- outlen += seq_printf(m, "\n"); \
+ outlen += wmi_bp_seq_printf(m, "\n"); \
\
if (pos == 0) \
pos = wmi_ring_size - 1; \
else \
pos--; \
} \
- \
return outlen; \
}
@@ -873,8 +871,8 @@
{
wmi_unified_t wmi_handle = (wmi_unified_t) m->private;
- return seq_printf(m, "%d\n", wmi_handle->log_info.wmi_logging_enable);
-
+ return wmi_bp_seq_printf(m, "%d\n",
+ wmi_handle->log_info.wmi_logging_enable);
}
/**
@@ -889,9 +887,11 @@
static int debug_wmi_log_size_show(struct seq_file *m, void *v)
{
- seq_printf(m, "WMI command/event log max size:%d\n", wmi_log_max_entry);
- return seq_printf(m, "WMI management command/events log max size:%d\n",
- wmi_mgmt_log_max_entry);
+ wmi_bp_seq_printf(m, "WMI command/event log max size:%d\n",
+ wmi_log_max_entry);
+ return wmi_bp_seq_printf(m,
+ "WMI management command/events log max size:%d\n",
+ wmi_mgmt_log_max_entry);
}
/**
@@ -915,9 +915,16 @@
((struct seq_file *)file->private_data)->private;\
struct wmi_log_buf_t *wmi_log = &wmi_handle->log_info. \
wmi_##func_base##_buf_info; \
+ char locbuf[50]; \
\
- ret = sscanf(buf, "%d", &k); \
- if ((ret != 1) || (k != 0)) { \
+ if ((!buf) || (count > 50)) \
+ return -EFAULT; \
+ \
+ if (copy_from_user(locbuf, buf, count)) \
+ return -EFAULT; \
+ \
+ ret = sscanf(locbuf, "%d", &k); \
+ if ((ret != 1) || (k != 0)) { \
qdf_print("Wrong input, echo 0 to clear the wmi buffer\n");\
return -EINVAL; \
} \
@@ -964,8 +971,15 @@
wmi_unified_t wmi_handle =
((struct seq_file *)file->private_data)->private;
int k, ret;
+ char locbuf[50];
- ret = sscanf(buf, "%d", &k);
+ if ((!buf) || (count > 50))
+ return -EFAULT;
+
+ if (copy_from_user(locbuf, buf, count))
+ return -EFAULT;
+
+ ret = sscanf(locbuf, "%d", &k);
if ((ret != 1) || ((k != 0) && (k != 1)))
return -EINVAL;