diff options
author | Maya Erez <qca_merez@qca.qualcomm.com> | 2016-11-28 06:49:01 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@qca.qualcomm.com> | 2016-12-01 06:20:31 -0500 |
commit | 1db226ffe1c2ab900cffb1d71f042e565f77775d (patch) | |
tree | 6c8ff295e6baff3146b4d740ed8bab5b9603f864 /drivers/net/wireless/ath | |
parent | bb6743f7c2ffc467002dfe24bea5dedc96c7da04 (diff) |
wil6210: validate wil_pmc_alloc parameters
num_descriptors and descriptor_size needs to be
checked for:
1) not being negative values
2) no overflow occurs when these are multiplied
together as done in wil_pmc_read.
An overflow of two signed integers is undefined
behavior.
Signed-off-by: Maya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/wil6210/pmc.c | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index 5ca0307a3274..b9faae0278c9 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c | |||
@@ -54,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, | |||
54 | struct pmc_ctx *pmc = &wil->pmc; | 54 | struct pmc_ctx *pmc = &wil->pmc; |
55 | struct device *dev = wil_to_dev(wil); | 55 | struct device *dev = wil_to_dev(wil); |
56 | struct wmi_pmc_cmd pmc_cmd = {0}; | 56 | struct wmi_pmc_cmd pmc_cmd = {0}; |
57 | int last_cmd_err = -ENOMEM; | ||
57 | 58 | ||
58 | mutex_lock(&pmc->lock); | 59 | mutex_lock(&pmc->lock); |
59 | 60 | ||
@@ -62,6 +63,29 @@ void wil_pmc_alloc(struct wil6210_priv *wil, | |||
62 | wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__); | 63 | wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__); |
63 | goto no_release_err; | 64 | goto no_release_err; |
64 | } | 65 | } |
66 | if ((num_descriptors <= 0) || (descriptor_size <= 0)) { | ||
67 | wil_err(wil, | ||
68 | "Invalid params num_descriptors(%d), descriptor_size(%d)\n", | ||
69 | num_descriptors, descriptor_size); | ||
70 | last_cmd_err = -EINVAL; | ||
71 | goto no_release_err; | ||
72 | } | ||
73 | |||
74 | if (num_descriptors > (1 << WIL_RING_SIZE_ORDER_MAX)) { | ||
75 | wil_err(wil, | ||
76 | "num_descriptors(%d) exceeds max ring size %d\n", | ||
77 | num_descriptors, 1 << WIL_RING_SIZE_ORDER_MAX); | ||
78 | last_cmd_err = -EINVAL; | ||
79 | goto no_release_err; | ||
80 | } | ||
81 | |||
82 | if (num_descriptors > INT_MAX / descriptor_size) { | ||
83 | wil_err(wil, | ||
84 | "Overflow in num_descriptors(%d)*descriptor_size(%d)\n", | ||
85 | num_descriptors, descriptor_size); | ||
86 | last_cmd_err = -EINVAL; | ||
87 | goto no_release_err; | ||
88 | } | ||
65 | 89 | ||
66 | pmc->num_descriptors = num_descriptors; | 90 | pmc->num_descriptors = num_descriptors; |
67 | pmc->descriptor_size = descriptor_size; | 91 | pmc->descriptor_size = descriptor_size; |
@@ -189,7 +213,7 @@ release_pmc_skb_list: | |||
189 | pmc->descriptors = NULL; | 213 | pmc->descriptors = NULL; |
190 | 214 | ||
191 | no_release_err: | 215 | no_release_err: |
192 | pmc->last_cmd_status = -ENOMEM; | 216 | pmc->last_cmd_status = last_cmd_err; |
193 | mutex_unlock(&pmc->lock); | 217 | mutex_unlock(&pmc->lock); |
194 | } | 218 | } |
195 | 219 | ||
@@ -295,7 +319,7 @@ ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count, | |||
295 | size_t retval = 0; | 319 | size_t retval = 0; |
296 | unsigned long long idx; | 320 | unsigned long long idx; |
297 | loff_t offset; | 321 | loff_t offset; |
298 | size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors; | 322 | size_t pmc_size; |
299 | 323 | ||
300 | mutex_lock(&pmc->lock); | 324 | mutex_lock(&pmc->lock); |
301 | 325 | ||
@@ -306,6 +330,8 @@ ssize_t wil_pmc_read(struct file *filp, char __user *buf, size_t count, | |||
306 | return -EPERM; | 330 | return -EPERM; |
307 | } | 331 | } |
308 | 332 | ||
333 | pmc_size = pmc->descriptor_size * pmc->num_descriptors; | ||
334 | |||
309 | wil_dbg_misc(wil, | 335 | wil_dbg_misc(wil, |
310 | "%s: size %u, pos %lld\n", | 336 | "%s: size %u, pos %lld\n", |
311 | __func__, (unsigned)count, *f_pos); | 337 | __func__, (unsigned)count, *f_pos); |
@@ -345,7 +371,18 @@ loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence) | |||
345 | loff_t newpos; | 371 | loff_t newpos; |
346 | struct wil6210_priv *wil = filp->private_data; | 372 | struct wil6210_priv *wil = filp->private_data; |
347 | struct pmc_ctx *pmc = &wil->pmc; | 373 | struct pmc_ctx *pmc = &wil->pmc; |
348 | size_t pmc_size = pmc->descriptor_size * pmc->num_descriptors; | 374 | size_t pmc_size; |
375 | |||
376 | mutex_lock(&pmc->lock); | ||
377 | |||
378 | if (!wil_is_pmc_allocated(pmc)) { | ||
379 | wil_err(wil, "error, pmc is not allocated!\n"); | ||
380 | pmc->last_cmd_status = -EPERM; | ||
381 | mutex_unlock(&pmc->lock); | ||
382 | return -EPERM; | ||
383 | } | ||
384 | |||
385 | pmc_size = pmc->descriptor_size * pmc->num_descriptors; | ||
349 | 386 | ||
350 | switch (whence) { | 387 | switch (whence) { |
351 | case 0: /* SEEK_SET */ | 388 | case 0: /* SEEK_SET */ |
@@ -361,15 +398,21 @@ loff_t wil_pmc_llseek(struct file *filp, loff_t off, int whence) | |||
361 | break; | 398 | break; |
362 | 399 | ||
363 | default: /* can't happen */ | 400 | default: /* can't happen */ |
364 | return -EINVAL; | 401 | newpos = -EINVAL; |
402 | goto out; | ||
365 | } | 403 | } |
366 | 404 | ||
367 | if (newpos < 0) | 405 | if (newpos < 0) { |
368 | return -EINVAL; | 406 | newpos = -EINVAL; |
407 | goto out; | ||
408 | } | ||
369 | if (newpos > pmc_size) | 409 | if (newpos > pmc_size) |
370 | newpos = pmc_size; | 410 | newpos = pmc_size; |
371 | 411 | ||
372 | filp->f_pos = newpos; | 412 | filp->f_pos = newpos; |
373 | 413 | ||
414 | out: | ||
415 | mutex_unlock(&pmc->lock); | ||
416 | |||
374 | return newpos; | 417 | return newpos; |
375 | } | 418 | } |