aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRygebin <kaankulahli@gmail.com>2017-06-20 14:29:27 +0000
committerRygebin <kaankulahli@gmail.com>2017-06-20 14:29:27 +0000
commitafa9ad70f02491fbe10df2203f8f2fa42f956228 (patch)
treeb6dce4ed04f62fd443721a94ac3e7f81427e0ad1 /drivers
parent582eb92a1e8bf6c0e743774c1fb550e630715433 (diff)
parent08d1ec9238c605a9a5cf1229fd60961efcd21ff1 (diff)
Merge https://github.com/OneDeveloperOrganization/android_kernel_google_shamrock into n7.1HEADn7.1
Diffstat (limited to 'drivers')
-rw-r--r--drivers/char/adsprpc.c20
-rw-r--r--drivers/crypto/msm/ota_crypto.c4
-rw-r--r--drivers/crypto/msm/qce50.c49
-rw-r--r--drivers/crypto/msm/qcedev.c15
-rw-r--r--drivers/crypto/msm/qcrypto.c4
-rw-r--r--drivers/input/touchscreen/gt9xx/goodix_tool.c8
-rw-r--r--drivers/leds/leds-qpnp-flash.c147
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c7
-rwxr-xr-xdrivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c10
-rw-r--r--drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c11
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c3
-rw-r--r--drivers/mfd/wcd9xxx-slimslave.c10
-rw-r--r--drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c81
-rw-r--r--drivers/misc/qseecom.c666
-rw-r--r--drivers/net/ethernet/msm/rndis_ipa.c432
-rw-r--r--drivers/platform/msm/ipa/ipa_flt.c36
-rw-r--r--drivers/platform/msm/ipa/ipa_nat.c77
-rw-r--r--drivers/platform/msm/ipa/ipa_rt.c26
-rwxr-xr-xdrivers/power/qpnp-fg.c34
-rw-r--r--drivers/slimbus/slim-msm-ngd.c5
-rw-r--r--drivers/slimbus/slim-msm.h3
-rw-r--r--drivers/soc/qcom/qdsp6v2/voice_svc.c26
-rw-r--r--drivers/soc/qcom/scm.c27
-rw-r--r--drivers/spmi/spmi-dbgfs.c37
-rwxr-xr-xdrivers/staging/android/ion/ion.c84
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c11
-rw-r--r--drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c7
-rw-r--r--drivers/uio/msm_sharedmem/sharedmem_qmi.c17
-rw-r--r--drivers/video/msm/mdss/mdss_debug.c10
-rw-r--r--drivers/video/msm/mdss/mdss_dsi.c21
-rw-r--r--drivers/video/msm/mdss/mdss_fb.c18
-rw-r--r--drivers/video/msm/mdss/mdss_mdp.c2
-rw-r--r--drivers/video/msm/mdss/mdss_mdp_overlay.c5
33 files changed, 1146 insertions, 767 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c
index 97c02d299a3..797a42d86b4 100644
--- a/drivers/char/adsprpc.c
+++ b/drivers/char/adsprpc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2015,2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -457,9 +457,9 @@ static int overlap_ptr_cmp(const void *a, const void *b)
return st == 0 ? ed : st;
}
-static void context_build_overlap(struct smq_invoke_ctx *ctx)
+static int context_build_overlap(struct smq_invoke_ctx *ctx)
{
- int i;
+ int err = 0, i;
remote_arg_t *lpra = ctx->lpra;
int inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
int outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc);
@@ -468,6 +468,11 @@ static void context_build_overlap(struct smq_invoke_ctx *ctx)
for (i = 0; i < nbufs; ++i) {
ctx->overs[i].start = (uintptr_t)lpra[i].buf.pv;
ctx->overs[i].end = ctx->overs[i].start + lpra[i].buf.len;
+ if (lpra[i].buf.len) {
+ VERIFY(err, ctx->overs[i].end > ctx->overs[i].start);
+ if (err)
+ goto bail;
+ }
ctx->overs[i].raix = i;
ctx->overps[i] = &ctx->overs[i];
}
@@ -493,6 +498,8 @@ static void context_build_overlap(struct smq_invoke_ctx *ctx)
max = *ctx->overps[i];
}
}
+bail:
+ return err;
}
#define K_COPY_FROM_USER(err, kernel, dst, src, size) \
@@ -557,8 +564,11 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel,
goto bail;
}
ctx->sc = invoke->sc;
- if (bufs)
- context_build_overlap(ctx);
+ if (bufs) {
+ VERIFY(err, 0 == context_build_overlap(ctx));
+ if (err)
+ goto bail;
+ }
ctx->retval = -1;
ctx->pid = current->pid;
ctx->tgid = current->tgid;
diff --git a/drivers/crypto/msm/ota_crypto.c b/drivers/crypto/msm/ota_crypto.c
index 9fc548d73e6..d9e3395fec5 100644
--- a/drivers/crypto/msm/ota_crypto.c
+++ b/drivers/crypto/msm/ota_crypto.c
@@ -880,8 +880,8 @@ static ssize_t _debug_stats_read(struct file *file, char __user *buf,
int len;
len = _disp_stats();
-
- rc = simple_read_from_buffer((void __user *) buf, len,
+ if (len <= count)
+ rc = simple_read_from_buffer((void __user *) buf, len,
ppos, (void *) _debug_read_buf, len);
return rc;
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index c4334c9d05d..bbdde2206c7 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1279,7 +1279,8 @@ go_proc:
CRYPTO_CONFIG_REG));
/* issue go to crypto */
if (use_hw_key == false) {
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
} else {
QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1461,7 +1462,8 @@ static int _ce_setup_aead_direct(struct qce_device *pce_dev,
CRYPTO_CONFIG_REG));
/* issue go to crypto */
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
/*
* Ensure previous instructions (setting the GO register)
@@ -1781,7 +1783,8 @@ static int _ce_setup_cipher_direct(struct qce_device *pce_dev,
CRYPTO_CONFIG_REG));
/* issue go to crypto */
if (use_hw_key == false) {
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
} else {
QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
@@ -1869,7 +1872,8 @@ static int _ce_f9_setup_direct(struct qce_device *pce_dev,
QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/* write go */
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
/*
* Ensure previous instructions (setting the GO register)
@@ -1946,7 +1950,8 @@ static int _ce_f8_setup_direct(struct qce_device *pce_dev,
QCE_WRITE_REG(pce_dev->reg.crypto_cfg_le, (pce_dev->iobase +
CRYPTO_CONFIG_REG));
/* write go */
- QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
+ QCE_WRITE_REG(((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)),
pce_dev->iobase + CRYPTO_GOPROC_REG);
/*
* Ensure previous instructions (setting the GO register)
@@ -3024,8 +3029,8 @@ static int _setup_cipher_aes_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3137,8 +3142,8 @@ static int _setup_cipher_des_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3315,8 +3320,8 @@ static int _setup_auth_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3530,8 +3535,8 @@ static int _setup_aead_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3662,8 +3667,8 @@ static int _setup_aead_ccm_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3747,8 +3752,8 @@ static int _setup_f8_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -3828,8 +3833,8 @@ static int _setup_f9_cmdlistptrs(struct qce_device *pdev,
pdev->reg.crypto_cfg_le, NULL);
qce_add_cmd_element(pdev, &ce_vaddr, CRYPTO_GOPROC_REG,
- ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP)),
- &pcl_info->go_proc);
+ ((1 << CRYPTO_GO) | (1 << CRYPTO_RESULTS_DUMP) |
+ (1 << CRYPTO_CLR_CNTXT)), &pcl_info->go_proc);
pcl_info->size = (uintptr_t)ce_vaddr - (uintptr_t)ce_vaddr_start;
*pvaddr = (unsigned char *) ce_vaddr;
@@ -4425,6 +4430,12 @@ int qce_aead_req(void *handle, struct qce_req *q_req)
else
q_req->cryptlen = areq->cryptlen - authsize;
+ if ((q_req->cryptlen > UINT_MAX - areq->assoclen) ||
+ (q_req->cryptlen + areq->assoclen > UINT_MAX - ivsize)) {
+ pr_err("Integer overflow on total aead req length.\n");
+ return -EINVAL;
+ }
+
totallen = q_req->cryptlen + areq->assoclen + ivsize;
if (pce_dev->support_cmd_dscr) {
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 0bc47fbf1a9..1bfbe7c1fa3 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1472,6 +1472,15 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
pr_err("%s: Invalid byte offset\n", __func__);
goto error;
}
+ total = req->byteoffset;
+ for (i = 0; i < req->entries; i++) {
+ if (total > U32_MAX - req->vbuf.src[i].len) {
+ pr_err("%s:Integer overflow on total src len\n",
+ __func__);
+ goto error;
+ }
+ total += req->vbuf.src[i].len;
+ }
}
if (req->data_len < req->byteoffset) {
@@ -1507,7 +1516,7 @@ static int qcedev_check_cipher_params(struct qcedev_cipher_op_req *req,
}
}
/* Check for sum of all dst length is equal to data_len */
- for (i = 0; i < req->entries; i++) {
+ for (i = 0, total = 0; i < req->entries; i++) {
if (req->vbuf.dst[i].len >= U32_MAX - total) {
pr_err("%s: Integer overflow on total req dst vbuf length\n",
__func__);
@@ -2075,9 +2084,9 @@ static ssize_t _debug_stats_read(struct file *file, char __user *buf,
len = _disp_stats(qcedev);
- rc = simple_read_from_buffer((void __user *) buf, len,
+ if (len <= count)
+ rc = simple_read_from_buffer((void __user *) buf, len,
ppos, (void *) _debug_read_buf, len);
-
return rc;
}
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 1c5a18fa4c3..64e8f466a68 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -5147,9 +5147,9 @@ static ssize_t _debug_stats_read(struct file *file, char __user *buf,
len = _disp_stats(qcrypto);
- rc = simple_read_from_buffer((void __user *) buf, len,
+ if (len <= count)
+ rc = simple_read_from_buffer((void __user *) buf, len,
ppos, (void *) _debug_read_buf, len);
-
return rc;
}
diff --git a/drivers/input/touchscreen/gt9xx/goodix_tool.c b/drivers/input/touchscreen/gt9xx/goodix_tool.c
index ada68b69b9e..430292d3e24 100644
--- a/drivers/input/touchscreen/gt9xx/goodix_tool.c
+++ b/drivers/input/touchscreen/gt9xx/goodix_tool.c
@@ -1,7 +1,7 @@
/* drivers/input/touchscreen/goodix_tool.c
*
* 2010 - 2012 Goodix Technology.
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -311,6 +311,7 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
size_t count, loff_t *ppos)
{
s32 ret = 0;
+ u8 *dataptr = NULL;
mutex_lock(&lock);
ret = copy_from_user(&cmd_head, userbuf, CMD_HEAD_LENGTH);
@@ -469,6 +470,11 @@ static s32 goodix_tool_write(struct file *filp, const char __user *userbuf,
ret = CMD_HEAD_LENGTH;
exit:
+ dataptr = cmd_head.data;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.wr = 0xFF;
+ cmd_head.data = dataptr;
+
mutex_unlock(&lock);
return ret;
}
diff --git a/drivers/leds/leds-qpnp-flash.c b/drivers/leds/leds-qpnp-flash.c
index 392238f20be..bda73cb85d6 100644
--- a/drivers/leds/leds-qpnp-flash.c
+++ b/drivers/leds/leds-qpnp-flash.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -213,10 +213,13 @@ struct flash_led_platform_data {
};
struct qpnp_flash_led_buffer {
- size_t rpos;
- size_t wpos;
- size_t len;
- char data[0];
+ struct mutex debugfs_lock; /* Prevent thread concurrency */
+ size_t rpos;
+ size_t wpos;
+ size_t len;
+ struct qpnp_flash_led *led;
+ u32 buffer_cnt;
+ char data[0];
};
/*
@@ -233,10 +236,8 @@ struct qpnp_flash_led {
struct workqueue_struct *ordered_workq;
struct qpnp_vadc_chip *vadc_dev;
struct mutex flash_led_lock;
- struct qpnp_flash_led_buffer *log;
struct dentry *dbgfs_root;
int num_leds;
- u32 buffer_cnt;
u16 base;
u16 current_addr;
u16 current2_addr;
@@ -266,10 +267,11 @@ static int flash_led_dbgfs_file_open(struct qpnp_flash_led *led,
log->rpos = 0;
log->wpos = 0;
log->len = logbufsize - sizeof(*log);
- led->log = log;
+ mutex_init(&log->debugfs_lock);
+ log->led = led;
- led->buffer_cnt = 1;
- file->private_data = led;
+ log->buffer_cnt = 1;
+ file->private_data = log;
return 0;
}
@@ -282,24 +284,30 @@ static int flash_led_dfs_open(struct inode *inode, struct file *file)
static int flash_led_dfs_close(struct inode *inode, struct file *file)
{
- struct qpnp_flash_led *led = file->private_data;
+ struct qpnp_flash_led_buffer *log = file->private_data;
- if (led && led->log) {
+ if (log) {
file->private_data = NULL;
- kfree(led->log);
+ mutex_destroy(&log->debugfs_lock);
+ kfree(log);
}
return 0;
}
+#define MIN_BUFFER_WRITE_LEN 20
static int print_to_log(struct qpnp_flash_led_buffer *log,
const char *fmt, ...)
{
va_list args;
int cnt;
- char *log_buf = &log->data[log->wpos];
+ char *log_buf;
size_t size = log->len - log->wpos;
+ if (size < MIN_BUFFER_WRITE_LEN)
+ return 0; /* not enough buffer left */
+
+ log_buf = &log->data[log->wpos];
va_start(args, fmt);
cnt = vscnprintf(log_buf, size, fmt, args);
va_end(args);
@@ -310,15 +318,23 @@ static int print_to_log(struct qpnp_flash_led_buffer *log,
static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
+ struct qpnp_flash_led_buffer *log = fp->private_data;
+ struct qpnp_flash_led *led;
u8 val;
- int rc;
+ int rc = 0;
size_t len;
size_t ret;
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
+ mutex_lock(&log->debugfs_lock);
+ if ((log->rpos >= log->wpos && log->buffer_cnt == 0) ||
+ ((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
+ goto unlock_mutex;
rc = spmi_ext_register_readl(led->spmi_dev->ctrl,
led->spmi_dev->sid, INT_LATCHED_STS(led->base), &val, 1);
@@ -326,17 +342,17 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
dev_err(&led->spmi_dev->dev,
"Unable to read from address %x, rc(%d)\n",
INT_LATCHED_STS(led->base), rc);
- return -EINVAL;
+ goto unlock_mutex;
}
- led->buffer_cnt--;
+ log->buffer_cnt--;
rc = print_to_log(log, "0x%05X ", INT_LATCHED_STS(led->base));
if (rc == 0)
- return rc;
+ goto unlock_mutex;
rc = print_to_log(log, "0x%02X ", val);
if (rc == 0)
- return rc;
+ goto unlock_mutex;
if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
log->data[log->wpos - 1] = '\n';
@@ -346,36 +362,49 @@ static ssize_t flash_led_dfs_latched_reg_read(struct file *fp, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret) {
pr_err("error copy register value to user\n");
- return -EFAULT;
+ rc = -EFAULT;
+ goto unlock_mutex;
}
len -= ret;
*ppos += len;
log->rpos += len;
- return len;
+ rc = len;
+
+unlock_mutex:
+ mutex_unlock(&log->debugfs_lock);
+ return rc;
}
static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
size_t count, loff_t *ppos) {
- struct qpnp_flash_led *led = fp->private_data;
- struct qpnp_flash_led_buffer *log = led->log;
- int rc;
+ struct qpnp_flash_led_buffer *log = fp->private_data;
+ struct qpnp_flash_led *led;
+ int rc = 0;
size_t len;
size_t ret;
- if (log->rpos >= log->wpos && led->buffer_cnt == 0)
- return 0;
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
+ mutex_lock(&log->debugfs_lock);
+ if ((log->rpos >= log->wpos && log->buffer_cnt == 0) ||
+ ((log->len - log->wpos) < MIN_BUFFER_WRITE_LEN))
+ goto unlock_mutex;
- led->buffer_cnt--;
+ log->buffer_cnt--;
rc = print_to_log(log, "0x%05X ", FLASH_LED_FAULT_STATUS(led->base));
if (rc == 0)
- return rc;
+ goto unlock_mutex;
rc = print_to_log(log, "0x%02X ", led->fault_reg);
if (rc == 0)
- return rc;
+ goto unlock_mutex;
if (log->wpos > 0 && log->data[log->wpos - 1] == ' ')
log->data[log->wpos - 1] = '\n';
@@ -385,14 +414,19 @@ static ssize_t flash_led_dfs_fault_reg_read(struct file *fp, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret) {
pr_err("error copy register value to user\n");
- return -EFAULT;
+ rc = -EFAULT;
+ goto unlock_mutex;
}
len -= ret;
*ppos += len;
log->rpos += len;
- return len;
+ rc = len;
+
+unlock_mutex:
+ mutex_unlock(&log->debugfs_lock);
+ return rc;
}
static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
@@ -404,10 +438,22 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
int data;
size_t ret = 0;
- struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
+ struct qpnp_flash_led_buffer *log = file->private_data;
+ struct qpnp_flash_led *led;
+ char *kbuf;
+
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
+ mutex_lock(&log->debugfs_lock);
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (!ret) {
@@ -436,6 +482,8 @@ static ssize_t flash_led_dfs_fault_reg_enable(struct file *file,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&log->debugfs_lock);
return ret;
}
@@ -447,11 +495,22 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
int cnt = 0;
int data;
size_t ret = 0;
+ struct qpnp_flash_led_buffer *log = file->private_data;
+ struct qpnp_flash_led *led;
+ char *kbuf;
- struct qpnp_flash_led *led = file->private_data;
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
+ if (!log) {
+ pr_err("error: file private data is NULL\n");
+ return -EFAULT;
+ }
+ led = log->led;
+
+ mutex_lock(&log->debugfs_lock);
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (ret == count) {
@@ -479,6 +538,8 @@ static ssize_t flash_led_dfs_dbg_enable(struct file *file,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&log->debugfs_lock);
return ret;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
index eee402593eb..94bc01712ac 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/cci/msm_cci.c
@@ -1151,6 +1151,13 @@ static struct msm_cam_clk_info *msm_cci_get_clk(struct cci_device *cci_dev,
struct msm_cci_clk_params_t *clk_params = NULL;
enum i2c_freq_mode_t i2c_freq_mode = c_ctrl->cci_info->i2c_freq_mode;
struct device_node *of_node = cci_dev->pdev->dev.of_node;
+
+ if ((i2c_freq_mode >= I2C_MAX_MODES) || (i2c_freq_mode < 0)) {
+ pr_err("%s:%d invalid i2c_freq_mode %d\n",
+ __func__, __LINE__, i2c_freq_mode);
+ return NULL;
+ }
+
clk_params = &cci_dev->cci_clk_params[i2c_freq_mode];
cci_clk_src = clk_params->cci_clk_src;
diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
index 0022fc5275c..f70cd662fb6 100755
--- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c
@@ -293,6 +293,16 @@ static int32_t msm_flash_i2c_init(
flash_ctrl->power_info.power_down_setting_size =
flash_ctrl->power_setting_array.size_down;
+ if ((flash_ctrl->power_info.power_setting_size > MAX_POWER_CONFIG) ||
+ (flash_ctrl->power_info.power_down_setting_size > MAX_POWER_CONFIG)) {
+ pr_err("%s:%d invalid power setting size=%d size_down=%d\n",
+ __func__, __LINE__,
+ flash_ctrl->power_info.power_setting_size,
+ flash_ctrl->power_info.power_down_setting_size);
+ rc = -EINVAL;
+ goto msm_flash_i2c_init_fail;
+ }
+
rc = msm_camera_power_up(&flash_ctrl->power_info,
flash_ctrl->flash_device_type,
&flash_ctrl->flash_i2c_client);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
index 29ed44ab3db..b6130709957 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_io_util.c
@@ -42,6 +42,7 @@ void msm_camera_io_w_mb(u32 data, void __iomem *addr)
u32 msm_camera_io_r(void __iomem *addr)
{
uint32_t data = readl_relaxed(addr);
+
CDBG("%s: 0x%pK %08x\n", __func__, (addr), (data));
return data;
}
@@ -49,6 +50,7 @@ u32 msm_camera_io_r(void __iomem *addr)
u32 msm_camera_io_r_mb(void __iomem *addr)
{
uint32_t data;
+
rmb();
data = readl_relaxed(addr);
rmb();
@@ -73,6 +75,7 @@ void msm_camera_io_dump(void __iomem *addr, int size)
int i;
u32 *p = (u32 *) addr;
u32 data;
+
CDBG("%s: %pK %d\n", __func__, addr, size);
line_str[0] = '\0';
p_str = line_str;
@@ -152,6 +155,7 @@ int msm_cam_clk_enable(struct device *dev, struct msm_cam_clk_info *clk_info,
int i;
int rc = 0;
long clk_rate;
+
if (enable) {
for (i = 0; i < num_clk; i++) {
CDBG("%s enable %s\n", __func__, clk_info[i].clk_name);
@@ -258,6 +262,12 @@ int msm_camera_config_vreg(struct device *dev, struct camera_vreg_t *cam_vreg,
pr_err("%s:%d vreg sequence invalid\n", __func__, __LINE__);
return -EINVAL;
}
+
+ if (cam_vreg == NULL) {
+ pr_err("%s:%d cam_vreg sequence invalid\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
if (!num_vreg_seq)
num_vreg_seq = num_vreg;
@@ -434,6 +444,7 @@ void msm_camera_bus_scale_cfg(uint32_t bus_perf_client,
enum msm_bus_perf_setting perf_setting)
{
int rc = 0;
+
if (!bus_perf_client) {
pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
return;
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index a2f4501c23c..f61d1d7ba76 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1939,6 +1939,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
if (!found)
return -ENOENT;
+ if (ctrl->info.size < mapping->size)
+ return -EINVAL;
+
if (mutex_lock_interruptible(&chain->ctrl_mutex))
return -ERESTARTSYS;
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 3ad63abf5b2..fd35c264238 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -62,6 +62,10 @@ int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
goto err;
}
+ if (!rx_num || rx_num > wcd9xxx->num_rx_port) {
+ pr_err("%s: invalid rx num %d\n", __func__, rx_num);
+ return -EINVAL;
+ }
if (wcd9xxx->rx_chs) {
wcd9xxx->num_rx_port = rx_num;
for (i = 0; i < rx_num; i++) {
@@ -84,6 +88,10 @@ int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
wcd9xxx->num_rx_port);
}
+ if (!tx_num || tx_num > wcd9xxx->num_tx_port) {
+ pr_err("%s: invalid tx num %d\n", __func__, tx_num);
+ return -EINVAL;
+ }
if (wcd9xxx->tx_chs) {
wcd9xxx->num_tx_port = tx_num;
for (i = 0; i < tx_num; i++) {
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
index ec3b5c2d8d2..166601e22db 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -17,7 +17,6 @@
#include "q6audio_common.h"
#include "audio_utils_aio.h"
#include <sound/msm-audio-effects-q6-v2.h>
-#include <sound/msm-dts-eagle.h>
#define MAX_CHANNELS_SUPPORTED 8
#define WAIT_TIMEDOUT_DURATION_SECS 1
@@ -29,6 +28,8 @@ struct q6audio_effects {
struct audio_client *ac;
struct msm_hwacc_effects_config config;
+ struct mutex lock;
+
atomic_t in_count;
atomic_t out_count;
@@ -51,31 +52,11 @@ static void audio_effects_init_pp(struct audio_client *ac)
pr_err("%s: audio client null to init pp\n", __func__);
return;
}
- switch (ac->topology) {
- case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
-
- ret = q6asm_set_softvolume_v2(ac, &softvol,
- SOFT_VOLUME_INSTANCE_1);
- if (ret < 0)
- pr_err("%s: Send SoftVolume1 Param failed ret=%d\n",
- __func__, ret);
- ret = q6asm_set_softvolume_v2(ac, &softvol,
- SOFT_VOLUME_INSTANCE_2);
- if (ret < 0)
- pr_err("%s: Send SoftVolume2 Param failed ret=%d\n",
- __func__, ret);
-
- msm_dts_eagle_init_master_module(ac);
-
- break;
- default:
- ret = q6asm_set_softvolume_v2(ac, &softvol,
- SOFT_VOLUME_INSTANCE_1);
- if (ret < 0)
- pr_err("%s: Send SoftVolume Param failed ret=%d\n",
- __func__, ret);
- break;
- }
+ ret = q6asm_set_softvolume_v2(ac, &softvol,
+ SOFT_VOLUME_INSTANCE_1);
+ if (ret < 0)
+ pr_err("%s: Send SoftVolume Param failed ret=%d\n",
+ __func__, ret);
}
static void audio_effects_deinit_pp(struct audio_client *ac)
@@ -84,13 +65,6 @@ static void audio_effects_deinit_pp(struct audio_client *ac)
pr_err("%s: audio client null to deinit pp\n", __func__);
return;
}
- switch (ac->topology) {
- case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER:
- msm_dts_eagle_deinit_master_module(ac);
- break;
- default:
- break;
- }
}
static void audio_effects_event_handler(uint32_t opcode, uint32_t token,
@@ -230,8 +204,11 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
uint32_t idx = 0;
uint32_t size = 0;
+ mutex_lock(&effects->lock);
+
if (!effects->started) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -241,11 +218,13 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
if (!rc) {
pr_err("%s: write wait_event_timeout\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
if (!atomic_read(&effects->out_count)) {
pr_err("%s: pcm stopped out_count 0\n", __func__);
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
@@ -254,6 +233,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
if (copy_from_user(bufptr, (void *)arg,
effects->config.buf_cfg.output_len)) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
rc = q6asm_write(effects->ac,
@@ -261,6 +241,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
0, 0, NO_TIMESTAMP);
if (rc < 0) {
rc = -EFAULT;
+ mutex_unlock(&effects->lock);
goto ioctl_fail;
}
atomic_dec(&effects->out_count);
@@ -268,6 +249,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd,
pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n",
__func__);
}
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_READ: {
@@ -400,33 +382,6 @@ static long audio_effects_set_pp_param(struct q6audio_effects *effects,
&(effects->audio_effects.topo_switch_vol),
(long *)&values[1], SOFT_VOLUME_INSTANCE_2);
break;
- case DTS_EAGLE_MODULE_ENABLE:
- pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__);
- if (msm_audio_effects_is_effmodule_supp_in_top(
- effects_module, effects->ac->topology)) {
- /*
- * HPX->OFF: first disable HPX and then
- * enable SA+
- * HPX->ON: first disable SA+ and then
- * enable HPX
- */
- bool hpx_state = (bool)values[1];
- if (hpx_state)
- msm_audio_effects_enable_extn(effects->ac,
- &(effects->audio_effects),
- false);
- msm_dts_eagle_enable_asm(effects->ac,
- hpx_state,
- AUDPROC_MODULE_ID_DTS_HPX_PREMIX);
- msm_dts_eagle_enable_asm(effects->ac,
- hpx_state,
- AUDPROC_MODULE_ID_DTS_HPX_POSTMIX);
- if (!hpx_state)
- msm_audio_effects_enable_extn(effects->ac,
- &(effects->audio_effects),
- true);
- }
- break;
default:
pr_err("%s: Invalid effects config module\n", __func__);
rc = -EINVAL;
@@ -464,6 +419,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd,
break;
}
case AUDIO_EFFECTS_SET_BUF_LEN: {
+ mutex_lock(&effects->lock);
if (copy_from_user(&effects->config.buf_cfg, (void *)arg,
sizeof(effects->config.buf_cfg))) {
pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n",
@@ -473,6 +429,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd,
pr_debug("%s: write buf len: %d, read buf len: %d\n",
__func__, effects->config.buf_cfg.output_len,
effects->config.buf_cfg.input_len);
+ mutex_unlock(&effects->lock);
break;
}
case AUDIO_EFFECTS_GET_BUF_AVAIL: {
@@ -717,6 +674,7 @@ static int audio_effects_release(struct inode *inode, struct file *file)
}
q6asm_audio_client_free(effects->ac);
+ mutex_destroy(&effects->lock);
kfree(effects);
pr_debug("%s: close session success\n", __func__);
@@ -747,6 +705,7 @@ static int audio_effects_open(struct inode *inode, struct file *file)
init_waitqueue_head(&effects->read_wait);
init_waitqueue_head(&effects->write_wait);
+ mutex_init(&effects->lock);
effects->opened = 0;
effects->started = 0;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b228952f554..79f5c7843fd 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,6 +1,6 @@
/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,9 @@
/* Encrypt/Decrypt Data Integrity Partition (DIP) for MDTP */
#define SCM_MDTP_CIPHER_DIP 0x01
+/* Maximum Allowed Size (128K) of Data Integrity Partition (DIP) for MDTP */
+#define MAX_DIP 0x20000
+
#define RPMB_SERVICE 0x2000
#define SSD_SERVICE 0x3000
@@ -116,6 +119,35 @@ static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
+struct sglist_info {
+ uint32_t indexAndFlags;
+ uint32_t sizeOrCount;
+};
+
+/*
+ * The 31th bit indicates only one or multiple physical address inside
+ * the request buffer. If it is set, the index locates a single physical addr
+ * inside the request buffer, and `sizeOrCount` is the size of the memory being
+ * shared at that physical address.
+ * Otherwise, the index locates an array of {start, len} pairs (a
+ * "scatter/gather list"), and `sizeOrCount` gives the number of entries in
+ * that array.
+ *
+ * The 30th bit indicates 64 or 32bit address; when it is set, physical addr
+ * and scatter gather entry sizes are 64-bit values. Otherwise, 32-bit values.
+ *
+ * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer.
+ */
+#define SGLISTINFO_SET_INDEX_FLAG(c, s, i) \
+ ((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff)))
+
+#define SGLISTINFO_TABLE_SIZE (sizeof(struct sglist_info) * MAX_ION_FD)
+
+#define FEATURE_ID_WHITELIST 15 /*whitelist feature id*/
+
+#define MAKE_WHITELIST_VERSION(major, minor, patch) \
+ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+
struct qseecom_registered_listener_list {
struct list_head list;
struct qseecom_register_listener_req svc;
@@ -130,6 +162,8 @@ struct qseecom_registered_listener_list {
bool listener_in_use;
/* wq for thread blocked on this listener*/
wait_queue_head_t listener_block_app_wq;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
};
struct qseecom_registered_app_list {
@@ -181,6 +215,7 @@ struct qseecom_control {
uint32_t qseos_version;
uint32_t qsee_version;
struct device *pdev;
+ bool whitelist_support;
bool commonlib_loaded;
bool commonlib64_loaded;
struct ion_handle *cmnlib_ion_handle;
@@ -254,6 +289,9 @@ struct qseecom_dev_handle {
bool perf_enabled;
bool fast_load_enabled;
enum qseecom_bandwidth_request_mode mode;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
+ bool use_legacy_cmd;
};
struct qseecom_key_id_usage_desc {
@@ -513,6 +551,34 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
+ struct qseecom_client_listener_data_irsp *req;
+ struct qseecom_client_listener_data_64bit_irsp *req_64;
+
+ smc_id =
+ TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req =
+ (struct qseecom_client_listener_data_irsp *)
+ req_buf;
+ desc.args[0] = req->listener_id;
+ desc.args[1] = req->status;
+ desc.args[2] = req->sglistinfo_ptr;
+ desc.args[3] = req->sglistinfo_len;
+ } else {
+ req_64 =
+ (struct qseecom_client_listener_data_64bit_irsp *)
+ req_buf;
+ desc.args[0] = req_64->listener_id;
+ desc.args[1] = req_64->status;
+ desc.args[2] = req_64->sglistinfo_ptr;
+ desc.args[3] = req_64->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
struct qseecom_load_app_ireq *req;
struct qseecom_load_app_64bit_ireq *req_64bit;
@@ -568,6 +634,38 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
+ struct qseecom_client_send_data_ireq *req;
+ struct qseecom_client_send_data_64bit_ireq *req_64bit;
+
+ smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req = (struct qseecom_client_send_data_ireq *)
+ req_buf;
+ desc.args[0] = req->app_id;
+ desc.args[1] = req->req_ptr;
+ desc.args[2] = req->req_len;
+ desc.args[3] = req->rsp_ptr;
+ desc.args[4] = req->rsp_len;
+ desc.args[5] = req->sglistinfo_ptr;
+ desc.args[6] = req->sglistinfo_len;
+ } else {
+ req_64bit =
+ (struct qseecom_client_send_data_64bit_ireq *)
+ req_buf;
+ desc.args[0] = req_64bit->app_id;
+ desc.args[1] = req_64bit->req_ptr;
+ desc.args[2] = req_64bit->req_len;
+ desc.args[3] = req_64bit->rsp_ptr;
+ desc.args[4] = req_64bit->rsp_len;
+ desc.args[5] = req_64bit->sglistinfo_ptr;
+ desc.args[6] = req_64bit->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
struct qseecom_client_send_service_ireq *req;
req = (struct qseecom_client_send_service_ireq *)
@@ -695,6 +793,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
+ struct qseecom_qteec_ireq *req;
+ struct qseecom_qteec_64bit_ireq *req_64bit;
+
+ smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req = (struct qseecom_qteec_ireq *)req_buf;
+ desc.args[0] = req->app_id;
+ desc.args[1] = req->req_ptr;
+ desc.args[2] = req->req_len;
+ desc.args[3] = req->resp_ptr;
+ desc.args[4] = req->resp_len;
+ desc.args[5] = req->sglistinfo_ptr;
+ desc.args[6] = req->sglistinfo_len;
+ } else {
+ req_64bit = (struct qseecom_qteec_64bit_ireq *)
+ req_buf;
+ desc.args[0] = req_64bit->app_id;
+ desc.args[1] = req_64bit->req_ptr;
+ desc.args[2] = req_64bit->req_len;
+ desc.args[3] = req_64bit->resp_ptr;
+ desc.args[4] = req_64bit->resp_len;
+ desc.args[5] = req_64bit->sglistinfo_ptr;
+ desc.args[6] = req_64bit->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_TEE_INVOKE_COMMAND: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
@@ -719,6 +847,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
+ struct qseecom_qteec_ireq *req;
+ struct qseecom_qteec_64bit_ireq *req_64bit;
+
+ smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req = (struct qseecom_qteec_ireq *)req_buf;
+ desc.args[0] = req->app_id;
+ desc.args[1] = req->req_ptr;
+ desc.args[2] = req->req_len;
+ desc.args[3] = req->resp_ptr;
+ desc.args[4] = req->resp_len;
+ desc.args[5] = req->sglistinfo_ptr;
+ desc.args[6] = req->sglistinfo_len;
+ } else {
+ req_64bit = (struct qseecom_qteec_64bit_ireq *)
+ req_buf;
+ desc.args[0] = req_64bit->app_id;
+ desc.args[1] = req_64bit->req_ptr;
+ desc.args[2] = req_64bit->req_len;
+ desc.args[3] = req_64bit->resp_ptr;
+ desc.args[4] = req_64bit->resp_len;
+ desc.args[5] = req_64bit->sglistinfo_ptr;
+ desc.args[6] = req_64bit->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_TEE_CLOSE_SESSION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
@@ -946,7 +1104,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
return -EBUSY;
}
- new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
+ new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry) {
pr_err("kmalloc failed\n");
return -ENOMEM;
@@ -1398,6 +1556,16 @@ static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data,
return ret;
}
+static void __qseecom_clean_listener_sglistinfo(
+ struct qseecom_registered_listener_list *ptr_svc)
+{
+ if (ptr_svc->sglist_cnt) {
+ memset(ptr_svc->sglistinfo_ptr, 0,
+ SGLISTINFO_TABLE_SIZE);
+ ptr_svc->sglist_cnt = 0;
+ }
+}
+
static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp)
{
@@ -1406,9 +1574,14 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
uint32_t lstnr;
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
+ uint32_t status;
+ void *cmd_buf = NULL;
+ size_t cmd_len;
+ struct sglist_info *table = NULL;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -1420,6 +1593,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
+ ptr_svc->listener_in_use = true;
ptr_svc->rcv_req_flag = 1;
wake_up_interruptible(&ptr_svc->rcv_req_wq);
break;
@@ -1467,14 +1641,42 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
- send_data_rsp.status = QSEOS_RESULT_FAILURE;
+ status = QSEOS_RESULT_FAILURE;
} else {
- send_data_rsp.status = QSEOS_RESULT_SUCCESS;
+ status = QSEOS_RESULT_SUCCESS;
}
qseecom.send_resp_flag = 0;
- send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
- send_data_rsp.listener_id = lstnr;
+ ptr_svc->send_resp_flag = 0;
+ table = ptr_svc->sglistinfo_ptr;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ send_data_rsp.listener_id = lstnr;
+ send_data_rsp.status = status;
+ send_data_rsp.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_rsp.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp;
+ cmd_len = sizeof(send_data_rsp);
+ } else {
+ send_data_rsp_64bit.listener_id = lstnr;
+ send_data_rsp_64bit.status = status;
+ send_data_rsp_64bit.sglistinfo_ptr =
+ virt_to_phys(table);
+ send_data_rsp_64bit.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp_64bit;
+ cmd_len = sizeof(send_data_rsp_64bit);
+ }
+ if (qseecom.whitelist_support == false)
+ *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
+ else
+ *(uint32_t *)cmd_buf =
+ QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
if (ptr_svc)
msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
@@ -1484,9 +1686,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
__qseecom_enable_clk(CLK_QSEE);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- (const void *)&send_data_rsp,
- sizeof(send_data_rsp), resp,
- sizeof(*resp));
+ cmd_buf, cmd_len, resp, sizeof(*resp));
+ ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
ret, data->client.app_id);
@@ -1519,9 +1721,14 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
uint32_t lstnr;
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
+ uint32_t status;
+ void *cmd_buf = NULL;
+ size_t cmd_len;
+ struct sglist_info *table = NULL;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -1585,13 +1792,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
- send_data_rsp.status = QSEOS_RESULT_FAILURE;
+ status = QSEOS_RESULT_FAILURE;
} else {
- send_data_rsp.status = QSEOS_RESULT_SUCCESS;
+ status = QSEOS_RESULT_SUCCESS;
}
-
- send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
- send_data_rsp.listener_id = lstnr;
+ table = ptr_svc->sglistinfo_ptr;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ send_data_rsp.listener_id = lstnr;
+ send_data_rsp.status = status;
+ send_data_rsp.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp;
+ cmd_len = sizeof(send_data_rsp);
+ } else {
+ send_data_rsp_64bit.listener_id = lstnr;
+ send_data_rsp_64bit.status = status;
+ send_data_rsp_64bit.sglistinfo_ptr =
+ virt_to_phys(table);
+ send_data_rsp_64bit.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp_64bit;
+ cmd_len = sizeof(send_data_rsp_64bit);
+ }
+ if (qseecom.whitelist_support == false)
+ *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
+ else
+ *(uint32_t *)cmd_buf =
+ QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
if (ptr_svc)
msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
@@ -1601,11 +1833,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
__qseecom_enable_clk(CLK_QSEE);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- (const void *)&send_data_rsp,
- sizeof(send_data_rsp), resp,
- sizeof(*resp));
-
+ cmd_buf, cmd_len, resp, sizeof(*resp));
ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
wake_up_interruptible(&ptr_svc->listener_block_app_wq);
if (ret) {
@@ -2134,11 +2364,6 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
return -EINVAL;
}
- if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
- pr_err("Invalid req/resp buffer, exiting\n");
- return -EINVAL;
- }
-
/* Clients need to ensure req_buf is at base offset of shared buffer */
if ((uintptr_t)req_ptr->cmd_req_buf !=
data_ptr->client.user_virt_sb_base) {
@@ -2146,15 +2371,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
return -EINVAL;
}
- if (((uintptr_t)req_ptr->resp_buf <
- data_ptr->client.user_virt_sb_base) ||
- ((uintptr_t)req_ptr->resp_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))){
- pr_err("response buffer address not within shared bufffer\n");
+ if (data_ptr->client.sb_length <
+ sizeof(struct qseecom_rpmb_provision_key)) {
+ pr_err("shared buffer is too small to hold key type\n");
return -EINVAL;
}
-
req_buf = data_ptr->client.sb_virt;
send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
@@ -2181,36 +2402,6 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
return -EINVAL;
}
- if (((uintptr_t)req_ptr->cmd_req_buf <
- data_ptr->client.user_virt_sb_base) ||
- ((uintptr_t)req_ptr->cmd_req_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if (((uintptr_t)req_ptr->resp_buf <
- data_ptr->client.user_virt_sb_base) ||
- ((uintptr_t)req_ptr->resp_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))){
- pr_err("response buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if ((req_ptr->cmd_req_len == 0) || (req_ptr->resp_len == 0) ||
- req_ptr->cmd_req_len > data_ptr->client.sb_length ||
- req_ptr->resp_len > data_ptr->client.sb_length) {
- pr_err("cmd buffer length or response buffer length not valid\n");
- return -EINVAL;
- }
-
- if (req_ptr->cmd_req_len > UINT_MAX - req_ptr->resp_len) {
- pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
- return -EINVAL;
- }
-
reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len;
if (reqd_len_sb_in > data_ptr->client.sb_length) {
pr_err("Not enough memory to fit cmd_buf and resp_buf. ");
@@ -2232,28 +2423,11 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
return ret;
}
-static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
- void __user *argp)
+static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
+ struct qseecom_send_svc_cmd_req *req)
{
- int ret = 0;
- struct qseecom_client_send_service_ireq send_svc_ireq;
- struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
- struct qseecom_command_scm_resp resp;
- struct qseecom_send_svc_cmd_req req;
- void *send_req_ptr;
- size_t req_buf_size;
-
- /*struct qseecom_command_scm_resp resp;*/
-
- if (copy_from_user(&req,
- (void __user *)argp,
- sizeof(req))) {
- pr_err("copy_from_user failed\n");
- return -EFAULT;
- }
-
- if ((req.resp_buf == NULL) || (req.cmd_req_buf == NULL)) {
- pr_err("cmd buffer or response buffer is null\n");
+ if (!req || !req->resp_buf || !req->cmd_req_buf) {
+ pr_err("req or cmd buffer or response buffer is null\n");
return -EINVAL;
}
@@ -2277,6 +2451,86 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
return -EINVAL;
}
+ if (((uintptr_t)req->cmd_req_buf <
+ data->client.user_virt_sb_base) ||
+ ((uintptr_t)req->cmd_req_buf >=
+ (data->client.user_virt_sb_base + data->client.sb_length))) {
+ pr_err("cmd buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+ if (((uintptr_t)req->resp_buf <
+ data->client.user_virt_sb_base) ||
+ ((uintptr_t)req->resp_buf >=
+ (data->client.user_virt_sb_base + data->client.sb_length))) {
+ pr_err("response buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+ if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
+ (req->cmd_req_len > data->client.sb_length) ||
+ (req->resp_len > data->client.sb_length)) {
+ pr_err("cmd buf length or response buf length not valid\n");
+ return -EINVAL;
+ }
+ if (req->cmd_req_len > UINT_MAX - req->resp_len) {
+ pr_err("Integer overflow detected in req_len & rsp_len\n");
+ return -EINVAL;
+ }
+
+ if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
+ pr_debug("Not enough memory to fit cmd_buf.\n");
+ pr_debug("resp_buf. Required: %u, Available: %zu\n",
+ (req->cmd_req_len + req->resp_len),
+ data->client.sb_length);
+ return -ENOMEM;
+ }
+ if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
+ pr_err("Integer overflow in req_len & cmd_req_buf\n");
+ return -EINVAL;
+ }
+ if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
+ pr_err("Integer overflow in resp_len & resp_buf\n");
+ return -EINVAL;
+ }
+ if (data->client.user_virt_sb_base >
+ (ULONG_MAX - data->client.sb_length)) {
+ pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
+ return -EINVAL;
+ }
+ if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length)) ||
+ (((uintptr_t)req->resp_buf + req->resp_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buf or resp buf is out of shared buffer region\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ int ret = 0;
+ struct qseecom_client_send_service_ireq send_svc_ireq;
+ struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
+ struct qseecom_command_scm_resp resp;
+ struct qseecom_send_svc_cmd_req req;
+ void *send_req_ptr;
+ size_t req_buf_size;
+
+ /*struct qseecom_command_scm_resp resp;*/
+
+ if (copy_from_user(&req,
+ (void __user *)argp,
+ sizeof(req))) {
+ pr_err("copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ if (__validate_send_service_cmd_inputs(data, &req))
+ return -EINVAL;
+
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
@@ -2528,8 +2782,8 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
{
int ret = 0;
u32 reqd_len_sb_in = 0;
- struct qseecom_client_send_data_ireq send_data_req;
- struct qseecom_client_send_data_64bit_ireq send_data_req_64bit;
+ struct qseecom_client_send_data_ireq send_data_req = {0};
+ struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
struct qseecom_command_scm_resp resp;
unsigned long flags;
struct qseecom_registered_app_list *ptr_app;
@@ -2537,6 +2791,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
int name_len = 0;
void *cmd_buf = NULL;
size_t cmd_len;
+ struct sglist_info *table = data->sglistinfo_ptr;
reqd_len_sb_in = req->cmd_req_len + req->resp_len;
/* find app_id & img_name from list */
@@ -2561,7 +2816,6 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
}
if (qseecom.qsee_version < QSEE_VERSION_40) {
- send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
send_data_req.app_id = data->client.app_id;
send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
data, (uintptr_t)req->cmd_req_buf));
@@ -2569,11 +2823,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
data, (uintptr_t)req->resp_buf));
send_data_req.rsp_len = req->resp_len;
+ send_data_req.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&send_data_req;
cmd_len = sizeof(struct qseecom_client_send_data_ireq);
} else {
- send_data_req_64bit.qsee_cmd_id =
- QSEOS_CLIENT_SEND_DATA_COMMAND;
send_data_req_64bit.app_id = data->client.app_id;
send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data,
(uintptr_t)req->cmd_req_buf);
@@ -2595,10 +2852,20 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
send_data_req_64bit.rsp_len);
return -EFAULT;
}
+ send_data_req_64bit.sglistinfo_ptr =
+ (uint64_t)virt_to_phys(table);
+ send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&send_data_req_64bit;
cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
}
+ if (qseecom.whitelist_support == false || data->use_legacy_cmd == true)
+ *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND;
+ else
+ *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
+
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
@@ -2699,6 +2966,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_send_modfd_cmd_req *req = NULL;
struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
struct qseecom_registered_listener_list *this_lstnr = NULL;
+ uint32_t offset;
+ struct sg_table *sg_ptr;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(data->type != QSEECOM_CLIENT_APP))
@@ -2720,7 +2989,6 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
}
for (i = 0; i < MAX_ION_FD; i++) {
- struct sg_table *sg_ptr = NULL;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -2852,14 +3120,37 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
goto err;
}
}
- if (cleanup)
+
+ if (cleanup) {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_INV_CACHES);
- else
+ } else {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (data->type == QSEECOM_CLIENT_APP) {
+ offset = req->ifd_data[i].cmd_buf_offset;
+ data->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 0, offset);
+ data->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ data->sglist_cnt = i + 1;
+ } else {
+ offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
+ + (uintptr_t)lstnr_resp->resp_buf_ptr -
+ (uintptr_t)this_lstnr->sb_virt);
+ this_lstnr->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 0, offset);
+ this_lstnr->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ this_lstnr->sglist_cnt = i + 1;
+ }
+ }
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -2883,6 +3174,8 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
struct qseecom_send_modfd_cmd_req *req = NULL;
struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
struct qseecom_registered_listener_list *this_lstnr = NULL;
+ uint32_t offset;
+ struct sg_table *sg_ptr;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(data->type != QSEECOM_CLIENT_APP))
@@ -2904,7 +3197,6 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
}
for (i = 0; i < MAX_ION_FD; i++) {
- struct sg_table *sg_ptr = NULL;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -2994,14 +3286,36 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
sg = sg_next(sg);
}
}
- if (cleanup)
+ if (cleanup) {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_INV_CACHES);
- else
+ } else {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (data->type == QSEECOM_CLIENT_APP) {
+ offset = req->ifd_data[i].cmd_buf_offset;
+ data->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 1, offset);
+ data->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ data->sglist_cnt = i + 1;
+ } else {
+ offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
+ + (uintptr_t)lstnr_resp->resp_buf_ptr -
+ (uintptr_t)this_lstnr->sb_virt);
+ this_lstnr->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 1, offset);
+ this_lstnr->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ this_lstnr->sglist_cnt = i + 1;
+ }
+ }
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -3195,7 +3509,7 @@ static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
return true;
}
-static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size,
+static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size,
uint32_t *app_arch)
{
int ret = -1;
@@ -3233,14 +3547,21 @@ static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size,
}
pr_debug("QSEE %s app, arch %u\n", appname, *app_arch);
release_firmware(fw_entry);
+ fw_entry = NULL;
for (i = 0; i < num_images; i++) {
memset(fw_name, 0, sizeof(fw_name));
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
if (ret)
goto err;
+ if (*fw_size > U32_MAX - fw_entry->size) {
+ pr_err("QSEE %s app file size overflow\n", appname);
+ ret = -EINVAL;
+ goto err;
+ }
*fw_size += fw_entry->size;
release_firmware(fw_entry);
+ fw_entry = NULL;
}
return ret;
@@ -3251,8 +3572,9 @@ err:
return ret;
}
-static int __qseecom_get_fw_data(char *appname, u8 *img_data,
- struct qseecom_load_app_ireq *load_req)
+static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
+ uint32_t fw_size,
+ struct qseecom_load_app_ireq *load_req)
{
int ret = -1;
int i = 0, rc = 0;
@@ -3272,6 +3594,12 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
}
load_req->img_len = fw_entry->size;
+ if (load_req->img_len > fw_size) {
+ pr_err("app %s size %zu is larger than buf size %u\n",
+ appname, fw_entry->size, fw_size);
+ ret = -EINVAL;
+ goto err;
+ }
memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
img_data_ptr = img_data_ptr + fw_entry->size;
load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
@@ -3290,6 +3618,7 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
goto err;
}
release_firmware(fw_entry);
+ fw_entry = NULL;
for (i = 0; i < num_images; i++) {
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
@@ -3297,10 +3626,17 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
pr_err("Failed to locate blob %s\n", fw_name);
goto err;
}
+ if ((fw_entry->size > U32_MAX - load_req->img_len) ||
+ (fw_entry->size + load_req->img_len > fw_size)) {
+ pr_err("Invalid file size for %s\n", fw_name);
+ ret = -EINVAL;
+ goto err;
+ }
memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
img_data_ptr = img_data_ptr + fw_entry->size;
load_req->img_len += fw_entry->size;
release_firmware(fw_entry);
+ fw_entry = NULL;
}
return ret;
err:
@@ -3405,7 +3741,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
if (ret)
return ret;
- ret = __qseecom_get_fw_data(appname, img_data, &load_req);
+ ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
if (ret) {
ret = -EIO;
goto exit_free_img_data;
@@ -3526,7 +3862,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data,
if (ret)
return -EIO;
- ret = __qseecom_get_fw_data(cmnlib_name, img_data, &load_req);
+ ret = __qseecom_get_fw_data(cmnlib_name, img_data, fw_size, &load_req);
if (ret) {
ret = -EIO;
goto exit_free_img_data;
@@ -3894,8 +4230,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
}
perf_enabled = true;
}
+ if (!strcmp(data->client.app_name, "securemm"))
+ data->use_legacy_cmd = true;
ret = __qseecom_send_cmd(data, &req);
+ data->use_legacy_cmd = false;
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
@@ -5295,7 +5634,8 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
}
if (req.in_buf == NULL || req.out_buf == NULL ||
- req.in_buf_size == 0 || req.out_buf_size == 0 ||
+ req.in_buf_size == 0 || req.in_buf_size > MAX_DIP ||
+ req.out_buf_size == 0 || req.out_buf_size > MAX_DIP ||
req.direction > 1) {
pr_err("invalid parameters\n");
ret = -EINVAL;
@@ -5575,14 +5915,23 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req,
*update = (uint32_t)sg_dma_address(sg_ptr->sgl);
}
clean:
- if (cleanup)
+ if (cleanup) {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, sg->length,
ION_IOC_INV_CACHES);
- else
+ } else {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, sg->length,
ION_IOC_CLEAN_INV_CACHES);
+ data->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 0,
+ req->ifd_data[i].cmd_buf_offset);
+ data->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ data->sglist_cnt = i + 1;
+ }
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -5607,6 +5956,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
uint32_t reqd_len_sb_in = 0;
void *cmd_buf = NULL;
size_t cmd_len;
+ struct sglist_info *table = data->sglistinfo_ptr;
ret = __qseecom_qteec_validate_msg(data, req);
if (ret)
@@ -5631,8 +5981,15 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
return -ENOENT;
}
+ if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
+ (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
+ ret = __qseecom_update_qteec_req_buf(
+ (struct qseecom_qteec_modfd_req *)req, data, false);
+ if (ret)
+ return ret;
+ }
+
if (qseecom.qsee_version < QSEE_VERSION_40) {
- ireq.qsee_cmd_id = cmd_id;
ireq.app_id = data->client.app_id;
ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
(uintptr_t)req->req_ptr);
@@ -5640,10 +5997,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
(uintptr_t)req->resp_ptr);
ireq.resp_len = req->resp_len;
+ ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
+ ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&ireq;
cmd_len = sizeof(struct qseecom_qteec_ireq);
} else {
- ireq_64bit.qsee_cmd_id = cmd_id;
ireq_64bit.app_id = data->client.app_id;
ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
(uintptr_t)req->req_ptr);
@@ -5663,17 +6023,19 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
ireq_64bit.resp_ptr, ireq_64bit.resp_len);
return -EFAULT;
}
+ ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
+ ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&ireq_64bit;
cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
}
+ if (qseecom.whitelist_support == true
+ && cmd_id == QSEOS_TEE_OPEN_SESSION)
+ *(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST;
+ else
+ *(uint32_t *)cmd_buf = cmd_id;
- if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
- (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
- ret = __qseecom_update_qteec_req_buf(
- (struct qseecom_qteec_modfd_req *)req, data, false);
- if (ret)
- return ret;
- }
reqd_len_sb_in = req->req_len + req->resp_len;
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
@@ -5771,6 +6133,9 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
uint32_t reqd_len_sb_in = 0;
void *cmd_buf = NULL;
size_t cmd_len;
+ struct sglist_info *table = data->sglistinfo_ptr;
+ void *req_ptr = NULL;
+ void *resp_ptr = NULL;
ret = copy_from_user(&req, argp,
sizeof(struct qseecom_qteec_modfd_req));
@@ -5782,6 +6147,8 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
(struct qseecom_qteec_req *)(&req));
if (ret)
return ret;
+ req_ptr = req.req_ptr;
+ resp_ptr = req.resp_ptr;
/* find app_id & img_name from list */
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
@@ -5802,45 +6169,56 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
return -ENOENT;
}
+ /* validate offsets */
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req.ifd_data[i].fd) {
+ if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
+ return -EINVAL;
+ }
+ }
+ req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uintptr_t)req.req_ptr);
+ req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uintptr_t)req.resp_ptr);
+ ret = __qseecom_update_qteec_req_buf(&req, data, false);
+ if (ret)
+ return ret;
+
if (qseecom.qsee_version < QSEE_VERSION_40) {
- ireq.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
ireq.app_id = data->client.app_id;
ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.req_ptr);
+ (uintptr_t)req_ptr);
ireq.req_len = req.req_len;
ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.resp_ptr);
+ (uintptr_t)resp_ptr);
ireq.resp_len = req.resp_len;
cmd_buf = (void *)&ireq;
cmd_len = sizeof(struct qseecom_qteec_ireq);
+ ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
+ ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
} else {
- ireq_64bit.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
ireq_64bit.app_id = data->client.app_id;
ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.req_ptr);
+ (uintptr_t)req_ptr);
ireq_64bit.req_len = req.req_len;
ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.resp_ptr);
+ (uintptr_t)resp_ptr);
ireq_64bit.resp_len = req.resp_len;
cmd_buf = (void *)&ireq_64bit;
cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
+ ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
+ ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
}
reqd_len_sb_in = req.req_len + req.resp_len;
+ if (qseecom.whitelist_support == true)
+ *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST;
+ else
+ *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND;
- /* validate offsets */
- for (i = 0; i < MAX_ION_FD; i++) {
- if (req.ifd_data[i].fd) {
- if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
- return -EINVAL;
- }
- }
- req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
- (uintptr_t)req.req_ptr);
- req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
- (uintptr_t)req.resp_ptr);
- ret = __qseecom_update_qteec_req_buf(&req, data, false);
- if (ret)
- return ret;
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
@@ -5903,6 +6281,15 @@ static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data,
return ret;
}
+static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
+{
+ if (data->sglist_cnt) {
+ memset(data->sglistinfo_ptr, 0,
+ SGLISTINFO_TABLE_SIZE);
+ data->sglist_cnt = 0;
+ }
+}
+
long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
int ret = 0;
@@ -6082,6 +6469,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed qseecom_send_cmd: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_IOCTL_RECEIVE_REQ: {
@@ -6455,6 +6843,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
wake_up_all(&data->abort_wq);
if (ret)
pr_err("failed qseecom_send_mod_resp: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ: {
@@ -6479,6 +6868,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed open_session_cmd: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: {
@@ -6527,6 +6917,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed Invoke cmd: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: {
@@ -6578,7 +6969,6 @@ static int qseecom_open(struct inode *inode, struct file *file)
data->mode = INACTIVE;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
-
return ret;
}
@@ -6773,6 +7163,17 @@ static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
qclk->instance = CLK_INVALID;
}
+/*
+ * Check whitelist feature, and if TZ feature version is < 1.0.0,
+ * then whitelist feature is not supported.
+ */
+static int qseecom_check_whitelist_feature(void)
+{
+ int version = scm_get_feat_version(FEATURE_ID_WHITELIST);
+
+ return version >= MAKE_WHITELIST_VERSION(1, 0, 0);
+}
+
static int qseecom_probe(struct platform_device *pdev)
{
int rc;
@@ -6804,6 +7205,7 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.app_block_ref_cnt = 0;
init_waitqueue_head(&qseecom.app_block_wq);
+ qseecom.whitelist_support = true;
rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
if (rc < 0) {
@@ -7096,6 +7498,10 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
+ qseecom.whitelist_support = qseecom_check_whitelist_feature();
+ pr_warn("qseecom.whitelist_support = %d\n",
+ qseecom.whitelist_support);
+
if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
return 0;
diff --git a/drivers/net/ethernet/msm/rndis_ipa.c b/drivers/net/ethernet/msm/rndis_ipa.c
index 09b85fb32d4..c61e2a72040 100644
--- a/drivers/net/ethernet/msm/rndis_ipa.c
+++ b/drivers/net/ethernet/msm/rndis_ipa.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -132,29 +132,6 @@ enum rndis_ipa_operation {
RNDIS_IPA_DEBUG("Driver state: %s\n",\
rndis_ipa_state_string(ctx->state));
-/**
- * struct rndis_loopback_pipe - hold all information needed for
- * pipe loopback logic
- */
-struct rndis_loopback_pipe {
- struct sps_pipe *ipa_sps;
- struct ipa_sps_params ipa_sps_connect;
- struct ipa_connect_params ipa_connect_params;
-
- struct sps_pipe *dma_sps;
- struct sps_connect dma_connect;
-
- struct sps_alloc_dma_chan dst_alloc;
- struct sps_dma_chan ipa_sps_channel;
- enum sps_mode mode;
- u32 ipa_peer_bam_hdl;
- u32 peer_pipe_index;
- u32 ipa_drv_ep_hdl;
- u32 ipa_pipe_index;
- enum ipa_client_type ipa_client;
- ipa_notify_cb ipa_callback;
- struct ipa_ep_cfg *ipa_ep_cfg;
-};
/**
* struct rndis_ipa_dev - main driver context parameters
@@ -169,13 +146,9 @@ struct rndis_loopback_pipe {
* @rx_dump_enable: dump all Rx packets
* @icmp_filter: allow all ICMP packet to pass through the filters
* @rm_enable: flag that enable/disable Resource manager request prior to Tx
- * @loopback_enable: flag that enable/disable USB stub loopback
* @deaggregation_enable: enable/disable IPA HW deaggregation logic
* @during_xmit_error: flags that indicate that the driver is in a middle
* of error handling in Tx path
- * @usb_to_ipa_loopback_pipe: usb to ipa (Rx) pipe representation for loopback
- * @ipa_to_usb_loopback_pipe: ipa to usb (Tx) pipe representation for loopback
- * @bam_dma_hdl: handle representing bam-dma, used for loopback logic
* @directory: holds all debug flags used by the driver to allow cleanup
* for driver unload
* @eth_ipv4_hdr_hdl: saved handle for ipv4 header-insertion table
@@ -205,12 +178,8 @@ struct rndis_ipa_dev {
u32 rx_dump_enable;
u32 icmp_filter;
u32 rm_enable;
- bool loopback_enable;
u32 deaggregation_enable;
u32 during_xmit_error;
- struct rndis_loopback_pipe usb_to_ipa_loopback_pipe;
- struct rndis_loopback_pipe ipa_to_usb_loopback_pipe;
- u32 bam_dma_hdl;
struct dentry *directory;
uint32_t eth_ipv4_hdr_hdl;
uint32_t eth_ipv6_hdr_hdl;
@@ -274,31 +243,12 @@ static int resource_request(struct rndis_ipa_dev *rndis_ipa_ctx);
static void resource_release(struct rndis_ipa_dev *rndis_ipa_ctx);
static netdev_tx_t rndis_ipa_start_xmit(struct sk_buff *skb,
struct net_device *net);
-static int rndis_ipa_loopback_pipe_create(
- struct rndis_ipa_dev *rndis_ipa_ctx,
- struct rndis_loopback_pipe *loopback_pipe);
-static void rndis_ipa_destroy_loopback_pipe(
- struct rndis_loopback_pipe *loopback_pipe);
-static int rndis_ipa_create_loopback(struct rndis_ipa_dev *rndis_ipa_ctx);
-static void rndis_ipa_destroy_loopback(struct rndis_ipa_dev *rndis_ipa_ctx);
-static int rndis_ipa_setup_loopback(bool enable,
- struct rndis_ipa_dev *rndis_ipa_ctx);
-static int rndis_ipa_debugfs_loopback_open(struct inode *inode,
- struct file *file);
static int rndis_ipa_debugfs_atomic_open(struct inode *inode,
struct file *file);
static int rndis_ipa_debugfs_aggr_open(struct inode *inode,
struct file *file);
static ssize_t rndis_ipa_debugfs_aggr_write(struct file *file,
const char __user *buf, size_t count, loff_t *ppos);
-static ssize_t rndis_ipa_debugfs_loopback_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-static ssize_t rndis_ipa_debugfs_enable_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos);
-static ssize_t rndis_ipa_debugfs_enable_read(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos);
-static ssize_t rndis_ipa_debugfs_loopback_read(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos);
static ssize_t rndis_ipa_debugfs_atomic_read(struct file *file,
char __user *ubuf, size_t count, loff_t *ppos);
static void rndis_ipa_dump_skb(struct sk_buff *skb);
@@ -333,12 +283,6 @@ const struct file_operations rndis_ipa_debugfs_atomic_ops = {
.read = rndis_ipa_debugfs_atomic_read,
};
-const struct file_operations rndis_ipa_loopback_ops = {
- .open = rndis_ipa_debugfs_loopback_open,
- .read = rndis_ipa_debugfs_loopback_read,
- .write = rndis_ipa_debugfs_loopback_write,
-};
-
const struct file_operations rndis_ipa_aggr_ops = {
.open = rndis_ipa_debugfs_aggr_open,
.write = rndis_ipa_debugfs_aggr_write,
@@ -2188,14 +2132,6 @@ static int rndis_ipa_debugfs_init(struct rndis_ipa_dev *rndis_ipa_ctx)
goto fail_file;
}
- file = debugfs_create_file("loopback_enable", flags_read_write,
- rndis_ipa_ctx->directory,
- rndis_ipa_ctx, &rndis_ipa_loopback_ops);
- if (!file) {
- RNDIS_IPA_ERROR("could not create outstanding file\n");
- goto fail_file;
- }
-
file = debugfs_create_u8("state", flags_read_only,
rndis_ipa_ctx->directory, (u8 *)&rndis_ipa_ctx->state);
if (!file) {
@@ -2351,59 +2287,6 @@ static ssize_t rndis_ipa_debugfs_aggr_write(struct file *file,
return count;
}
-static int rndis_ipa_debugfs_loopback_open(struct inode *inode,
- struct file *file)
-{
- struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private;
- file->private_data = rndis_ipa_ctx;
-
- return 0;
-}
-
-static ssize_t rndis_ipa_debugfs_loopback_read(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
-{
- int cnt;
- struct rndis_ipa_dev *rndis_ipa_ctx = file->private_data;
-
- file->private_data = &rndis_ipa_ctx->loopback_enable;
-
- cnt = rndis_ipa_debugfs_enable_read(file,
- ubuf, count, ppos);
-
- return cnt;
-}
-
-static ssize_t rndis_ipa_debugfs_loopback_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- int retval;
- int cnt;
- struct rndis_ipa_dev *rndis_ipa_ctx = file->private_data;
- bool old_state = rndis_ipa_ctx->loopback_enable;
-
- file->private_data = &rndis_ipa_ctx->loopback_enable;
-
- cnt = rndis_ipa_debugfs_enable_write(file,
- buf, count, ppos);
-
- RNDIS_IPA_DEBUG("loopback_enable was set to:%d->%d\n",
- old_state, rndis_ipa_ctx->loopback_enable);
-
- if (old_state == rndis_ipa_ctx->loopback_enable) {
- RNDIS_IPA_ERROR("NOP - same state\n");
- return cnt;
- }
-
- retval = rndis_ipa_setup_loopback(
- rndis_ipa_ctx->loopback_enable,
- rndis_ipa_ctx);
- if (retval)
- rndis_ipa_ctx->loopback_enable = old_state;
-
- return cnt;
-}
-
static int rndis_ipa_debugfs_atomic_open(struct inode *inode, struct file *file)
{
struct rndis_ipa_dev *rndis_ipa_ctx = inode->i_private;
@@ -2434,319 +2317,6 @@ static ssize_t rndis_ipa_debugfs_atomic_read(struct file *file,
return simple_read_from_buffer(ubuf, count, ppos, atomic_str, nbytes);
}
-static ssize_t rndis_ipa_debugfs_enable_read(struct file *file,
- char __user *ubuf, size_t count, loff_t *ppos)
-{
- int nbytes;
- int size = 0;
- int ret;
- loff_t pos;
- u8 enable_str[sizeof(char)*3] = {0};
- bool *enable = file->private_data;
- pos = *ppos;
- nbytes = scnprintf(enable_str, sizeof(enable_str), "%d\n", *enable);
- ret = simple_read_from_buffer(ubuf, count, ppos, enable_str, nbytes);
- if (ret < 0) {
- RNDIS_IPA_ERROR("simple_read_from_buffer problem\n");
- return ret;
- }
- size += ret;
- count -= nbytes;
- *ppos = pos + size;
- return size;
-}
-
-static ssize_t rndis_ipa_debugfs_enable_write(struct file *file,
- const char __user *buf, size_t count, loff_t *ppos)
-{
- unsigned long missing;
- char input;
- bool *enable = file->private_data;
- if (count != sizeof(input) + 1) {
- RNDIS_IPA_ERROR("wrong input length(%zd)\n", count);
- return -EINVAL;
- }
- if (!buf) {
- RNDIS_IPA_ERROR("Bad argument\n");
- return -EINVAL;
- }
- missing = copy_from_user(&input, buf, 1);
- if (missing)
- return -EFAULT;
- RNDIS_IPA_DEBUG("input received %c\n", input);
- *enable = input - '0';
- RNDIS_IPA_DEBUG("value was set to %d\n", *enable);
- return count;
-}
-
-/**
- * Connects IPA->BAMDMA
- * This shall simulate the path from IPA to USB
- * Allowing the driver TX path
- */
-static int rndis_ipa_loopback_pipe_create(
- struct rndis_ipa_dev *rndis_ipa_ctx,
- struct rndis_loopback_pipe *loopback_pipe)
-{
- int retval;
-
- RNDIS_IPA_LOG_ENTRY();
-
- /* SPS pipe has two side handshake
- * This is the first handshake of IPA->BAMDMA,
- * This is the IPA side
- */
- loopback_pipe->ipa_connect_params.client = loopback_pipe->ipa_client;
- loopback_pipe->ipa_connect_params.client_bam_hdl =
- rndis_ipa_ctx->bam_dma_hdl;
- loopback_pipe->ipa_connect_params.client_ep_idx =
- loopback_pipe->peer_pipe_index;
- loopback_pipe->ipa_connect_params.desc_fifo_sz = BAM_DMA_DESC_FIFO_SIZE;
- loopback_pipe->ipa_connect_params.data_fifo_sz = BAM_DMA_DATA_FIFO_SIZE;
- loopback_pipe->ipa_connect_params.notify = loopback_pipe->ipa_callback;
- loopback_pipe->ipa_connect_params.priv = rndis_ipa_ctx;
- loopback_pipe->ipa_connect_params.ipa_ep_cfg =
- *(loopback_pipe->ipa_ep_cfg);
-
- /* loopback_pipe->ipa_sps_connect is out param */
- retval = ipa_connect(&loopback_pipe->ipa_connect_params,
- &loopback_pipe->ipa_sps_connect,
- &loopback_pipe->ipa_drv_ep_hdl);
- if (retval) {
- RNDIS_IPA_ERROR("ipa_connect() fail (%d)", retval);
- return retval;
- }
- RNDIS_IPA_DEBUG("ipa_connect() succeeded, ipa_drv_ep_hdl=%d",
- loopback_pipe->ipa_drv_ep_hdl);
-
- /* SPS pipe has two side handshake
- * This is the second handshake of IPA->BAMDMA,
- * This is the BAMDMA side
- */
- loopback_pipe->dma_sps = sps_alloc_endpoint();
- if (!loopback_pipe->dma_sps) {
- RNDIS_IPA_ERROR("sps_alloc_endpoint() failed ");
- retval = -ENOMEM;
- goto fail_sps_alloc;
- }
-
- retval = sps_get_config(loopback_pipe->dma_sps,
- &loopback_pipe->dma_connect);
- if (retval) {
- RNDIS_IPA_ERROR("sps_get_config() failed (%d)", retval);
- goto fail_get_cfg;
- }
-
- /* Start setting the non IPA ep for SPS driver*/
- loopback_pipe->dma_connect.mode = loopback_pipe->mode;
-
- /* SPS_MODE_DEST: DMA end point is the dest (consumer) IPA->DMA */
- if (loopback_pipe->mode == SPS_MODE_DEST) {
-
- loopback_pipe->dma_connect.source =
- loopback_pipe->ipa_sps_connect.ipa_bam_hdl;
- loopback_pipe->dma_connect.src_pipe_index =
- loopback_pipe->ipa_sps_connect.ipa_ep_idx;
- loopback_pipe->dma_connect.destination =
- rndis_ipa_ctx->bam_dma_hdl;
- loopback_pipe->dma_connect.dest_pipe_index =
- loopback_pipe->peer_pipe_index;
-
- /* SPS_MODE_SRC: DMA end point is the source (producer) DMA->IPA */
- } else {
-
- loopback_pipe->dma_connect.source =
- rndis_ipa_ctx->bam_dma_hdl;
- loopback_pipe->dma_connect.src_pipe_index =
- loopback_pipe->peer_pipe_index;
- loopback_pipe->dma_connect.destination =
- loopback_pipe->ipa_sps_connect.ipa_bam_hdl;
- loopback_pipe->dma_connect.dest_pipe_index =
- loopback_pipe->ipa_sps_connect.ipa_ep_idx;
-
- }
-
- loopback_pipe->dma_connect.desc = loopback_pipe->ipa_sps_connect.desc;
- loopback_pipe->dma_connect.data = loopback_pipe->ipa_sps_connect.data;
- loopback_pipe->dma_connect.event_thresh = 0x10;
- /* BAM-to-BAM */
- loopback_pipe->dma_connect.options = SPS_O_AUTO_ENABLE;
-
- RNDIS_IPA_DEBUG("doing sps_connect() with - ");
- RNDIS_IPA_DEBUG("src bam_hdl:0x%lx, src_pipe#:%d",
- loopback_pipe->dma_connect.source,
- loopback_pipe->dma_connect.src_pipe_index);
- RNDIS_IPA_DEBUG("dst bam_hdl:0x%lx, dst_pipe#:%d",
- loopback_pipe->dma_connect.destination,
- loopback_pipe->dma_connect.dest_pipe_index);
-
- retval = sps_connect(loopback_pipe->dma_sps,
- &loopback_pipe->dma_connect);
- if (retval) {
- RNDIS_IPA_ERROR("sps_connect() fail for BAMDMA side (%d)",
- retval);
- goto fail_sps_connect;
- }
-
- RNDIS_IPA_LOG_EXIT();
-
- return 0;
-
-fail_sps_connect:
-fail_get_cfg:
- sps_free_endpoint(loopback_pipe->dma_sps);
-fail_sps_alloc:
- ipa_disconnect(loopback_pipe->ipa_drv_ep_hdl);
- return retval;
-}
-
-static void rndis_ipa_destroy_loopback_pipe(
- struct rndis_loopback_pipe *loopback_pipe)
-{
- sps_disconnect(loopback_pipe->dma_sps);
- sps_free_endpoint(loopback_pipe->dma_sps);
-}
-
-/**
- * rndis_ipa_create_loopback() - create a BAM-DMA loopback
- * in order to replace the USB core
- */
-static int rndis_ipa_create_loopback(struct rndis_ipa_dev *rndis_ipa_ctx)
-{
- /* The BAM handle should be use as
- * source/destination in the sps_connect()
- */
- int retval;
-
- RNDIS_IPA_LOG_ENTRY();
-
-
- retval = sps_ctrl_bam_dma_clk(true);
- if (retval) {
- RNDIS_IPA_ERROR("fail on enabling BAM-DMA clocks");
- return -ENODEV;
- }
-
- /* Get BAM handle instead of USB handle */
- rndis_ipa_ctx->bam_dma_hdl = sps_dma_get_bam_handle();
- if (!rndis_ipa_ctx->bam_dma_hdl) {
- RNDIS_IPA_ERROR("sps_dma_get_bam_handle() failed");
- return -ENODEV;
- }
- RNDIS_IPA_DEBUG("sps_dma_get_bam_handle() succeeded (0x%x)",
- rndis_ipa_ctx->bam_dma_hdl);
-
- /* IPA<-BAMDMA, NetDev Rx path (BAMDMA is the USB stub) */
- rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_client =
- IPA_CLIENT_USB_PROD;
- rndis_ipa_ctx->usb_to_ipa_loopback_pipe.peer_pipe_index =
- FROM_USB_TO_IPA_BAMDMA;
- /*DMA EP mode*/
- rndis_ipa_ctx->usb_to_ipa_loopback_pipe.mode = SPS_MODE_SRC;
- rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_ep_cfg =
- &usb_to_ipa_ep_cfg_deaggr_en;
- rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_callback =
- rndis_ipa_packet_receive_notify;
- RNDIS_IPA_DEBUG("setting up IPA<-BAMDAM pipe (RNDIS_IPA RX path)");
- retval = rndis_ipa_loopback_pipe_create(rndis_ipa_ctx,
- &rndis_ipa_ctx->usb_to_ipa_loopback_pipe);
- if (retval) {
- RNDIS_IPA_ERROR("fail to close IPA->BAMDAM pipe");
- goto fail_to_usb;
- }
- RNDIS_IPA_DEBUG("IPA->BAMDAM pipe successfully connected (TX path)");
-
- /* IPA->BAMDMA, NetDev Tx path (BAMDMA is the USB stub)*/
- rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_client =
- IPA_CLIENT_USB_CONS;
- /*DMA EP mode*/
- rndis_ipa_ctx->ipa_to_usb_loopback_pipe.mode = SPS_MODE_DEST;
- rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_ep_cfg = &ipa_to_usb_ep_cfg;
- rndis_ipa_ctx->ipa_to_usb_loopback_pipe.peer_pipe_index =
- FROM_IPA_TO_USB_BAMDMA;
- rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_callback =
- rndis_ipa_tx_complete_notify;
- RNDIS_IPA_DEBUG("setting up IPA->BAMDAM pipe (RNDIS_IPA TX path)");
- retval = rndis_ipa_loopback_pipe_create(rndis_ipa_ctx,
- &rndis_ipa_ctx->ipa_to_usb_loopback_pipe);
- if (retval) {
- RNDIS_IPA_ERROR("fail to close IPA<-BAMDAM pipe");
- goto fail_from_usb;
- }
- RNDIS_IPA_DEBUG("IPA<-BAMDAM pipe successfully connected(RX path)");
-
- RNDIS_IPA_LOG_EXIT();
-
- return 0;
-
-fail_from_usb:
- rndis_ipa_destroy_loopback_pipe(
- &rndis_ipa_ctx->usb_to_ipa_loopback_pipe);
-fail_to_usb:
-
- return retval;
-}
-
-static void rndis_ipa_destroy_loopback(struct rndis_ipa_dev *rndis_ipa_ctx)
-{
- rndis_ipa_destroy_loopback_pipe(
- &rndis_ipa_ctx->ipa_to_usb_loopback_pipe);
- rndis_ipa_destroy_loopback_pipe(
- &rndis_ipa_ctx->usb_to_ipa_loopback_pipe);
- sps_dma_free_bam_handle(rndis_ipa_ctx->bam_dma_hdl);
- if (sps_ctrl_bam_dma_clk(false))
- RNDIS_IPA_ERROR("fail to disable BAM-DMA clocks");
-}
-
-/**
- * rndis_ipa_setup_loopback() - create/destroy a loopback on IPA HW
- * (as USB pipes loopback) and notify RNDIS_IPA netdev for pipe connected
- * @enable: flag that determines if the loopback should be created or destroyed
- * @rndis_ipa_ctx: driver main context
- *
- * This function is the main loopback logic.
- * It shall create/destory the loopback by using BAM-DMA and notify
- * the netdev accordingly.
- */
-static int rndis_ipa_setup_loopback(bool enable,
- struct rndis_ipa_dev *rndis_ipa_ctx)
-{
- int retval;
-
- if (!enable) {
- rndis_ipa_destroy_loopback(rndis_ipa_ctx);
- RNDIS_IPA_DEBUG("loopback destroy done");
- retval = rndis_ipa_pipe_disconnect_notify(rndis_ipa_ctx);
- if (retval) {
- RNDIS_IPA_ERROR("connect notify fail");
- return -ENODEV;
- }
- return 0;
- }
-
- RNDIS_IPA_DEBUG("creating loopback (instead of USB core)");
- retval = rndis_ipa_create_loopback(rndis_ipa_ctx);
- RNDIS_IPA_DEBUG("creating loopback- %s", (retval ? "FAIL" : "OK"));
- if (retval) {
- RNDIS_IPA_ERROR("Fail to connect loopback");
- return -ENODEV;
- }
- retval = rndis_ipa_pipe_connect_notify(
- rndis_ipa_ctx->usb_to_ipa_loopback_pipe.ipa_drv_ep_hdl,
- rndis_ipa_ctx->ipa_to_usb_loopback_pipe.ipa_drv_ep_hdl,
- BAM_DMA_DATA_FIFO_SIZE,
- 15,
- BAM_DMA_DATA_FIFO_SIZE - rndis_ipa_ctx->net->mtu,
- rndis_ipa_ctx);
- if (retval) {
- RNDIS_IPA_ERROR("connect notify fail");
- return -ENODEV;
- }
-
- return 0;
-
-}
-
static int rndis_ipa_init_module(void)
{
pr_info("RNDIS_IPA module is loaded.");
diff --git a/drivers/platform/msm/ipa/ipa_flt.c b/drivers/platform/msm/ipa/ipa_flt.c
index 140986aab5f..b179737c318 100644
--- a/drivers/platform/msm/ipa/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -235,7 +235,7 @@ static int ipa_generate_flt_hw_rule(enum ipa_ip_type ip,
* @ip: the ip address family type
* @hdr_sz: header size
*
- * Returns: 0 on success, negative on failure
+ * Returns: size on success, negative on failure
*
* caller needs to hold any needed locks to ensure integrity
*
@@ -373,7 +373,12 @@ static int ipa_generate_flt_hw_tbl_common(enum ipa_ip_type ip, u8 *base,
((long)body &
IPA_FLT_ENTRY_MEMORY_ALLIGNMENT));
} else {
- WARN_ON(tbl->sz == 0);
+ if (tbl->sz == 0) {
+ IPAERR("tbl size is 0\n");
+ WARN_ON(1);
+ goto proc_err;
+ }
+
/* allocate memory for the flt tbl */
flt_tbl_mem.size = tbl->sz;
flt_tbl_mem.base =
@@ -460,7 +465,12 @@ static int ipa_generate_flt_hw_tbl_common(enum ipa_ip_type ip, u8 *base,
((long)body &
IPA_FLT_ENTRY_MEMORY_ALLIGNMENT));
} else {
- WARN_ON(tbl->sz == 0);
+ if (tbl->sz == 0) {
+ IPAERR("tbl size is 0\n");
+ WARN_ON(1);
+ goto proc_err;
+ }
+
/* allocate memory for the flt tbl */
flt_tbl_mem.size = tbl->sz;
flt_tbl_mem.base =
@@ -534,8 +544,15 @@ static int ipa_generate_flt_hw_tbl_v1_1(enum ipa_ip_type ip,
u8 *hdr;
u8 *body;
u8 *base;
+ int res;
+
+ res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ if (res < 0) {
+ IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res);
+ return res;
+ }
- mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ mem->size = res;
mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size);
if (mem->size == 0) {
@@ -720,6 +737,7 @@ static int ipa_generate_flt_hw_tbl_v2(enum ipa_ip_type ip,
u32 *entr;
u32 body_start_offset;
u32 hdr_top;
+ int res;
if (ip == IPA_IP_v4)
body_start_offset = IPA_MEM_PART(apps_v4_flt_ofst) -
@@ -756,7 +774,13 @@ static int ipa_generate_flt_hw_tbl_v2(enum ipa_ip_type ip,
entr++;
}
- mem->size = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ res = ipa_get_flt_hw_tbl_size(ip, &hdr_sz);
+ if (res < 0) {
+ IPAERR("ipa_get_flt_hw_tbl_size failed %d\n", res);
+ goto body_err;
+ }
+
+ mem->size = res;
mem->size -= hdr_sz;
mem->size = IPA_HW_TABLE_ALIGNMENT(mem->size);
diff --git a/drivers/platform/msm/ipa/ipa_nat.c b/drivers/platform/msm/ipa/ipa_nat.c
index b4ccf5f9946..12691fac466 100644
--- a/drivers/platform/msm/ipa/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -25,6 +25,16 @@
#define IPA_NAT_SHARED_MEMORY 1
#define IPA_NAT_TEMP_MEM_SIZE 128
+enum nat_table_type {
+ IPA_NAT_BASE_TBL = 0,
+ IPA_NAT_EXPN_TBL = 1,
+ IPA_NAT_INDX_TBL = 2,
+ IPA_NAT_INDEX_EXPN_TBL = 3,
+};
+
+#define NAT_TABLE_ENTRY_SIZE_BYTE 32
+#define NAT_INTEX_TABLE_ENTRY_SIZE_BYTE 4
+
static int ipa_nat_vma_fault_remap(
struct vm_area_struct *vma, struct vm_fault *vmf)
{
@@ -566,6 +576,71 @@ int ipa_nat_dma_cmd(struct ipa_ioc_nat_dma_cmd *dma)
goto bail;
}
+ for (cnt = 0; cnt < dma->entries; cnt++) {
+ if (dma->dma[cnt].table_index >= 1) {
+ IPAERR("Invalid table index %d\n",
+ dma->dma[cnt].table_index);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ switch (dma->dma[cnt].base_addr) {
+ case IPA_NAT_BASE_TBL:
+ if (dma->dma[cnt].offset >=
+ (ipa_ctx->nat_mem.size_base_tables + 1) *
+ NAT_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_EXPN_TBL:
+ if (dma->dma[cnt].offset >=
+ ipa_ctx->nat_mem.size_expansion_tables *
+ NAT_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_INDX_TBL:
+ if (dma->dma[cnt].offset >=
+ (ipa_ctx->nat_mem.size_base_tables + 1) *
+ NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ case IPA_NAT_INDEX_EXPN_TBL:
+ if (dma->dma[cnt].offset >=
+ ipa_ctx->nat_mem.size_expansion_tables *
+ NAT_INTEX_TABLE_ENTRY_SIZE_BYTE) {
+ IPAERR("Invalid offset %d\n",
+ dma->dma[cnt].offset);
+ ret = -EPERM;
+ goto bail;
+ }
+
+ break;
+
+ default:
+ IPAERR("Invalid base_addr %d\n",
+ dma->dma[cnt].base_addr);
+ ret = -EPERM;
+ goto bail;
+ }
+ }
+
size = sizeof(struct ipa_desc) * NUM_OF_DESC;
desc = kzalloc(size, GFP_KERNEL);
if (desc == NULL) {
diff --git a/drivers/platform/msm/ipa/ipa_rt.c b/drivers/platform/msm/ipa/ipa_rt.c
index 660f3fb014c..0476f519b24 100644
--- a/drivers/platform/msm/ipa/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_rt.c
@@ -226,7 +226,7 @@ int __ipa_generate_rt_hw_rule_v2_6L(enum ipa_ip_type ip,
* @hdr_sz: header size
* @max_rt_idx: maximal index
*
- * Returns: 0 on success, negative on failure
+ * Returns: size on success, negative on failure
*
* caller needs to hold any needed locks to ensure integrity
*
@@ -355,7 +355,11 @@ static int ipa_generate_rt_hw_tbl_common(enum ipa_ip_type ip, u8 *base, u8 *hdr,
((long)body &
IPA_RT_ENTRY_MEMORY_ALLIGNMENT));
} else {
- WARN_ON(tbl->sz == 0);
+ if (tbl->sz == 0) {
+ IPAERR("cannot generate 0 size table\n");
+ goto proc_err;
+ }
+
/* allocate memory for the RT tbl */
rt_tbl_mem.size = tbl->sz;
rt_tbl_mem.base =
@@ -428,8 +432,15 @@ static int ipa_generate_rt_hw_tbl_v1_1(enum ipa_ip_type ip,
u8 *base;
int max_rt_idx;
int i;
+ int res;
- mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ if (res < 0) {
+ IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res);
+ goto error;
+ }
+
+ mem->size = res;
mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) &
~IPA_RT_TABLE_MEMORY_ALLIGNMENT;
@@ -602,6 +613,7 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip,
int num_index;
u32 body_start_offset;
u32 apps_start_idx;
+ int res;
if (ip == IPA_IP_v4) {
num_index = IPA_MEM_PART(v4_apps_rt_index_hi) -
@@ -631,7 +643,13 @@ static int ipa_generate_rt_hw_tbl_v2(enum ipa_ip_type ip,
entr++;
}
- mem->size = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ res = ipa_get_rt_hw_tbl_size(ip, &hdr_sz, &max_rt_idx);
+ if (res < 0) {
+ IPAERR("ipa_get_rt_hw_tbl_size failed %d\n", res);
+ goto base_err;
+ }
+
+ mem->size = res;
mem->size -= hdr_sz;
mem->size = (mem->size + IPA_RT_TABLE_MEMORY_ALLIGNMENT) &
~IPA_RT_TABLE_MEMORY_ALLIGNMENT;
diff --git a/drivers/power/qpnp-fg.c b/drivers/power/qpnp-fg.c
index 25e1f1ced3b..a83284e65c7 100755
--- a/drivers/power/qpnp-fg.c
+++ b/drivers/power/qpnp-fg.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -525,6 +525,7 @@ struct fg_trans {
struct fg_chip *chip;
struct fg_log_buffer *log; /* log buffer */
u8 *data; /* fg data that is read */
+ struct mutex memif_dfs_lock; /* Prevent thread concurrency */
};
struct fg_dbgfs {
@@ -5259,6 +5260,7 @@ static int fg_memif_data_open(struct inode *inode, struct file *file)
trans->addr = dbgfs_data.addr;
trans->chip = dbgfs_data.chip;
trans->offset = trans->addr;
+ mutex_init(&trans->memif_dfs_lock);
file->private_data = trans;
return 0;
@@ -5270,6 +5272,7 @@ static int fg_memif_dfs_close(struct inode *inode, struct file *file)
if (trans && trans->log && trans->data) {
file->private_data = NULL;
+ mutex_destroy(&trans->memif_dfs_lock);
kfree(trans->log);
kfree(trans->data);
kfree(trans);
@@ -5427,10 +5430,13 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf,
size_t ret;
size_t len;
+ mutex_lock(&trans->memif_dfs_lock);
/* Is the the log buffer empty */
if (log->rpos >= log->wpos) {
- if (get_log_data(trans) <= 0)
- return 0;
+ if (get_log_data(trans) <= 0) {
+ len = 0;
+ goto unlock_mutex;
+ }
}
len = min(count, log->wpos - log->rpos);
@@ -5438,7 +5444,8 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret == len) {
pr_err("error copy sram register values to user\n");
- return -EFAULT;
+ len = -EFAULT;
+ goto unlock_mutex;
}
/* 'ret' is the number of bytes not copied */
@@ -5446,6 +5453,9 @@ static ssize_t fg_memif_dfs_reg_read(struct file *file, char __user *buf,
*ppos += len;
log->rpos += len;
+
+unlock_mutex:
+ mutex_unlock(&trans->memif_dfs_lock);
return len;
}
@@ -5466,14 +5476,20 @@ static ssize_t fg_memif_dfs_reg_write(struct file *file, const char __user *buf,
int cnt = 0;
u8 *values;
size_t ret = 0;
+ char *kbuf;
+ u32 offset;
struct fg_trans *trans = file->private_data;
- u32 offset = trans->offset;
+
+ mutex_lock(&trans->memif_dfs_lock);
+ offset = trans->offset;
/* Make a copy of the user data */
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (ret == count) {
@@ -5512,6 +5528,8 @@ static ssize_t fg_memif_dfs_reg_write(struct file *file, const char __user *buf,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&trans->memif_dfs_lock);
return ret;
}
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index aca73efdec6..5d04f48c12e 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -1447,11 +1447,13 @@ static void ngd_adsp_down(struct msm_slim_ctrl *dev)
struct slim_controller *ctrl = &dev->ctrl;
struct slim_device *sbdev;
+ mutex_lock(&dev->ssr_lock);
ngd_slim_enable(dev, false);
/* device up should be called again after SSR */
list_for_each_entry(sbdev, &ctrl->devs, dev_list)
slim_report_absent(sbdev);
SLIM_INFO(dev, "SLIM ADSP SSR (DOWN) done\n");
+ mutex_unlock(&dev->ssr_lock);
}
static void ngd_adsp_up(struct work_struct *work)
@@ -1460,7 +1462,9 @@ static void ngd_adsp_up(struct work_struct *work)
container_of(work, struct msm_slim_qmi, ssr_up);
struct msm_slim_ctrl *dev =
container_of(qmi, struct msm_slim_ctrl, qmi);
+ mutex_lock(&dev->ssr_lock);
ngd_slim_enable(dev, true);
+ mutex_unlock(&dev->ssr_lock);
}
static ssize_t show_mask(struct device *device, struct device_attribute *attr,
@@ -1624,6 +1628,7 @@ static int ngd_slim_probe(struct platform_device *pdev)
init_completion(&dev->reconf);
init_completion(&dev->ctrl_up);
mutex_init(&dev->tx_lock);
+ mutex_init(&dev->ssr_lock);
spin_lock_init(&dev->tx_buf_lock);
spin_lock_init(&dev->rx_lock);
dev->ee = 1;
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index dbb125dc9a6..0b4c4d33f79 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -284,6 +284,7 @@ struct msm_slim_ctrl {
struct clk *rclk;
struct clk *hclk;
struct mutex tx_lock;
+ struct mutex ssr_lock;
spinlock_t tx_buf_lock;
u8 pgdla;
enum msm_slim_msgq use_rx_msgqs;
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index 67c58d1e6d4..c54d9dda420 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -42,6 +42,12 @@ struct voice_svc_prvt {
struct list_head response_queue;
wait_queue_head_t response_wait;
spinlock_t response_lock;
+ /*
+ * This mutex ensures responses are processed in sequential order and
+ * that no two threads access and free the same response at the same
+ * time.
+ */
+ struct mutex response_mutex_lock;
};
struct apr_data {
@@ -448,6 +454,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
goto done;
}
+ mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
if (list_empty(&prtd->response_queue)) {
@@ -461,7 +468,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
pr_debug("%s: Read timeout\n", __func__);
ret = -ETIMEDOUT;
- goto done;
+ goto unlock;
} else if (ret > 0 && !list_empty(&prtd->response_queue)) {
pr_debug("%s: Interrupt recieved for response\n",
__func__);
@@ -469,7 +476,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
pr_debug("%s: Interrupted by SIGNAL %d\n",
__func__, ret);
- goto done;
+ goto unlock;
}
spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -488,7 +495,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
__func__, count, size);
ret = -ENOMEM;
- goto done;
+ goto unlock;
}
if (!access_ok(VERIFY_WRITE, arg, size)) {
@@ -496,7 +503,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
__func__);
ret = -EPERM;
- goto done;
+ goto unlock;
}
ret = copy_to_user(arg, &resp->resp,
@@ -506,7 +513,7 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
pr_err("%s: copy_to_user failed %d\n", __func__, ret);
ret = -EPERM;
- goto done;
+ goto unlock;
}
spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -520,6 +527,8 @@ static ssize_t voice_svc_read(struct file *file, char __user *arg,
ret = count;
+unlock:
+ mutex_unlock(&prtd->response_mutex_lock);
done:
return ret;
}
@@ -575,6 +584,7 @@ static int voice_svc_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&prtd->response_queue);
init_waitqueue_head(&prtd->response_wait);
spin_lock_init(&prtd->response_lock);
+ mutex_init(&prtd->response_mutex_lock);
file->private_data = (void *)prtd;
/* Current APR implementation doesn't support session based
@@ -625,6 +635,7 @@ static int voice_svc_release(struct inode *inode, struct file *file)
pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
}
+ mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
while (!list_empty(&prtd->response_queue)) {
@@ -638,6 +649,9 @@ static int voice_svc_release(struct inode *inode, struct file *file)
}
spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+ mutex_unlock(&prtd->response_mutex_lock);
+
+ mutex_destroy(&prtd->response_mutex_lock);
kfree(file->private_data);
file->private_data = NULL;
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 05da047c526..1ffda2eca13 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -46,9 +46,6 @@ static DEFINE_MUTEX(scm_lock);
#define SMC_ATOMIC_MASK 0x80000000
#define IS_CALL_AVAIL_CMD 1
-#define SCM_BUF_LEN(__cmd_size, __resp_size) \
- (sizeof(struct scm_command) + sizeof(struct scm_response) + \
- __cmd_size + __resp_size)
/**
* struct scm_command - one SCM command buffer
* @len: total available memory for command and response
@@ -120,6 +117,21 @@ struct scm_response {
#endif
+/* Calculate size for buffer given cmd_size and resp_size.
+ * Returns 0 in case the result would overflow size_t.
+ */
+static size_t scm_get_buf_len(size_t cmd_size, size_t resp_size)
+{
+ size_t contents = cmd_size + resp_size;
+ size_t structs = sizeof(struct scm_command) +
+ sizeof(struct scm_response);
+ size_t buf_len = contents + structs;
+
+ if (contents < cmd_size || buf_len < contents)
+ buf_len = 0;
+ return buf_len;
+}
+
/**
* scm_command_to_response() - Get a pointer to a scm_response
* @cmd: command
@@ -342,10 +354,9 @@ int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
void *scm_buf, size_t scm_buf_len)
{
int ret;
- size_t len = SCM_BUF_LEN(cmd_len, resp_len);
+ size_t len = scm_get_buf_len(cmd_len, resp_len);
- if (cmd_len > scm_buf_len || resp_len > scm_buf_len ||
- len > scm_buf_len)
+ if (len == 0 || len > scm_buf_len)
return -EINVAL;
if (!IS_ALIGNED((unsigned long)scm_buf, PAGE_SIZE))
@@ -739,9 +750,9 @@ int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
{
struct scm_command *cmd;
int ret;
- size_t len = SCM_BUF_LEN(cmd_len, resp_len);
+ size_t len = scm_get_buf_len(cmd_len, resp_len);
- if (cmd_len > len || resp_len > len)
+ if (len == 0 || PAGE_ALIGN(len) < len)
return -EINVAL;
cmd = kzalloc(PAGE_ALIGN(len), GFP_KERNEL);
diff --git a/drivers/spmi/spmi-dbgfs.c b/drivers/spmi/spmi-dbgfs.c
index b0a354b59a5..2e0b0a9d584 100644
--- a/drivers/spmi/spmi-dbgfs.c
+++ b/drivers/spmi/spmi-dbgfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -69,6 +69,7 @@ struct spmi_trans {
u32 addr; /* 20-bit address: SID + PID + Register offset */
u32 offset; /* Offset of last read data */
bool raw_data; /* Set to true for raw data dump */
+ struct mutex spmi_dfs_lock; /* Prevent thread concurrency */
struct spmi_controller *ctrl;
struct spmi_log_buffer *log; /* log buffer */
};
@@ -168,6 +169,7 @@ static int spmi_dfs_open(struct spmi_ctrl_data *ctrl_data, struct file *file)
trans->addr = ctrl_data->addr;
trans->ctrl = ctrl_data->ctrl;
trans->offset = trans->addr;
+ mutex_init(&trans->spmi_dfs_lock);
file->private_data = trans;
return 0;
@@ -197,6 +199,7 @@ static int spmi_dfs_close(struct inode *inode, struct file *file)
if (trans && trans->log) {
file->private_data = NULL;
+ mutex_destroy(&trans->spmi_dfs_lock);
kfree(trans->log);
kfree(trans);
}
@@ -473,14 +476,21 @@ static ssize_t spmi_dfs_reg_write(struct file *file, const char __user *buf,
int cnt = 0;
u8 *values;
size_t ret = 0;
-
+ u32 offset;
+ char *kbuf;
struct spmi_trans *trans = file->private_data;
- u32 offset = trans->offset;
+
+ mutex_lock(&trans->spmi_dfs_lock);
+
+ trans = file->private_data;
+ offset = trans->offset;
/* Make a copy of the user data */
- char *kbuf = kmalloc(count + 1, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
+ kbuf = kmalloc(count + 1, GFP_KERNEL);
+ if (!kbuf) {
+ ret = -ENOMEM;
+ goto unlock_mutex;
+ }
ret = copy_from_user(kbuf, buf, count);
if (ret == count) {
@@ -517,6 +527,8 @@ static ssize_t spmi_dfs_reg_write(struct file *file, const char __user *buf,
free_buf:
kfree(kbuf);
+unlock_mutex:
+ mutex_unlock(&trans->spmi_dfs_lock);
return ret;
}
@@ -537,10 +549,13 @@ static ssize_t spmi_dfs_reg_read(struct file *file, char __user *buf,
size_t ret;
size_t len;
+ mutex_lock(&trans->spmi_dfs_lock);
/* Is the the log buffer empty */
if (log->rpos >= log->wpos) {
- if (get_log_data(trans) <= 0)
- return 0;
+ if (get_log_data(trans) <= 0) {
+ len = 0;
+ goto unlock_mutex;
+ }
}
len = min(count, log->wpos - log->rpos);
@@ -548,7 +563,8 @@ static ssize_t spmi_dfs_reg_read(struct file *file, char __user *buf,
ret = copy_to_user(buf, &log->data[log->rpos], len);
if (ret == len) {
pr_err("error copy SPMI register values to user\n");
- return -EFAULT;
+ len = -EFAULT;
+ goto unlock_mutex;
}
/* 'ret' is the number of bytes not copied */
@@ -556,6 +572,9 @@ static ssize_t spmi_dfs_reg_read(struct file *file, char __user *buf,
*ppos += len;
log->rpos += len;
+
+unlock_mutex:
+ mutex_unlock(&trans->spmi_dfs_lock);
return len;
}
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 5fb366b4967..a5d264fb7f1 100755
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -113,6 +113,7 @@ struct ion_client {
*/
struct ion_handle {
struct kref ref;
+ unsigned int user_ref_count;
struct ion_client *client;
struct ion_buffer *buffer;
struct rb_node node;
@@ -434,6 +435,50 @@ int ion_handle_put(struct ion_handle *handle)
return ret;
}
+/* Must hold the client lock */
+static void user_ion_handle_get(struct ion_handle *handle)
+{
+ if (handle->user_ref_count++ == 0) {
+ kref_get(&handle->ref);
+ }
+}
+
+/* Must hold the client lock */
+static struct ion_handle* user_ion_handle_get_check_overflow(struct ion_handle *handle)
+{
+ if (handle->user_ref_count + 1 == 0)
+ return ERR_PTR(-EOVERFLOW);
+ user_ion_handle_get(handle);
+ return handle;
+}
+
+/* passes a kref to the user ref count.
+ * We know we're holding a kref to the object before and
+ * after this call, so no need to reverify handle. */
+static struct ion_handle* pass_to_user(struct ion_handle *handle)
+{
+ struct ion_client *client = handle->client;
+ struct ion_handle *ret;
+
+ mutex_lock(&client->lock);
+ ret = user_ion_handle_get_check_overflow(handle);
+ ion_handle_put_nolock(handle);
+ mutex_unlock(&client->lock);
+ return ret;
+}
+
+/* Must hold the client lock */
+static int user_ion_handle_put_nolock(struct ion_handle *handle)
+{
+ int ret;
+
+ if (--handle->user_ref_count == 0) {
+ ret = ion_handle_put_nolock(handle);
+ }
+
+ return ret;
+}
+
static struct ion_handle *ion_handle_lookup(struct ion_client *client,
struct ion_buffer *buffer)
{
@@ -645,6 +690,24 @@ static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle
ion_handle_put_nolock(handle);
}
+static void user_ion_free_nolock(struct ion_client *client, struct ion_handle *handle)
+{
+ bool valid_handle;
+
+ BUG_ON(client != handle->client);
+
+ valid_handle = ion_handle_validate(client, handle);
+ if (!valid_handle) {
+ WARN(1, "%s: invalid handle passed to free.\n", __func__);
+ return;
+ }
+ if (!handle->user_ref_count > 0) {
+ WARN(1, "%s: User does not have access!\n", __func__);
+ return;
+ }
+ user_ion_handle_put_nolock(handle);
+}
+
void ion_free(struct ion_client *client, struct ion_handle *handle)
{
BUG_ON(client != handle->client);
@@ -1509,7 +1572,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
data.allocation.flags, true);
if (IS_ERR(handle))
return PTR_ERR(handle);
-
+ pass_to_user(handle);
data.allocation.handle = handle->id;
cleanup_handle = handle;
@@ -1525,7 +1588,7 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mutex_unlock(&client->lock);
return PTR_ERR(handle);
}
- ion_free_nolock(client, handle);
+ user_ion_free_nolock(client, handle);
ion_handle_put_nolock(handle);
mutex_unlock(&client->lock);
break;
@@ -1549,10 +1612,15 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
struct ion_handle *handle;
handle = ion_import_dma_buf(client, data.fd.fd);
- if (IS_ERR(handle))
+ if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
- else
- data.handle.handle = handle->id;
+ } else {
+ handle = pass_to_user(handle);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ else
+ data.handle.handle = handle->id;
+ }
break;
}
case ION_IOC_SYNC:
@@ -1584,8 +1652,10 @@ static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (dir & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
if (cleanup_handle) {
- ion_free(client, cleanup_handle);
- ion_handle_put(cleanup_handle);
+ mutex_lock(&client->lock);
+ user_ion_free_nolock(client, cleanup_handle);
+ ion_handle_put_nolock(cleanup_handle);
+ mutex_unlock(&client->lock);
}
return -EFAULT;
}
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c
index 7d891936b87..81e9f53d9ca 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -8736,6 +8736,17 @@ static int __wlan_hdd_change_station(struct wiphy *wiphy,
}
StaParams.supported_channels_len = j;
}
+
+ if (params->supported_oper_classes_len >
+ SIR_MAC_MAX_SUPP_OPER_CLASSES) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "received oper classes: %d, resetting it to max"
+ "supported: %d", params->supported_oper_classes_len,
+ SIR_MAC_MAX_SUPP_OPER_CLASSES);
+ params->supported_oper_classes_len =
+ SIR_MAC_MAX_SUPP_OPER_CLASSES;
+ }
+
vos_mem_copy(StaParams.supported_oper_classes,
params->supported_oper_classes,
params->supported_oper_classes_len);
diff --git a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c
index 7ef1862b798..0d1723cdf5c 100644
--- a/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/drivers/staging/prima/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -4377,6 +4377,13 @@ static int __iw_set_ap_genie(struct net_device *dev,
return 0;
}
+ if (wrqu->data.length > DOT11F_IE_RSN_MAX_LEN) {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: WPARSN Ie input length is more than max[%d]", __func__,
+ wrqu->data.length);
+ return -EINVAL;
+ }
+
switch (genie[0])
{
case DOT11F_EID_WPA:
diff --git a/drivers/uio/msm_sharedmem/sharedmem_qmi.c b/drivers/uio/msm_sharedmem/sharedmem_qmi.c
index 3b04c582cb3..8bd99e1cab0 100644
--- a/drivers/uio/msm_sharedmem/sharedmem_qmi.c
+++ b/drivers/uio/msm_sharedmem/sharedmem_qmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -221,6 +221,7 @@ static int sharedmem_qmi_req_cb(struct qmi_handle *handle, void *conn_h,
#define DEBUG_BUF_SIZE (2048)
static char *debug_buffer;
static u32 debug_data_size;
+static struct mutex dbg_buf_lock; /* mutex for debug_buffer */
static ssize_t debug_read(struct file *file, char __user *buf,
size_t count, loff_t *file_pos)
@@ -276,21 +277,29 @@ static u32 fill_debug_info(char *buffer, u32 buffer_size)
static int debug_open(struct inode *inode, struct file *file)
{
u32 buffer_size;
- if (debug_buffer != NULL)
+ mutex_lock(&dbg_buf_lock);
+ if (debug_buffer != NULL) {
+ mutex_unlock(&dbg_buf_lock);
return -EBUSY;
+ }
buffer_size = DEBUG_BUF_SIZE;
debug_buffer = kzalloc(buffer_size, GFP_KERNEL);
- if (debug_buffer == NULL)
+ if (debug_buffer == NULL) {
+ mutex_unlock(&dbg_buf_lock);
return -ENOMEM;
+ }
debug_data_size = fill_debug_info(debug_buffer, buffer_size);
+ mutex_unlock(&dbg_buf_lock);
return 0;
}
static int debug_close(struct inode *inode, struct file *file)
{
+ mutex_lock(&dbg_buf_lock);
kfree(debug_buffer);
debug_buffer = NULL;
debug_data_size = 0;
+ mutex_unlock(&dbg_buf_lock);
return 0;
}
@@ -321,6 +330,7 @@ static void debugfs_init(void)
{
struct dentry *f_ent;
+ mutex_init(&dbg_buf_lock);
dir_ent = debugfs_create_dir("rmt_storage", NULL);
if (IS_ERR(dir_ent)) {
pr_err("Failed to create debug_fs directory\n");
@@ -349,6 +359,7 @@ static void debugfs_init(void)
static void debugfs_exit(void)
{
debugfs_remove_recursive(dir_ent);
+ mutex_destroy(&dbg_buf_lock);
}
static void sharedmem_qmi_svc_recv_msg(struct work_struct *work)
diff --git a/drivers/video/msm/mdss/mdss_debug.c b/drivers/video/msm/mdss/mdss_debug.c
index 4cc7a97cff5..049873ca32f 100644
--- a/drivers/video/msm/mdss/mdss_debug.c
+++ b/drivers/video/msm/mdss/mdss_debug.c
@@ -79,7 +79,7 @@ static ssize_t panel_debug_base_offset_write(struct file *file,
buf[count] = 0; /* end of string */
- if (sscanf(buf, "%x %d", &off, &cnt) != 2)
+ if (sscanf(buf, "%x %u", &off, &cnt) != 2)
return -EFAULT;
if (off > dbg->max_offset)
@@ -171,6 +171,8 @@ static ssize_t panel_debug_base_reg_write(struct file *file,
p[2] = 0;
pr_debug("p[%d] = %pK:%s\n", i, p, p);
cnt = sscanf(p, "%x", &tmp);
+ if (cnt != 1)
+ return -EFAULT;
reg[i] = tmp;
pr_debug("reg[%d] = %x\n", i, (int)reg[i]);
}
@@ -693,11 +695,11 @@ static ssize_t mdss_debug_factor_write(struct file *file,
if (strnchr(buf, count, '/')) {
/* Parsing buf as fraction */
- if (sscanf(buf, "%d/%d", &numer, &denom) != 2)
+ if (sscanf(buf, "%u/%u", &numer, &denom) != 2)
return -EFAULT;
} else {
/* Parsing buf as percentage */
- if (sscanf(buf, "%d", &numer) != 1)
+ if (kstrtouint(buf, 0, &numer))
return -EFAULT;
denom = 100;
}
@@ -1004,7 +1006,7 @@ static ssize_t mdss_debug_perf_bw_limit_write(struct file *file,
if (strnchr(buf, count, ' ')) {
/* Parsing buf */
- if (sscanf(buf, "%d %d", &mode, &val) != 2)
+ if (sscanf(buf, "%u %u", &mode, &val) != 2)
return -EFAULT;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 63cc27ab6ad..1fcbd290380 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -651,6 +651,7 @@ struct buf_data {
char *string_buf; /* cmd buf as string, 3 bytes per number */
int sblen; /* string buffer length */
int sync_flag;
+ struct mutex dbg_mutex; /* mutex to synchronize read/write/flush */
};
struct mdss_dsi_debugfs_info {
@@ -738,6 +739,7 @@ static ssize_t mdss_dsi_cmd_read(struct file *file, char __user *buf,
char *bp;
ssize_t ret = 0;
+ mutex_lock(&pcmds->dbg_mutex);
if (*ppos == 0) {
kfree(pcmds->string_buf);
pcmds->string_buf = NULL;
@@ -756,6 +758,7 @@ static ssize_t mdss_dsi_cmd_read(struct file *file, char __user *buf,
buffer = kmalloc(bsize, GFP_KERNEL);
if (!buffer) {
pr_err("%s: Failed to allocate memory\n", __func__);
+ mutex_unlock(&pcmds->dbg_mutex);
return -ENOMEM;
}
@@ -791,10 +794,12 @@ static ssize_t mdss_dsi_cmd_read(struct file *file, char __user *buf,
kfree(pcmds->string_buf);
pcmds->string_buf = NULL;
pcmds->sblen = 0;
+ mutex_unlock(&pcmds->dbg_mutex);
return 0; /* the end */
}
ret = simple_read_from_buffer(buf, count, ppos, pcmds->string_buf,
pcmds->sblen);
+ mutex_unlock(&pcmds->dbg_mutex);
return ret;
}
@@ -806,6 +811,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
int blen = 0;
char *string_buf;
+ mutex_lock(&pcmds->dbg_mutex);
if (*ppos == 0) {
kfree(pcmds->string_buf);
pcmds->string_buf = NULL;
@@ -817,6 +823,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
string_buf = krealloc(pcmds->string_buf, blen + 1, GFP_KERNEL);
if (!string_buf) {
pr_err("%s: Failed to allocate memory\n", __func__);
+ mutex_unlock(&pcmds->dbg_mutex);
return -ENOMEM;
}
@@ -826,6 +833,7 @@ static ssize_t mdss_dsi_cmd_write(struct file *file, const char __user *p,
string_buf[blen] = '\0';
pcmds->string_buf = string_buf;
pcmds->sblen = blen;
+ mutex_unlock(&pcmds->dbg_mutex);
return ret;
}
@@ -836,8 +844,12 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id)
char *buf, *bufp, *bp;
struct dsi_ctrl_hdr *dchdr;
- if (!pcmds->string_buf)
+ mutex_lock(&pcmds->dbg_mutex);
+
+ if (!pcmds->string_buf) {
+ mutex_unlock(&pcmds->dbg_mutex);
return 0;
+ }
/*
* Allocate memory for command buffer
@@ -850,6 +862,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id)
kfree(pcmds->string_buf);
pcmds->string_buf = NULL;
pcmds->sblen = 0;
+ mutex_unlock(&pcmds->dbg_mutex);
return -ENOMEM;
}
@@ -874,6 +887,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id)
pr_err("%s: dtsi cmd=%x error, len=%d\n",
__func__, dchdr->dtype, dchdr->dlen);
kfree(buf);
+ mutex_unlock(&pcmds->dbg_mutex);
return -EINVAL;
}
bp += sizeof(*dchdr);
@@ -885,6 +899,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id)
pr_err("%s: dcs_cmd=%x len=%d error!\n", __func__,
bp[0], len);
kfree(buf);
+ mutex_unlock(&pcmds->dbg_mutex);
return -EINVAL;
}
@@ -897,6 +912,7 @@ static int mdss_dsi_cmd_flush(struct file *file, fl_owner_t id)
pcmds->buf = buf;
pcmds->blen = blen;
}
+ mutex_unlock(&pcmds->dbg_mutex);
return 0;
}
@@ -911,6 +927,7 @@ struct dentry *dsi_debugfs_create_dcs_cmd(const char *name, umode_t mode,
struct dentry *parent, struct buf_data *cmd,
struct dsi_panel_cmds ctrl_cmds)
{
+ mutex_init(&cmd->dbg_mutex);
cmd->buf = ctrl_cmds.buf;
cmd->blen = ctrl_cmds.blen;
cmd->string_buf = NULL;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index bc593eed7e6..81f217fcce3 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -2,7 +2,7 @@
* Core MDSS framebuffer driver.
*
* Copyright (C) 2007 Google Incorporated
- * Copyright (c) 2008-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -623,8 +623,8 @@ static ssize_t mdss_fb_force_panel_dead(struct device *dev,
return len;
}
- if (sscanf(buf, "%d", &pdata->panel_info.panel_force_dead) != 1)
- pr_err("sccanf buf error!\n");
+ if (kstrtouint(buf, 0, &pdata->panel_info.panel_force_dead))
+ pr_err("kstrtouint buf error\n");
return len;
}
@@ -737,8 +737,8 @@ static ssize_t mdss_fb_change_dfps_mode(struct device *dev,
}
pinfo = &pdata->panel_info;
- if (sscanf(buf, "%d", &dfps_mode) != 1) {
- pr_err("sccanf buf error!\n");
+ if (kstrtouint(buf, 0, &dfps_mode)) {
+ pr_err("kstrtouint buf error\n");
return len;
}
@@ -3511,8 +3511,6 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
goto buf_sync_err_2;
}
- sync_fence_install(rel_fence, rel_fen_fd);
-
ret = copy_to_user(buf_sync->rel_fen_fd, &rel_fen_fd, sizeof(int));
if (ret) {
pr_err("%s: copy_to_user failed\n", sync_pt_data->fence_name);
@@ -3549,8 +3547,6 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
goto buf_sync_err_3;
}
- sync_fence_install(retire_fence, retire_fen_fd);
-
ret = copy_to_user(buf_sync->retire_fen_fd, &retire_fen_fd,
sizeof(int));
if (ret) {
@@ -3561,7 +3557,11 @@ static int mdss_fb_handle_buf_sync_ioctl(struct msm_sync_pt_data *sync_pt_data,
goto buf_sync_err_3;
}
+ sync_fence_install(retire_fence, retire_fen_fd);
+
skip_retire_fence:
+ sync_fence_install(rel_fence, rel_fen_fd);
+
mutex_unlock(&sync_pt_data->sync_mutex);
if (buf_sync->flags & MDP_BUF_SYNC_FLAG_WAIT)
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
index 5d8deddd8da..3cf0f5f4ea9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.c
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -1673,7 +1673,7 @@ static ssize_t mdss_mdp_store_max_limit_bw(struct device *dev,
struct mdss_data_type *mdata = dev_get_drvdata(dev);
u32 data = 0;
- if (1 != sscanf(buf, "%d", &data)) {
+ if (kstrtouint(buf, 0, &data)) {
pr_info("Not able scan to bw_mode_bitmap\n");
} else {
mdata->bw_mode_bitmap = data;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index d81bf44515e..ee9bfdd605c 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -3677,6 +3677,11 @@ static int mdss_mdp_hw_cursor_update(struct msm_fb_data_type *mfd,
if (cursor->set & FB_CUR_SETIMAGE) {
u32 cursor_addr;
+ if (img->width * img->height * 4 > cursor_frame_size) {
+ pr_err("cursor image size is too large\n");
+ ret = -EINVAL;
+ goto done;
+ }
ret = copy_from_user(mfd->cursor_buf, img->data,
cursor_frame_size);
if (ret) {