[Dorado][PATCH] Qualcomm Post-CS10 0.0.040.1
Update Dorado Kernel to Qualcomm release Post-CS10 0.0.040.1
Linux kernel - Ver 3.18
Android Wear EPDK MR1 - Ver 3620091
Android security patch level - PLATFORM_SECURITY_PATCH = 2017-02-05
Commit history:
3916e83 staging/android/ion : fix a race condition in the ion driver
238b51b radio-iris: check argument values before copying the data
7be8159 qseecom: whitelist support for kernel client and listener
7cd76402 qseecom: remove entry from qseecom_registered_app_list
711d6ca qcom: scm: remove printing input arguments
3d768a8 net: ipc_router: Register services only on client port
bf276e7 msm: sensor: Adding mutex for actuator power down operations
be24ec0 msm: mdss: fix crash after partial update enable
166b4d6 msm: crypto: set CLR_CNTXT bit for crypto operations
90e941a drivers: soc: add size checks and update log messages
bccd9ed drivers: qcom: ultrasound: Lock async driver calls
20b4ee8 binder: blacklist %p kptr_restrict
af0e5f0 KEYS: Fix race between key destruction and finding a keyring by
128bfd2 perf: protect group_leader from races that cause ctx double-free
92cd830 Input: synaptics: check input, prevent sysfs races
fd7adb7 qcrypto: protect potential integer overflow.
7e87f1c perf: Fix event->ctx locking
918f18d percpu: fix synchronization between synchronous map extension an
deb7294 percpu: fix synchronization between chunk->map_extend_work and c
f1170b1 net: ping: Fix stack buffer overflow in ping_common_sendmsg()
da4d964 msm: sensor: validate the i2c table index before use
a4e95f1 msm: mdss: restore ROI update after idle power collapse
b3de23c msm: ipa: fix the potential heap overflow on wan-driver
00545d8 msm: cpp: Fix for buffer overflow in cpp.
35a6da3 msm: camera: cpp: Add validation for v4l2 ioctl arguments
daa4942c md: dm-req-crypt: fixed error propagation when ICE is used
94ffb76 input: synaptics_dsx: add checks of user input data
9b6d94d input: synaptics: Add checks of user input data
454e541 ecryptfs: don't allow mmap when the lower fs doesn't support it
5dd3054 cgroup: prefer %pK to %p
c90bcc9 arm64: make sys_call_table const
360fbaf UPSTREAM: mm: remove gup_flags FOLL_WRITE games from __get_user_
fba554b Revert "ecryptfs: forbid opening files without mmap handler"
a25a288 arm: fix handling of F_OFD_... in oabi_fcntl64()
314ecef ASoC: msm: lock read/write when add/free audio ion memory
e51b7b3 ARM: dts: msm: Remove oxili_gx gdsc node for 8909w
[Customer Impact]
- None
[Side effect of the change]
- None
diff --git a/arch/arm/boot/dts/qcom/msm8909w-1gb-wtp.dts b/arch/arm/boot/dts/qcom/msm8909w-1gb-wtp.dts
index 2564c1b..754ceca 100644
--- a/arch/arm/boot/dts/qcom/msm8909w-1gb-wtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8909w-1gb-wtp.dts
@@ -88,11 +88,3 @@
pinctrl-names = "default";
pinctrl-0 = <&uart_console_sleep>;
};
-
-&gdsc_oxili_gx {
- clock-names = "core_root_clk";
- clocks =<&clock_gcc clk_gfx3d_clk_src>;
- qcom,enable-root-clk;
- qcom,clk-dis-wait-val = <0x5>;
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/qcom/msm8909w-wtp.dts b/arch/arm/boot/dts/qcom/msm8909w-wtp.dts
index 2dee4686..f1c41b0 100644
--- a/arch/arm/boot/dts/qcom/msm8909w-wtp.dts
+++ b/arch/arm/boot/dts/qcom/msm8909w-wtp.dts
@@ -88,11 +88,3 @@
pinctrl-names = "default";
pinctrl-0 = <&uart_console_sleep>;
};
-
-&gdsc_oxili_gx {
- clock-names = "core_root_clk";
- clocks =<&clock_gcc clk_gfx3d_clk_src>;
- qcom,enable-root-clk;
- qcom,clk-dis-wait-val = <0x5>;
- status = "okay";
-};
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index e90a314..eb821e7 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -193,15 +193,44 @@
pid_t l_pid;
} __attribute__ ((packed,aligned(4)));
+static long do_locks(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
+ struct flock64 kernel;
+ struct oabi_flock64 user;
+ mm_segment_t fs;
+ long ret;
+
+ if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
+ sizeof(user)))
+ return -EFAULT;
+ kernel.l_type = user.l_type;
+ kernel.l_whence = user.l_whence;
+ kernel.l_start = user.l_start;
+ kernel.l_len = user.l_len;
+ kernel.l_pid = user.l_pid;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel);
+ set_fs(fs);
+
+ if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) {
+ user.l_type = kernel.l_type;
+ user.l_whence = kernel.l_whence;
+ user.l_start = kernel.l_start;
+ user.l_len = kernel.l_len;
+ user.l_pid = kernel.l_pid;
+ if (copy_to_user((struct oabi_flock64 __user *)arg,
+ &user, sizeof(user)))
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
unsigned long arg)
{
- struct oabi_flock64 user;
- struct flock64 kernel;
- mm_segment_t fs = USER_DS; /* initialized to kill a warning */
- unsigned long local_arg = arg;
- int ret;
-
switch (cmd) {
case F_OFD_GETLK:
case F_OFD_SETLK:
@@ -209,39 +238,11 @@
case F_GETLK64:
case F_SETLK64:
case F_SETLKW64:
- if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
- sizeof(user)))
- return -EFAULT;
- kernel.l_type = user.l_type;
- kernel.l_whence = user.l_whence;
- kernel.l_start = user.l_start;
- kernel.l_len = user.l_len;
- kernel.l_pid = user.l_pid;
- local_arg = (unsigned long)&kernel;
- fs = get_fs();
- set_fs(KERNEL_DS);
+ return do_locks(fd, cmd, arg);
+
+ default:
+ return sys_fcntl64(fd, cmd, arg);
}
-
- ret = sys_fcntl64(fd, cmd, local_arg);
-
- switch (cmd) {
- case F_GETLK64:
- if (!ret) {
- user.l_type = kernel.l_type;
- user.l_whence = kernel.l_whence;
- user.l_start = kernel.l_start;
- user.l_len = kernel.l_len;
- user.l_pid = kernel.l_pid;
- if (copy_to_user((struct oabi_flock64 __user *)arg,
- &user, sizeof(user)))
- ret = -EFAULT;
- }
- case F_SETLK64:
- case F_SETLKW64:
- set_fs(fs);
- }
-
- return ret;
}
struct oabi_epoll_event {
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index 3fa98ff..df20b79 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -50,7 +50,7 @@
* The sys_call_table array must be 4K aligned to be accessible from
* kernel/entry.S.
*/
-void *sys_call_table[__NR_syscalls] __aligned(4096) = {
+void * const sys_call_table[__NR_syscalls] __aligned(4096) = {
[0 ... __NR_syscalls - 1] = sys_ni_syscall,
#include <asm/unistd.h>
};
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 36949f4..92dc9f6 100644
--- a/drivers/crypto/msm/qce50.c
+++ b/drivers/crypto/msm/qce50.c
@@ -1337,7 +1337,8 @@
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)),
@@ -1518,7 +1519,8 @@
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)
@@ -1837,7 +1839,8 @@
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)),
@@ -1925,7 +1928,8 @@
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)
@@ -2002,7 +2006,8 @@
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)
@@ -3262,8 +3267,8 @@
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;
@@ -3376,8 +3381,8 @@
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;
@@ -3420,8 +3425,8 @@
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;
@@ -3598,8 +3603,8 @@
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;
@@ -3815,8 +3820,8 @@
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;
@@ -3948,8 +3953,8 @@
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;
@@ -4034,8 +4039,8 @@
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;
@@ -4116,8 +4121,8 @@
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;
@@ -4876,6 +4881,12 @@
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/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index cbdfb37..c340fe1 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2130,12 +2130,6 @@
return ret;
}
- ret = check_vma_flags(vma, entry->memdesc.flags);
- if (ret) {
- up_read(¤t->mm->mmap_sem);
- return ret;
- }
-
/*
* Check to see that this isn't our own memory that we have
* already mapped
diff --git a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
index 2282fe0..0ec16e6 100644
--- a/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_dsx/synaptics_dsx_fw_update.c
@@ -358,6 +358,7 @@
static struct synaptics_rmi4_fwu_handle *fwu;
DECLARE_COMPLETION(fwu_dsx_remove_complete);
+DEFINE_MUTEX(dsx_fwu_sysfs_mutex);
static unsigned int extract_uint_le(const unsigned char *ptr)
{
@@ -1589,39 +1590,72 @@
char *buf, loff_t pos, size_t count)
{
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
if (count < fwu->config_size) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Not enough space (%zu bytes) in buffer\n",
__func__, count);
- return -EINVAL;
+ retval = -EINVAL;
+ goto show_image_exit;
}
memcpy(buf, fwu->read_config_buf, fwu->config_size);
-
- return fwu->config_size;
+ retval = fwu->config_size;
+show_image_exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_store_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
+ if (count > (fwu->image_size - fwu->data_pos)) {
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "%s: Not enough space in buffer\n",
+ __func__);
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ if (!fwu->ext_data_source) {
+ dev_err(fwu->rmi4_data->pdev->dev.parent,
+ "%s: Need to set imagesize\n",
+ __func__);
+ retval = -EINVAL;
+ goto exit;
+ }
+
memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
(const void *)buf,
count);
fwu->data_pos += count;
+exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return count;
}
static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- int retval;
+ ssize_t retval;
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1650,6 +1684,9 @@
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1660,6 +1697,9 @@
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1693,6 +1733,9 @@
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = DO_LOCKDOWN;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1703,6 +1746,9 @@
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1726,6 +1772,9 @@
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->data_pos = 0;
+ fwu->image_size = 0;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return retval;
}
@@ -1742,7 +1791,11 @@
if (input != 1)
return -EINVAL;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
retval = fwu_do_read_config();
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+
if (retval < 0) {
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to read config\n",
@@ -1763,7 +1816,10 @@
if (retval)
return retval;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
fwu->config_area = config_area;
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
return count;
}
@@ -1771,17 +1827,30 @@
static ssize_t fwu_sysfs_image_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
if (strnlen(fwu->rmi4_data->fw_name, SYNA_FW_NAME_MAX_LEN) > 0)
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ retval = snprintf(buf, PAGE_SIZE, "%s\n",
fwu->rmi4_data->fw_name);
else
- return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_image_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- if (sscanf(buf, "%s", fwu->image_name) != 1)
+ ssize_t retval;
+
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+ retval = sscanf(buf, "%49s", fwu->image_name);
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+
+ if (retval != 1)
return -EINVAL;
return count;
@@ -1794,9 +1863,12 @@
unsigned long size;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&dsx_fwu_sysfs_mutex))
+ return -EBUSY;
+
retval = sstrtoul(buf, 10, &size);
if (retval)
- return retval;
+ goto exit;
fwu->image_size = size;
fwu->data_pos = 0;
@@ -1807,10 +1879,14 @@
dev_err(rmi4_data->pdev->dev.parent,
"%s: Failed to alloc mem for image data\n",
__func__);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto exit;
}
- return count;
+ retval = count;
+exit:
+ mutex_unlock(&dsx_fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_block_size_show(struct device *dev,
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index f4abf16..7d0dd38 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/firmware.h>
@@ -296,6 +297,7 @@
static struct synaptics_rmi4_fwu_handle *fwu;
DECLARE_COMPLETION(fwu_remove_complete);
+DEFINE_MUTEX(fwu_sysfs_mutex);
static unsigned int extract_uint(const unsigned char *ptr)
{
@@ -1680,31 +1682,59 @@
char *buf, loff_t pos, size_t count)
{
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ ssize_t retval;
+
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
if (count < fwu->config_size) {
dev_err(&rmi4_data->i2c_client->dev,
"%s: Not enough space (%zu bytes) in buffer\n",
__func__, count);
- return -EINVAL;
+ retval = -EINVAL;
+ goto show_image_exit;
}
memcpy(buf, fwu->read_config_buf, fwu->config_size);
-
- return fwu->config_size;
+ retval = fwu->config_size;
+show_image_exit:
+ mutex_unlock(&fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_store_image(struct file *data_file,
struct kobject *kobj, struct bin_attribute *attributes,
char *buf, loff_t pos, size_t count)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+ if (!fwu->ext_data_source) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "Cannot use this without setting imagesize!\n");
+ retval = -EAGAIN;
+ goto exit;
+ }
+ if (count > fwu->image_size - fwu->data_pos) {
+ dev_err(&fwu->rmi4_data->i2c_client->dev,
+ "%s: Not enough space in buffer\n",
+ __func__);
+
+ retval = -EINVAL;
+ goto exit;
+ }
+
memcpy((void *)(&fwu->ext_data_source[fwu->data_pos]),
(const void *)buf,
count);
fwu->data_buffer = fwu->ext_data_source;
fwu->data_pos += count;
-
- return count;
+ retval = count;
+exit:
+ mutex_unlock(&fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_image_name_store(struct device *dev,
@@ -1727,18 +1757,29 @@
return -EINVAL;
}
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
strlcpy(rmi4_data->fw_image_name, buf, count);
+ mutex_unlock(&fwu_sysfs_mutex);
+
return count;
}
static ssize_t fwu_sysfs_image_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ ssize_t retval;
+
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+
if (strnlen(fwu->rmi4_data->fw_image_name, NAME_BUFFER_SIZE) > 0)
- return snprintf(buf, PAGE_SIZE, "%s\n",
+ retval = snprintf(buf, PAGE_SIZE, "%s\n",
fwu->rmi4_data->fw_image_name);
else
- return snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ retval = snprintf(buf, PAGE_SIZE, "No firmware name given\n");
+ mutex_unlock(&fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_force_reflash_store(struct device *dev,
@@ -1748,6 +1789,9 @@
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+
retval = kstrtouint(buf, 10, &input);
if (retval)
goto exit;
@@ -1774,7 +1818,10 @@
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
+ fwu->image_size = 0;
+ fwu->data_pos = 0;
fwu->do_lockdown = rmi4_data->board->do_lockdown;
+ mutex_unlock(&fwu_sysfs_mutex);
return retval;
}
@@ -1785,6 +1832,9 @@
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+
retval = kstrtouint(buf, 10, &input);
if (retval)
goto exit;
@@ -1815,8 +1865,11 @@
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->image_size = 0;
+ fwu->data_pos = 0;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = rmi4_data->board->do_lockdown;
+ mutex_unlock(&fwu_sysfs_mutex);
return retval;
}
@@ -1827,6 +1880,9 @@
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+
if (sscanf(buf, "%u", &input) != 1) {
retval = -EINVAL;
goto exit;
@@ -1852,6 +1908,9 @@
fwu->ext_data_source = NULL;
fwu->force_update = FORCE_UPDATE;
fwu->do_lockdown = rmi4_data->board->do_lockdown;
+ fwu->image_size = 0;
+ fwu->data_pos = 0;
+ mutex_unlock(&fwu_sysfs_mutex);
return retval;
}
@@ -1862,6 +1921,9 @@
unsigned int input;
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data;
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+
retval = kstrtouint(buf, 10, &input);
if (retval)
goto exit;
@@ -1884,6 +1946,9 @@
exit:
kfree(fwu->ext_data_source);
fwu->ext_data_source = NULL;
+ fwu->image_size = 0;
+ fwu->data_pos = 0;
+ mutex_unlock(&fwu_sysfs_mutex);
return retval;
}
@@ -1901,7 +1966,11 @@
if (input != 1)
return -EINVAL;
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
retval = fwu_do_read_config();
+ mutex_unlock(&fwu_sysfs_mutex);
+
if (retval < 0) {
dev_err(&rmi4_data->i2c_client->dev,
"%s: Failed to read config\n",
@@ -1930,7 +1999,10 @@
return -EINVAL;
}
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
fwu->config_area = config_area;
+ mutex_unlock(&fwu_sysfs_mutex);
return count;
}
@@ -1945,15 +2017,23 @@
if (retval)
return retval;
+ if (!mutex_trylock(&fwu_sysfs_mutex))
+ return -EBUSY;
+
fwu->image_size = size;
fwu->data_pos = 0;
kfree(fwu->ext_data_source);
fwu->ext_data_source = kzalloc(fwu->image_size, GFP_KERNEL);
- if (!fwu->ext_data_source)
- return -ENOMEM;
+ if (!fwu->ext_data_source) {
+ retval = -ENOMEM;
+ goto exit;
+ }
- return count;
+ retval = count;
+exit:
+ mutex_unlock(&fwu_sysfs_mutex);
+ return retval;
}
static ssize_t fwu_sysfs_block_size_show(struct device *dev,
@@ -2117,7 +2197,9 @@
static void synaptics_rmi4_fwu_work(struct work_struct *work)
{
+ mutex_lock(&fwu_sysfs_mutex);
fwu_start_reflash();
+ mutex_unlock(&fwu_sysfs_mutex);
}
static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data)
diff --git a/drivers/md/dm-req-crypt.c b/drivers/md/dm-req-crypt.c
index 3257f1b..05b3c31 100644
--- a/drivers/md/dm-req-crypt.c
+++ b/drivers/md/dm-req-crypt.c
@@ -873,6 +873,7 @@
/* If it is for ICE, free up req_io and return */
if (encryption_mode == DM_REQ_CRYPT_ENCRYPTION_MODE_TRANSPARENT) {
mempool_free(req_io, req_io_pool);
+ err = error;
goto submit_request;
}
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 1dceed3..096a1ce 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -2931,14 +2931,14 @@
break;
default: {
if (ioctl_ptr == NULL) {
- pr_err("Wrong ioctl_ptr %p\n", ioctl_ptr);
+ pr_err("Wrong ioctl_ptr for cmd %u\n", cmd);
return -EINVAL;
}
*ioctl_ptr = arg;
if ((*ioctl_ptr == NULL) ||
- ((*ioctl_ptr)->ioctl_ptr == NULL)) {
- pr_err("Wrong arg %p\n", arg);
+ (*ioctl_ptr)->ioctl_ptr == NULL) {
+ pr_err("Error invalid ioctl argument cmd %u", cmd);
return -EINVAL;
}
break;
@@ -2963,6 +2963,12 @@
pr_err("cpp_dev is null\n");
return -EINVAL;
}
+
+ if (_IOC_DIR(cmd) == _IOC_NONE) {
+ pr_err("Invalid ioctl/subdev cmd %u", cmd);
+ return -EINVAL;
+ }
+
rc = msm_cpp_validate_input(cmd, arg, &ioctl_ptr);
if (rc != 0) {
pr_err("input validation failed\n");
@@ -3198,8 +3204,7 @@
uint32_t identity;
struct msm_cpp_buff_queue_info_t *buff_queue_info;
CPP_DBG("VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO\n");
- if ((ioctl_ptr->len == 0) ||
- (ioctl_ptr->len > sizeof(uint32_t))) {
+ if (ioctl_ptr->len != sizeof(uint32_t)) {
mutex_unlock(&cpp_dev->mutex);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
index b87e31e..a9ab187 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c
@@ -101,11 +101,6 @@
i2c_tbl = a_ctrl->i2c_reg_tbl;
for (i = 0; i < size; i++) {
- /* check that the index into i2c_tbl cannot grow larger that
- the allocated size of i2c_tbl */
- if ((a_ctrl->total_steps + 1) < (a_ctrl->i2c_tbl_index))
- break;
-
if (write_arr[i].reg_write_type == MSM_ACTUATOR_WRITE_DAC) {
value = (next_lens_position <<
write_arr[i].data_shift) |
@@ -119,6 +114,11 @@
i2c_byte2 = value & 0xFF;
CDBG("byte1:0x%x, byte2:0x%x\n",
i2c_byte1, i2c_byte2);
+ if (a_ctrl->i2c_tbl_index >
+ a_ctrl->total_steps) {
+ pr_err("failed:i2c table index out of bound\n");
+ break;
+ }
i2c_tbl[a_ctrl->i2c_tbl_index].
reg_addr = i2c_byte1;
i2c_tbl[a_ctrl->i2c_tbl_index].
@@ -139,6 +139,10 @@
i2c_byte2 = (hw_dword & write_arr[i].hw_mask) >>
write_arr[i].hw_shift;
}
+ if (a_ctrl->i2c_tbl_index > a_ctrl->total_steps) {
+ pr_err("failed: i2c table index out of bound\n");
+ break;
+ }
CDBG("i2c_byte1:0x%x, i2c_byte2:0x%x\n", i2c_byte1, i2c_byte2);
i2c_tbl[a_ctrl->i2c_tbl_index].reg_addr = i2c_byte1;
i2c_tbl[a_ctrl->i2c_tbl_index].reg_data = i2c_byte2;
@@ -1517,11 +1521,13 @@
pr_err("a_ctrl->i2c_client.i2c_func_tbl NULL\n");
return -EINVAL;
}
+ mutex_lock(a_ctrl->actuator_mutex);
rc = msm_actuator_power_down(a_ctrl);
if (rc < 0) {
pr_err("%s:%d Actuator Power down failed\n",
__func__, __LINE__);
}
+ mutex_unlock(a_ctrl->actuator_mutex);
return msm_actuator_close(sd, NULL);
default:
return -ENOIOCTLCMD;
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 4515859..c5f865d 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -3858,8 +3858,20 @@
bytes_to_copy = (ctrl->controls[0]).size;
spur_tbl_req.mode = data[0];
spur_tbl_req.no_of_freqs_entries = data[1];
- spur_data = kmalloc((data[1] * SPUR_DATA_LEN) + 2,
- GFP_ATOMIC);
+
+ if (((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) !=
+ bytes_to_copy - 2) ||
+ ((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN) >
+ 2 * FM_SPUR_TBL_SIZE)) {
+ FMDERR("Invalid data len: data[1] = %d, bytes = %zu",
+ spur_tbl_req.no_of_freqs_entries,
+ bytes_to_copy);
+ retval = -EINVAL;
+ goto END;
+ }
+ spur_data =
+ kmalloc((spur_tbl_req.no_of_freqs_entries * SPUR_DATA_LEN)
+ + 2, GFP_ATOMIC);
if (!spur_data) {
FMDERR("Allocation failed for Spur data");
retval = -EFAULT;
@@ -3874,7 +3886,8 @@
if (spur_tbl_req.no_of_freqs_entries <= ENTRIES_EACH_CMD) {
memcpy(&spur_tbl_req.spur_data[0], spur_data,
- (data[1] * SPUR_DATA_LEN));
+ (spur_tbl_req.no_of_freqs_entries *
+ SPUR_DATA_LEN));
retval = radio_hci_request(radio->fm_hdev,
hci_fm_set_spur_tbl_req,
(unsigned long)&spur_tbl_req,
diff --git a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
index 5abb8a4..23c30ff 100644
--- a/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
+++ b/drivers/misc/qcom/qdsp6v2/audio_utils_aio.c
@@ -570,6 +570,8 @@
struct q6audio_aio *audio = file->private_data;
pr_debug("%s[%p]\n", __func__, audio);
mutex_lock(&audio->lock);
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
audio->wflush = 1;
if (audio->wakelock_voted &&
(audio->audio_ws_mgr != NULL) &&
@@ -595,6 +597,8 @@
wake_up(&audio->event_wait);
audio_aio_reset_event_queue(audio);
q6asm_audio_client_free(audio->ac);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
mutex_unlock(&audio->lock);
mutex_destroy(&audio->lock);
mutex_destroy(&audio->read_lock);
@@ -1738,7 +1742,11 @@
__func__);
rc = -EFAULT;
} else {
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
rc = audio_aio_ion_add(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
}
mutex_unlock(&audio->lock);
break;
@@ -1753,7 +1761,11 @@
__func__);
rc = -EFAULT;
} else {
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
rc = audio_aio_ion_remove(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
}
mutex_unlock(&audio->lock);
break;
@@ -2057,7 +2069,11 @@
} else {
info.fd = info_32.fd;
info.vaddr = compat_ptr(info_32.vaddr);
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
rc = audio_aio_ion_add(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
}
mutex_unlock(&audio->lock);
break;
@@ -2074,7 +2090,11 @@
} else {
info.fd = info_32.fd;
info.vaddr = compat_ptr(info_32.vaddr);
+ mutex_lock(&audio->read_lock);
+ mutex_lock(&audio->write_lock);
rc = audio_aio_ion_remove(audio, &info);
+ mutex_unlock(&audio->write_lock);
+ mutex_unlock(&audio->read_lock);
}
mutex_unlock(&audio->lock);
break;
diff --git a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
index e0323ec..568fba8 100644
--- a/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
+++ b/drivers/misc/qcom/qdsp6v2/ultrasound/usf.c
@@ -23,6 +23,7 @@
#include <linux/time.h>
#include <linux/kmemleak.h>
#include <linux/wakelock.h>
+#include <linux/mutex.h>
#include <sound/apr_audio.h>
#include <linux/qdsp6v2/usf.h>
#include "q6usm.h"
@@ -132,6 +133,8 @@
uint16_t conflicting_event_filters;
/* The requested buttons bitmap */
uint16_t req_buttons_bitmap;
+ /* Mutex for exclusive operations (all public APIs) */
+ struct mutex mutex;
};
struct usf_input_dev_type {
@@ -1387,9 +1390,22 @@
int dir)
{
struct us_client *usc = usf_xx->usc;
- struct us_port_data *port = &usc->port[dir];
+ struct us_port_data *port;
int rc = 0;
+ if (usc == NULL) {
+ pr_err("%s: usc is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ port = &usc->port[dir];
+ if (port == NULL) {
+ pr_err("%s: port is null\n",
+ __func__);
+ return -EFAULT;
+ }
+
if (port->param_buf == NULL) {
pr_err("%s: parameter buffer is null\n",
__func__);
@@ -1514,10 +1530,12 @@
return __usf_get_stream_param(usf_xx, &get_stream_param, dir);
} /* usf_get_stream_param */
-static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long __usf_ioctl(struct usf_type *usf,
+ unsigned int cmd,
+ unsigned long arg)
{
+
int rc = 0;
- struct usf_type *usf = file->private_data;
struct usf_xx_type *usf_xx = NULL;
switch (cmd) {
@@ -1680,6 +1698,18 @@
release_xx(usf_xx);
return rc;
+} /* __usf_ioctl */
+
+static long usf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct usf_type *usf = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&usf->mutex);
+ rc = __usf_ioctl(usf, cmd, arg);
+ mutex_unlock(&usf->mutex);
+
+ return rc;
} /* usf_ioctl */
#ifdef CONFIG_COMPAT
@@ -2117,12 +2147,11 @@
return __usf_get_stream_param(usf_xx, &get_stream_param, dir);
} /* usf_get_stream_param32 */
-static long usf_compat_ioctl(struct file *file,
+static long __usf_compat_ioctl(struct usf_type *usf,
unsigned int cmd,
unsigned long arg)
{
int rc = 0;
- struct usf_type *usf = file->private_data;
struct usf_xx_type *usf_xx = NULL;
switch (cmd) {
@@ -2130,7 +2159,7 @@
case US_START_RX:
case US_STOP_TX:
case US_STOP_RX: {
- return usf_ioctl(file, cmd, arg);
+ return __usf_ioctl(usf, cmd, arg);
}
case US_SET_TX_INFO32: {
@@ -2239,6 +2268,20 @@
release_xx(usf_xx);
return rc;
+} /* __usf_compat_ioctl */
+
+static long usf_compat_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct usf_type *usf = file->private_data;
+ int rc = 0;
+
+ mutex_lock(&usf->mutex);
+ rc = __usf_compat_ioctl(usf, cmd, arg);
+ mutex_unlock(&usf->mutex);
+
+ return rc;
} /* usf_compat_ioctl */
#endif /* CONFIG_COMPAT */
@@ -2247,13 +2290,17 @@
struct usf_type *usf = file->private_data;
int dir = OUT;
struct usf_xx_type *usf_xx = &usf->usf_tx;
+ int rc = 0;
+ mutex_lock(&usf->mutex);
if (vms->vm_flags & USF_VM_WRITE) { /* RX buf mapping */
dir = IN;
usf_xx = &usf->usf_rx;
}
+ rc = q6usm_get_virtual_address(dir, usf_xx->usc, vms);
+ mutex_unlock(&usf->mutex);
- return q6usm_get_virtual_address(dir, usf_xx->usc, vms);
+ return rc;
}
static uint16_t add_opened_dev(int minor)
@@ -2306,6 +2353,8 @@
usf->usf_tx.us_detect_type = USF_US_DETECT_UNDEF;
usf->usf_rx.us_detect_type = USF_US_DETECT_UNDEF;
+ mutex_init(&usf->mutex);
+
pr_debug("%s:usf in open\n", __func__);
return 0;
}
@@ -2316,6 +2365,7 @@
pr_debug("%s: release entry\n", __func__);
+ mutex_lock(&usf->mutex);
usf_release_input(usf);
usf_disable(&usf->usf_tx);
@@ -2324,6 +2374,8 @@
s_opened_devs[usf->dev_ind] = 0;
wakeup_source_trash(&usf_wakeup_source);
+ mutex_unlock(&usf->mutex);
+ mutex_destroy(&usf->mutex);
kfree(usf);
pr_debug("%s: release exit\n", __func__);
return 0;
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 7dd1df9..ef084eac6 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -132,6 +132,35 @@
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;
@@ -146,6 +175,8 @@
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 {
@@ -269,30 +300,6 @@
static struct qseecom_control qseecom;
-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)
-
struct qseecom_dev_handle {
enum qseecom_client_handle_type type;
union {
@@ -306,8 +313,9 @@
bool perf_enabled;
bool fast_load_enabled;
enum qseecom_bandwidth_request_mode mode;
- struct sglist_info *sglistinfo_ptr;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
uint32_t sglist_cnt;
+ bool use_legacy_cmd;
};
struct qseecom_key_id_usage_desc {
@@ -586,6 +594,34 @@
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;
@@ -1126,7 +1162,7 @@
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;
@@ -1587,6 +1623,16 @@
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)
{
@@ -1595,9 +1641,14 @@
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;
@@ -1670,15 +1721,42 @@
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;
ptr_svc->send_resp_flag = 0;
- 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,
@@ -1688,9 +1766,8 @@
__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));
+ __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);
@@ -1723,9 +1800,14 @@
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;
@@ -1788,13 +1870,38 @@
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,
@@ -1804,11 +1911,9 @@
__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) {
@@ -1955,6 +2060,7 @@
struct qseecom_load_app_64bit_ireq load_req_64bit;
void *cmd_buf = NULL;
size_t cmd_len;
+ bool first_time = false;
/* Copy the relevant information needed for loading the image */
if (copy_from_user(&load_img_req,
@@ -2026,6 +2132,7 @@
&qseecom.registered_app_list_lock, flags);
ret = 0;
} else {
+ first_time = true;
pr_warn("App (%s) does'nt exist, loading apps for first time\n",
(char *)(load_img_req.img_name));
/* Get the handle of the shared fd */
@@ -2157,8 +2264,15 @@
load_img_req.app_id = app_id;
if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
pr_err("copy_to_user failed\n");
- kzfree(entry);
ret = -EFAULT;
+ if (first_time == true) {
+ spin_lock_irqsave(
+ &qseecom.registered_app_list_lock, flags);
+ list_del(&entry->list);
+ spin_unlock_irqrestore(
+ &qseecom.registered_app_list_lock, flags);
+ kzfree(entry);
+ }
}
loadapp_err:
@@ -2828,7 +2942,7 @@
cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
}
- if (qseecom.whitelist_support == false)
+ 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;
@@ -2933,6 +3047,8 @@
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))
@@ -2954,7 +3070,6 @@
}
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,
@@ -3096,14 +3211,25 @@
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,
- req->ifd_data[i].cmd_buf_offset);
+ (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 */
@@ -3176,6 +3302,8 @@
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))
@@ -3197,7 +3325,6 @@
}
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,
@@ -3314,14 +3441,25 @@
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,
- req->ifd_data[i].cmd_buf_offset);
+ (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 */
@@ -4018,21 +4156,12 @@
data->client.user_virt_sb_base = 0;
data->client.ihandle = NULL;
- /* Allocate sglistinfo buffer for kernel client */
- data->sglistinfo_ptr = kzalloc(SGLISTINFO_TABLE_SIZE, GFP_KERNEL);
- if (!(data->sglistinfo_ptr)) {
- kfree(data);
- kfree(*handle);
- *handle = NULL;
- return -ENOMEM;
- }
init_waitqueue_head(&data->abort_wq);
data->client.ihandle = ion_alloc(qseecom.ion_clnt, size, 4096,
ION_HEAP(ION_QSECOM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(data->client.ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
- kfree(data->sglistinfo_ptr);
kfree(data);
kfree(*handle);
*handle = NULL;
@@ -4130,7 +4259,6 @@
return 0;
err:
- kfree(data->sglistinfo_ptr);
kfree(data);
kfree(*handle);
*handle = NULL;
@@ -4178,7 +4306,6 @@
mutex_unlock(&app_access_lock);
if (ret == 0) {
- kzfree(data->sglistinfo_ptr);
kzfree(data);
kzfree(*handle);
kzfree(kclient);
@@ -4244,8 +4371,11 @@
}
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);
@@ -6907,6 +7037,7 @@
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: {
@@ -7056,10 +7187,6 @@
data->mode = INACTIVE;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
-
- data->sglistinfo_ptr = kzalloc(SGLISTINFO_TABLE_SIZE, GFP_KERNEL);
- if (!(data->sglistinfo_ptr))
- return -ENOMEM;
return ret;
}
@@ -7114,7 +7241,6 @@
if (data->perf_enabled == true)
qsee_disable_clock_vote(data, CLK_DFAB);
}
- kfree(data->sglistinfo_ptr);
kfree(data);
return ret;
@@ -7863,73 +7989,14 @@
}
/*
- * Check if whitelist feature is supported by making a test scm_call
- * to send a whitelist command to an invalid app ID 0
+ * 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)
{
- 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;
- uint32_t buf_size = 128;
- void *buf = NULL;
- void *cmd_buf = NULL;
- size_t cmd_len;
- int ret = 0;
- phys_addr_t pa;
+ int version = scm_get_feat_version(FEATURE_ID_WHITELIST);
- buf = kzalloc(buf_size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- pa = virt_to_phys(buf);
- if (qseecom.qsee_version < QSEE_VERSION_40) {
- send_data_req.qsee_cmd_id =
- QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
- send_data_req.app_id = 0;
- send_data_req.req_ptr = (uint32_t)pa;
- send_data_req.req_len = buf_size;
- send_data_req.rsp_ptr = (uint32_t)pa;
- send_data_req.rsp_len = buf_size;
- send_data_req.sglistinfo_ptr = (uint32_t)pa;
- send_data_req.sglistinfo_len = buf_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_WHITELIST;
- send_data_req_64bit.app_id = 0;
- send_data_req_64bit.req_ptr = (uint64_t)pa;
- send_data_req_64bit.req_len = buf_size;
- send_data_req_64bit.rsp_ptr = (uint64_t)pa;
- send_data_req_64bit.rsp_len = buf_size;
- send_data_req_64bit.sglistinfo_ptr = (uint64_t)pa;
- send_data_req_64bit.sglistinfo_len = buf_size;
- cmd_buf = (void *)&send_data_req_64bit;
- cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
- }
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- cmd_buf, cmd_len,
- &resp, sizeof(resp));
-/*
- * If this cmd exists and whitelist is supported, scm_call return -2 (scm
- * driver remap it to -EINVAL) and resp.result 0xFFFFFFED(-19); Otherwise,
- * scm_call return -1 (remap to -EIO).
- */
- if (ret == -EIO) {
- qseecom.whitelist_support = false;
- ret = 0;
- } else if (ret == -EINVAL &&
- resp.result == QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD) {
- qseecom.whitelist_support = true;
- ret = 0;
- } else {
- qseecom.whitelist_support = false;
- pr_err("Failed to check whitelist: ret = %d, result = 0x%x\n",
- ret, resp.result);
- ret = 0;
- }
- kfree(buf);
- return ret;
+ return version >= MAKE_WHITELIST_VERSION(1, 0, 0);
}
static int qseecom_probe(struct platform_device *pdev)
@@ -8175,11 +8242,7 @@
qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
- rc = qseecom_check_whitelist_feature();
- if (rc) {
- rc = -EINVAL;
- goto exit_destroy_ion_client;
- }
+ qseecom.whitelist_support = qseecom_check_whitelist_feature();
pr_warn("qseecom.whitelist_support = %d\n",
qseecom.whitelist_support);
diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
index a601cf2..59efcd2 100644
--- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c
@@ -2455,7 +2455,7 @@
*
* Return codes:
* 0: Success
- * -EFAULT: Invalid interface name provided
+ * -EFAULT: Invalid src/dst pipes provided
* other: See ipa_qmi_set_data_quota
*/
int rmnet_ipa_set_tether_client_pipe(
@@ -2463,6 +2463,23 @@
{
int number, i;
+ /* error checking if ul_src_pipe_len valid or not*/
+ if (data->ul_src_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->ul_src_pipe_len < 0) {
+ IPAWANERR("UL src pipes %d exceeding max %d\n",
+ data->ul_src_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+ /* error checking if dl_dst_pipe_len valid or not*/
+ if (data->dl_dst_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->dl_dst_pipe_len < 0) {
+ IPAWANERR("DL dst pipes %d exceeding max %d\n",
+ data->dl_dst_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+
IPAWANDBG("client %d, UL %d, DL %d, reset %d\n",
data->ipa_client,
data->ul_src_pipe_len,
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index a71c077..98fc8bd 100644
--- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
@@ -2506,6 +2506,23 @@
{
int number, i;
+ /* error checking if ul_src_pipe_len valid or not*/
+ if (data->ul_src_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->ul_src_pipe_len < 0) {
+ IPAWANERR("UL src pipes %d exceeding max %d\n",
+ data->ul_src_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+ /* error checking if dl_dst_pipe_len valid or not*/
+ if (data->dl_dst_pipe_len > QMI_IPA_MAX_PIPES_V01 ||
+ data->dl_dst_pipe_len < 0) {
+ IPAWANERR("DL dst pipes %d exceeding max %d\n",
+ data->dl_dst_pipe_len,
+ QMI_IPA_MAX_PIPES_V01);
+ return -EFAULT;
+ }
+
IPAWANDBG("client %d, UL %d, DL %d, reset %d\n",
data->ipa_client,
data->ul_src_pipe_len,
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index 67c58d1..50dd925 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -223,8 +223,8 @@
} else if (!strcmp(apr_request->svc_name, VOICE_SVC_MVM_STR)) {
apr_handle = prtd->apr_q6_mvm;
} else {
- pr_err("%s: Invalid service %s\n", __func__,
- apr_request->svc_name);
+ pr_err("%s: Invalid service %.*s\n", __func__,
+ MAX_APR_SERVICE_NAME_LEN, apr_request->svc_name);
ret = -EINVAL;
goto done;
@@ -338,8 +338,8 @@
svc = VOICE_SVC_CVS_STR;
handle = &prtd->apr_q6_cvs;
} else {
- pr_err("%s: Invalid Service: %s\n", __func__,
- apr_reg_svc->svc_name);
+ pr_err("%s: Invalid Service: %.*s\n", __func__,
+ MAX_APR_SERVICE_NAME_LEN, apr_reg_svc->svc_name);
ret = -EINVAL;
goto done;
}
@@ -365,7 +365,17 @@
pr_debug("%s\n", __func__);
- data = kmalloc(count, GFP_KERNEL);
+ /*
+ * Check if enough memory is allocated to parse the message type.
+ * Will check there is enough to hold the payload later.
+ */
+ if (count >= sizeof(struct voice_svc_write_msg)) {
+ data = kmalloc(count, GFP_KERNEL);
+ } else {
+ pr_debug("%s: invalid data size\n", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
if (data == NULL) {
pr_err("%s: data kmalloc failed.\n", __func__);
@@ -383,7 +393,7 @@
}
cmd = data->msg_type;
- prtd = (struct voice_svc_prvt *)file->private_data;
+ prtd = (struct voice_svc_prvt *) file->private_data;
if (prtd == NULL) {
pr_err("%s: prtd is NULL\n", __func__);
@@ -393,9 +403,13 @@
switch (cmd) {
case MSG_REGISTER:
- if (count >=
- (sizeof(struct voice_svc_register) +
- sizeof(*data))) {
+ /*
+ * Check that count reflects the expected size to ensure
+ * sufficient memory was allocated. Since voice_svc_register
+ * has a static size, this should be exact.
+ */
+ if (count == (sizeof(struct voice_svc_write_msg) +
+ sizeof(struct voice_svc_register))) {
ret = process_reg_cmd(
(struct voice_svc_register *)data->payload, prtd);
if (!ret)
@@ -407,8 +421,13 @@
}
break;
case MSG_REQUEST:
- if (count >= (sizeof(struct voice_svc_cmd_request) +
- sizeof(*data))) {
+ /*
+ * Check that count reflects the expected size to ensure
+ * sufficient memory was allocated. Since voice_svc_cmd_request
+ * has a variable size, check the minimum value count must be.
+ */
+ if (count >= (sizeof(struct voice_svc_write_msg) +
+ sizeof(struct voice_svc_cmd_request))) {
ret = voice_svc_send_req(
(struct voice_svc_cmd_request *)data->payload, prtd);
if (!ret)
diff --git a/drivers/soc/qcom/scm.c b/drivers/soc/qcom/scm.c
index 77f77fc..a27cb8b 100644
--- a/drivers/soc/qcom/scm.c
+++ b/drivers/soc/qcom/scm.c
@@ -657,10 +657,6 @@
desc->ret[0] = desc->ret[1] = desc->ret[2] = 0;
- pr_debug("scm_call: func id %#llx, args: %#x, %#llx, %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5);
-
if (scm_version == SCM_ARMV8_64)
ret = __scm_call_armv8_64(x0, desc->arginfo,
desc->args[0], desc->args[1],
@@ -684,10 +680,8 @@
} while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
if (ret < 0)
- pr_err("scm_call failed: func id %#llx, arginfo: %#x, args: %#llx, %#llx, %#llx, %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
- x0, desc->arginfo, desc->args[0], desc->args[1],
- desc->args[2], desc->x5, ret, desc->ret[0],
- desc->ret[1], desc->ret[2]);
+ pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
+ x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
if (arglen > N_REGISTER_ARGS)
kfree(desc->extra_arg_buf);
diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c
index 971e75a..2b5e770 100644
--- a/drivers/staging/android/binder.c
+++ b/drivers/staging/android/binder.c
@@ -473,7 +473,7 @@
new_buffer_size = binder_buffer_size(proc, new_buffer);
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: add free buffer, size %zd, at %p\n",
+ "%d: add free buffer, size %zd, at %pK\n",
proc->pid, new_buffer_size, new_buffer);
while (*p) {
@@ -551,7 +551,7 @@
struct mm_struct *mm;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: %s pages %p-%p\n", proc->pid,
+ "%d: %s pages %pK-%pK\n", proc->pid,
allocate ? "allocate" : "free", start, end);
if (end <= start)
@@ -591,7 +591,7 @@
BUG_ON(*page);
*page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
if (*page == NULL) {
- pr_err("%d: binder_alloc_buf failed for page at %p\n",
+ pr_err("%d: binder_alloc_buf failed for page at %pK\n",
proc->pid, page_addr);
goto err_alloc_page_failed;
}
@@ -600,7 +600,7 @@
flush_cache_vmap((unsigned long)page_addr,
(unsigned long)page_addr + PAGE_SIZE);
if (ret != 1) {
- pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
+ pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n",
proc->pid, page_addr);
goto err_map_kernel_failed;
}
@@ -704,7 +704,7 @@
}
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_alloc_buf size %zd got buffer %p size %zd\n",
+ "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n",
proc->pid, size, buffer, buffer_size);
has_page_addr =
@@ -734,7 +734,7 @@
binder_insert_free_buffer(proc, new_buffer);
}
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_alloc_buf size %zd got %p\n",
+ "%d: binder_alloc_buf size %zd got %pK\n",
proc->pid, size, buffer);
buffer->data_size = data_size;
buffer->offsets_size = offsets_size;
@@ -774,7 +774,7 @@
if (buffer_end_page(prev) == buffer_end_page(buffer))
free_page_end = 0;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p share page with %p\n",
+ "%d: merge free, buffer %pK share page with %pK\n",
proc->pid, buffer, prev);
}
@@ -787,14 +787,14 @@
buffer_start_page(buffer))
free_page_start = 0;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p share page with %p\n",
+ "%d: merge free, buffer %pK share page with %pK\n",
proc->pid, buffer, prev);
}
}
list_del(&buffer->entry);
if (free_page_start || free_page_end) {
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: merge free, buffer %p do not share page%s%s with %p or %p\n",
+ "%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
proc->pid, buffer, free_page_start ? "" : " end",
free_page_end ? "" : " start", prev, next);
binder_update_page_range(proc, 0, free_page_start ?
@@ -815,7 +815,7 @@
ALIGN(buffer->offsets_size, sizeof(void *));
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%d: binder_free_buf %p size %zd buffer_size %zd\n",
+ "%d: binder_free_buf %pK size %zd buffer_size %zd\n",
proc->pid, buffer, size, buffer_size);
BUG_ON(buffer->free);
@@ -1245,7 +1245,7 @@
int debug_id = buffer->debug_id;
binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d buffer release %d, size %zd-%zd, failed at %p\n",
+ "%d buffer release %d, size %zd-%zd, failed at %pK\n",
proc->pid, buffer->debug_id,
buffer->data_size, buffer->offsets_size, failed_at);
@@ -2092,7 +2092,7 @@
}
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
- "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
+ "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n",
proc->pid, thread->pid, (u64)cookie,
death);
if (death == NULL) {
@@ -2895,7 +2895,7 @@
#ifdef CONFIG_CPU_CACHE_VIPT
if (cache_is_vipt_aliasing()) {
while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
- pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
+ pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
vma->vm_start += PAGE_SIZE;
}
}
@@ -2927,7 +2927,7 @@
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
- /*pr_info("binder_mmap: %d %lx-%lx maps %p\n",
+ /*pr_info("binder_mmap: %d %lx-%lx maps %pK\n",
proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/
return 0;
@@ -3153,7 +3153,7 @@
page_addr = proc->buffer + i * PAGE_SIZE;
binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
- "%s: %d: page %d at %p not freed\n",
+ "%s: %d: page %d at %pK not freed\n",
__func__, proc->pid, i, page_addr);
unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
__free_page(proc->pages[i]);
@@ -3232,7 +3232,7 @@
struct binder_transaction *t)
{
seq_printf(m,
- "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+ "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
prefix, t->debug_id, t,
t->from ? t->from->proc->pid : 0,
t->from ? t->from->pid : 0,
@@ -3246,7 +3246,7 @@
if (t->buffer->target_node)
seq_printf(m, " node %d",
t->buffer->target_node->debug_id);
- seq_printf(m, " size %zd:%zd data %p\n",
+ seq_printf(m, " size %zd:%zd data %pK\n",
t->buffer->data_size, t->buffer->offsets_size,
t->buffer->data);
}
@@ -3254,7 +3254,7 @@
static void print_binder_buffer(struct seq_file *m, const char *prefix,
struct binder_buffer *buffer)
{
- seq_printf(m, "%s %d: %p size %zd:%zd %s\n",
+ seq_printf(m, "%s %d: %pK size %zd:%zd %s\n",
prefix, buffer->debug_id, buffer->data,
buffer->data_size, buffer->offsets_size,
buffer->transaction ? "active" : "delivered");
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
old mode 100644
new mode 100755
index a2569da..ce6909d
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -406,13 +406,22 @@
kref_get(&handle->ref);
}
+static int ion_handle_put_nolock(struct ion_handle *handle)
+{
+ int ret;
+
+ ret = kref_put(&handle->ref, ion_handle_destroy);
+
+ return ret;
+}
+
int ion_handle_put(struct ion_handle *handle)
{
struct ion_client *client = handle->client;
int ret;
mutex_lock(&client->lock);
- ret = kref_put(&handle->ref, ion_handle_destroy);
+ ret = ion_handle_put_nolock(handle);
mutex_unlock(&client->lock);
return ret;
@@ -436,18 +445,28 @@
return ERR_PTR(-EINVAL);
}
+static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client,
+ int id)
+{
+ struct ion_handle *handle;
+
+ handle = idr_find(&client->idr, id);
+ if (handle)
+ ion_handle_get(handle);
+
+ return handle ? handle : ERR_PTR(-EINVAL);
+}
+
struct ion_handle *ion_handle_get_by_id(struct ion_client *client,
int id)
{
struct ion_handle *handle;
mutex_lock(&client->lock);
- handle = idr_find(&client->idr, id);
- if (handle)
- ion_handle_get(handle);
+ handle = ion_handle_get_by_id_nolock(client, id);
mutex_unlock(&client->lock);
- return handle ? handle : ERR_PTR(-EINVAL);
+ return handle;
}
static bool ion_handle_validate(struct ion_client *client,
@@ -596,21 +615,27 @@
}
EXPORT_SYMBOL(ion_alloc);
-void ion_free(struct ion_client *client, struct ion_handle *handle)
+static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle)
{
bool valid_handle;
BUG_ON(client != handle->client);
- mutex_lock(&client->lock);
valid_handle = ion_handle_validate(client, handle);
if (!valid_handle) {
WARN(1, "%s: invalid handle passed to free.\n", __func__);
- mutex_unlock(&client->lock);
return;
}
+ ion_handle_put_nolock(handle);
+}
+
+void ion_free(struct ion_client *client, struct ion_handle *handle)
+{
+ BUG_ON(client != handle->client);
+
+ mutex_lock(&client->lock);
+ ion_free_nolock(client, handle);
mutex_unlock(&client->lock);
- ion_handle_put(handle);
}
EXPORT_SYMBOL(ion_free);
@@ -1477,11 +1502,15 @@
{
struct ion_handle *handle;
- handle = ion_handle_get_by_id(client, data.handle.handle);
- if (IS_ERR(handle))
+ mutex_lock(&client->lock);
+ handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
+ if (IS_ERR(handle)) {
+ mutex_unlock(&client->lock);
return PTR_ERR(handle);
- ion_free(client, handle);
- ion_handle_put(handle);
+ }
+ ion_free_nolock(client, handle);
+ ion_handle_put_nolock(handle);
+ mutex_unlock(&client->lock);
break;
}
case ION_IOC_SHARE:
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index ff4d8ca..03c1eda 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -1330,6 +1330,32 @@
return -EPERM;
}
+ panel = mdp3_session->panel;
+ mutex_lock(&mdp3_res->fs_idle_pc_lock);
+ if (mdp3_session->in_splash_screen ||
+ mdp3_res->idle_pc) {
+ pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
+ mdp3_session->in_splash_screen, mdp3_res->idle_pc);
+ rc = mdp3_ctrl_reset(mfd);
+ if (rc) {
+ pr_err("fail to reset display\n");
+ mutex_unlock(&mdp3_res->fs_idle_pc_lock);
+ return -EINVAL;
+ }
+ if ((mdp3_session->dma->roi.x || mdp3_session->dma->roi.y) &&
+ panel_info->partial_update_enabled)
+ mdp3_session->dma->update_src_cfg = true;
+ }
+ mutex_unlock(&mdp3_res->fs_idle_pc_lock);
+
+ mutex_lock(&mdp3_session->lock);
+
+ if (!mdp3_session->status) {
+ pr_err("%s, display off!\n", __func__);
+ mutex_unlock(&mdp3_session->lock);
+ return -EPERM;
+ }
+
if (panel_info->partial_update_enabled &&
is_roi_valid(mdp3_session->dma->source_config, cmt_data->l_roi)
&& update_roi(mdp3_session->dma->roi, cmt_data->l_roi)) {
@@ -1345,29 +1371,6 @@
mdp3_session->dma->roi.h);
}
- panel = mdp3_session->panel;
- mutex_lock(&mdp3_res->fs_idle_pc_lock);
- if (mdp3_session->in_splash_screen ||
- mdp3_res->idle_pc) {
- pr_debug("%s: reset- in_splash = %d, idle_pc = %d", __func__,
- mdp3_session->in_splash_screen, mdp3_res->idle_pc);
- rc = mdp3_ctrl_reset(mfd);
- if (rc) {
- pr_err("fail to reset display\n");
- mutex_unlock(&mdp3_res->fs_idle_pc_lock);
- return -EINVAL;
- }
- }
- mutex_unlock(&mdp3_res->fs_idle_pc_lock);
-
- mutex_lock(&mdp3_session->lock);
-
- if (!mdp3_session->status) {
- pr_err("%s, display off!\n", __func__);
- mutex_unlock(&mdp3_session->lock);
- return -EPERM;
- }
-
mdp3_ctrl_notify(mdp3_session, MDP_NOTIFY_FRAME_BEGIN);
data = mdp3_bufq_pop(&mdp3_session->bufq_in);
if (data) {
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index d68eb1b..e83d404 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -178,6 +178,19 @@
return rc;
}
+static int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct file *lower_file = ecryptfs_file_to_lower(file);
+ /*
+ * Don't allow mmap on top of file systems that don't support it
+ * natively. If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs
+ * allows recursive mounting, this will need to be extended.
+ */
+ if (!lower_file->f_op->mmap)
+ return -ENODEV;
+ return generic_file_mmap(file, vma);
+}
+
/**
* ecryptfs_open
* @inode: inode speciying file to open
@@ -398,7 +411,7 @@
#ifdef CONFIG_COMPAT
.compat_ioctl = ecryptfs_compat_ioctl,
#endif
- .mmap = generic_file_mmap,
+ .mmap = ecryptfs_mmap,
.open = ecryptfs_open,
.flush = ecryptfs_flush,
.release = ecryptfs_release,
diff --git a/fs/ecryptfs/kthread.c b/fs/ecryptfs/kthread.c
index 9b661a4..f1ea610 100644
--- a/fs/ecryptfs/kthread.c
+++ b/fs/ecryptfs/kthread.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/mount.h>
-#include <linux/file.h>
#include "ecryptfs_kernel.h"
struct ecryptfs_open_req {
@@ -148,7 +147,7 @@
flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
(*lower_file) = dentry_open(&req.path, flags, cred);
if (!IS_ERR(*lower_file))
- goto have_file;
+ goto out;
if ((flags & O_ACCMODE) == O_RDONLY) {
rc = PTR_ERR((*lower_file));
goto out;
@@ -166,16 +165,8 @@
mutex_unlock(&ecryptfs_kthread_ctl.mux);
wake_up(&ecryptfs_kthread_ctl.wait);
wait_for_completion(&req.done);
- if (IS_ERR(*lower_file)) {
+ if (IS_ERR(*lower_file))
rc = PTR_ERR(*lower_file);
- goto out;
- }
-have_file:
- if ((*lower_file)->f_op->mmap == NULL) {
- fput(*lower_file);
- *lower_file = NULL;
- rc = -EMEDIUMTYPE;
- }
out:
return rc;
}
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b44a28d..8f957a7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2044,6 +2044,7 @@
#define FOLL_NUMA 0x200 /* force NUMA hinting page fault */
#define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */
#define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */
+#define FOLL_COW 0x4000 /* internal GUP flag */
typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr,
void *data);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index c1a2bd1..93474a4 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -339,6 +339,12 @@
int nr_siblings;
int group_flags;
struct perf_event *group_leader;
+
+ /*
+ * Protect the pmu, attributes and context of a group leader.
+ * Note: does not protect the pointer to the group_leader.
+ */
+ struct mutex group_leader_mutex;
struct pmu *pmu;
enum perf_event_active_state state;
diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h
index b0a8d67..e33fd9f 100644
--- a/include/soc/qcom/qseecomi.h
+++ b/include/soc/qcom/qseecomi.h
@@ -68,6 +68,7 @@
QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST = 0x1C,
QSEOS_TEE_OPEN_SESSION_WHITELIST = 0x1D,
QSEOS_TEE_INVOKE_COMMAND_WHITELIST = 0x1E,
+ QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST = 0x1F,
QSEOS_FSM_LTEOTA_REQ_CMD = 0x109,
QSEOS_FSM_LTEOTA_REQ_RSP_CMD = 0x110,
QSEOS_FSM_IKE_REQ_CMD = 0x203,
@@ -217,6 +218,16 @@
uint32_t qsee_cmd_id;
uint32_t listener_id;
uint32_t status;
+ uint32_t sglistinfo_ptr;
+ uint32_t sglistinfo_len;
+};
+
+__packed struct qseecom_client_listener_data_64bit_irsp {
+ uint32_t qsee_cmd_id;
+ uint32_t listener_id;
+ uint32_t status;
+ uint64_t sglistinfo_ptr;
+ uint32_t sglistinfo_len;
};
/*
@@ -703,4 +714,12 @@
TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \
TZ_SYSCALL_PARAM_TYPE_VAL)
+#define TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID \
+ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_QSEE_OS, TZ_SVC_LISTENER, 0x05)
+
+#define TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID \
+ TZ_SYSCALL_CREATE_PARAM_ID_4( \
+ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_VAL, \
+ TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+
#endif /* __QSEECOMI_H_ */
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 8560c93..7d47410 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -5514,7 +5514,7 @@
struct task_struct *task;
int count = 0;
- seq_printf(seq, "css_set %p\n", cset);
+ seq_printf(seq, "css_set %pK\n", cset);
list_for_each_entry(task, &cset->tasks, cg_list) {
if (count++ > MAX_TASKS_SHOWN_PER_CSS)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index f72dc9f..264b178 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -915,6 +915,77 @@
}
/*
+ * Because of perf_event::ctx migration in sys_perf_event_open::move_group and
+ * perf_pmu_migrate_context() we need some magic.
+ *
+ * Those places that change perf_event::ctx will hold both
+ * perf_event_ctx::mutex of the 'old' and 'new' ctx value.
+ *
+ * Lock ordering is by mutex address. There is one other site where
+ * perf_event_context::mutex nests and that is put_event(). But remember that
+ * that is a parent<->child context relation, and migration does not affect
+ * children, therefore these two orderings should not interact.
+ *
+ * The change in perf_event::ctx does not affect children (as claimed above)
+ * because the sys_perf_event_open() case will install a new event and break
+ * the ctx parent<->child relation, and perf_pmu_migrate_context() is only
+ * concerned with cpuctx and that doesn't have children.
+ *
+ * The places that change perf_event::ctx will issue:
+ *
+ * perf_remove_from_context();
+ * synchronize_rcu();
+ * perf_install_in_context();
+ *
+ * to affect the change. The remove_from_context() + synchronize_rcu() should
+ * quiesce the event, after which we can install it in the new location. This
+ * means that only external vectors (perf_fops, prctl) can perturb the event
+ * while in transit. Therefore all such accessors should also acquire
+ * perf_event_context::mutex to serialize against this.
+ *
+ * However; because event->ctx can change while we're waiting to acquire
+ * ctx->mutex we must be careful and use the below perf_event_ctx_lock()
+ * function.
+ *
+ * Lock order:
+ * task_struct::perf_event_mutex
+ * perf_event_context::mutex
+ * perf_event_context::lock
+ * perf_event::child_mutex;
+ * perf_event::mmap_mutex
+ * mmap_sem
+ */
+static struct perf_event_context *perf_event_ctx_lock(struct perf_event *event)
+{
+ struct perf_event_context *ctx;
+
+again:
+ rcu_read_lock();
+ ctx = ACCESS_ONCE(event->ctx);
+ if (!atomic_inc_not_zero(&ctx->refcount)) {
+ rcu_read_unlock();
+ goto again;
+ }
+ rcu_read_unlock();
+
+ mutex_lock(&ctx->mutex);
+ if (event->ctx != ctx) {
+ mutex_unlock(&ctx->mutex);
+ put_ctx(ctx);
+ goto again;
+ }
+
+ return ctx;
+}
+
+static void perf_event_ctx_unlock(struct perf_event *event,
+ struct perf_event_context *ctx)
+{
+ mutex_unlock(&ctx->mutex);
+ put_ctx(ctx);
+}
+
+/*
* This must be done under the ctx->lock, such as to serialize against
* context_equiv(), therefore we cannot call put_ctx() since that might end up
* calling scheduler related locks and ctx->lock nests inside those.
@@ -1693,7 +1764,7 @@
* is the current context on this CPU and preemption is disabled,
* hence we can't get into perf_event_task_sched_out for this context.
*/
-void perf_event_disable(struct perf_event *event)
+static void _perf_event_disable(struct perf_event *event)
{
struct perf_event_context *ctx = event->ctx;
struct task_struct *task = ctx->task;
@@ -1734,6 +1805,19 @@
}
raw_spin_unlock_irq(&ctx->lock);
}
+
+/*
+ * Strictly speaking kernel users cannot create groups and therefore this
+ * interface does not need the perf_event_ctx_lock() magic.
+ */
+void perf_event_disable(struct perf_event *event)
+{
+ struct perf_event_context *ctx;
+
+ ctx = perf_event_ctx_lock(event);
+ _perf_event_disable(event);
+ perf_event_ctx_unlock(event, ctx);
+}
EXPORT_SYMBOL_GPL(perf_event_disable);
static void perf_set_shadow_time(struct perf_event *event,
@@ -2197,7 +2281,7 @@
* perf_event_for_each_child or perf_event_for_each as described
* for perf_event_disable.
*/
-void perf_event_enable(struct perf_event *event)
+static void _perf_event_enable(struct perf_event *event)
{
struct perf_event_context *ctx = event->ctx;
struct task_struct *task = ctx->task;
@@ -2253,9 +2337,21 @@
out:
raw_spin_unlock_irq(&ctx->lock);
}
+
+/*
+ * See perf_event_disable();
+ */
+void perf_event_enable(struct perf_event *event)
+{
+ struct perf_event_context *ctx;
+
+ ctx = perf_event_ctx_lock(event);
+ _perf_event_enable(event);
+ perf_event_ctx_unlock(event, ctx);
+}
EXPORT_SYMBOL_GPL(perf_event_enable);
-int perf_event_refresh(struct perf_event *event, int refresh)
+static int _perf_event_refresh(struct perf_event *event, int refresh)
{
/*
* not supported on inherited events
@@ -2264,10 +2360,25 @@
return -EINVAL;
atomic_add(refresh, &event->event_limit);
- perf_event_enable(event);
+ _perf_event_enable(event);
return 0;
}
+
+/*
+ * See perf_event_disable()
+ */
+int perf_event_refresh(struct perf_event *event, int refresh)
+{
+ struct perf_event_context *ctx;
+ int ret;
+
+ ctx = perf_event_ctx_lock(event);
+ ret = _perf_event_refresh(event, refresh);
+ perf_event_ctx_unlock(event, ctx);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(perf_event_refresh);
static void ctx_sched_out(struct perf_event_context *ctx,
@@ -3465,7 +3576,16 @@
rcu_read_unlock();
if (owner) {
- mutex_lock(&owner->perf_event_mutex);
+ /*
+ * If we're here through perf_event_exit_task() we're already
+ * holding ctx->mutex which would be an inversion wrt. the
+ * normal lock order.
+ *
+ * However we can safely take this lock because its the child
+ * ctx->mutex.
+ */
+ mutex_lock_nested(&owner->perf_event_mutex, SINGLE_DEPTH_NESTING);
+
/*
* We have to re-check the event->owner field, if it is cleared
* we raced with perf_event_exit_task(), acquiring the mutex
@@ -3600,12 +3720,13 @@
u64 read_format, char __user *buf)
{
struct perf_event *leader = event->group_leader, *sub;
- int n = 0, size = 0, ret = -EFAULT;
struct perf_event_context *ctx = leader->ctx;
- u64 values[5];
+ int n = 0, size = 0, ret;
u64 count, enabled, running;
+ u64 values[5];
- mutex_lock(&ctx->mutex);
+ lockdep_assert_held(&ctx->mutex);
+
count = perf_event_read_value(leader, &enabled, &running);
values[n++] = 1 + leader->nr_siblings;
@@ -3620,7 +3741,7 @@
size = n * sizeof(u64);
if (copy_to_user(buf, values, size))
- goto unlock;
+ return -EFAULT;
ret = size;
@@ -3634,14 +3755,11 @@
size = n * sizeof(u64);
if (copy_to_user(buf + ret, values, size)) {
- ret = -EFAULT;
- goto unlock;
+ return -EFAULT;
}
ret += size;
}
-unlock:
- mutex_unlock(&ctx->mutex);
return ret;
}
@@ -3713,8 +3831,14 @@
perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct perf_event *event = file->private_data;
+ struct perf_event_context *ctx;
+ int ret;
- return perf_read_hw(event, buf, count);
+ ctx = perf_event_ctx_lock(event);
+ ret = perf_read_hw(event, buf, count);
+ perf_event_ctx_unlock(event, ctx);
+
+ return ret;
}
static unsigned int perf_poll(struct file *file, poll_table *wait)
@@ -3740,7 +3864,7 @@
return events;
}
-static void perf_event_reset(struct perf_event *event)
+static void _perf_event_reset(struct perf_event *event)
{
(void)perf_event_read(event);
local64_set(&event->count, 0);
@@ -3759,6 +3883,7 @@
struct perf_event *child;
WARN_ON_ONCE(event->ctx->parent_ctx);
+
mutex_lock(&event->child_mutex);
func(event);
list_for_each_entry(child, &event->child_list, child_list)
@@ -3772,14 +3897,13 @@
struct perf_event_context *ctx = event->ctx;
struct perf_event *sibling;
- WARN_ON_ONCE(ctx->parent_ctx);
- mutex_lock(&ctx->mutex);
+ lockdep_assert_held(&ctx->mutex);
+
event = event->group_leader;
perf_event_for_each_child(event, func);
list_for_each_entry(sibling, &event->sibling_list, group_entry)
perf_event_for_each_child(sibling, func);
- mutex_unlock(&ctx->mutex);
}
struct period_event {
@@ -3884,25 +4008,24 @@
struct perf_event *output_event);
static int perf_event_set_filter(struct perf_event *event, void __user *arg);
-static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned long arg)
{
- struct perf_event *event = file->private_data;
void (*func)(struct perf_event *);
u32 flags = arg;
switch (cmd) {
case PERF_EVENT_IOC_ENABLE:
- func = perf_event_enable;
+ func = _perf_event_enable;
break;
case PERF_EVENT_IOC_DISABLE:
- func = perf_event_disable;
+ func = _perf_event_disable;
break;
case PERF_EVENT_IOC_RESET:
- func = perf_event_reset;
+ func = _perf_event_reset;
break;
case PERF_EVENT_IOC_REFRESH:
- return perf_event_refresh(event, arg);
+ return _perf_event_refresh(event, arg);
case PERF_EVENT_IOC_PERIOD:
return perf_event_period(event, (u64 __user *)arg);
@@ -3949,6 +4072,19 @@
return 0;
}
+static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct perf_event *event = file->private_data;
+ struct perf_event_context *ctx;
+ long ret;
+
+ ctx = perf_event_ctx_lock(event);
+ ret = _perf_ioctl(event, cmd, arg);
+ perf_event_ctx_unlock(event, ctx);
+
+ return ret;
+}
+
#ifdef CONFIG_COMPAT
static long perf_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
@@ -3971,11 +4107,15 @@
int perf_event_task_enable(void)
{
+ struct perf_event_context *ctx;
struct perf_event *event;
mutex_lock(¤t->perf_event_mutex);
- list_for_each_entry(event, ¤t->perf_event_list, owner_entry)
- perf_event_for_each_child(event, perf_event_enable);
+ list_for_each_entry(event, ¤t->perf_event_list, owner_entry) {
+ ctx = perf_event_ctx_lock(event);
+ perf_event_for_each_child(event, _perf_event_enable);
+ perf_event_ctx_unlock(event, ctx);
+ }
mutex_unlock(¤t->perf_event_mutex);
return 0;
@@ -3983,11 +4123,15 @@
int perf_event_task_disable(void)
{
+ struct perf_event_context *ctx;
struct perf_event *event;
mutex_lock(¤t->perf_event_mutex);
- list_for_each_entry(event, ¤t->perf_event_list, owner_entry)
- perf_event_for_each_child(event, perf_event_disable);
+ list_for_each_entry(event, ¤t->perf_event_list, owner_entry) {
+ ctx = perf_event_ctx_lock(event);
+ perf_event_for_each_child(event, _perf_event_disable);
+ perf_event_ctx_unlock(event, ctx);
+ }
mutex_unlock(¤t->perf_event_mutex);
return 0;
@@ -7031,6 +7175,7 @@
if (!group_leader)
group_leader = event;
+ mutex_init(&event->group_leader_mutex);
mutex_init(&event->child_mutex);
INIT_LIST_HEAD(&event->child_list);
@@ -7307,6 +7452,15 @@
return ret;
}
+static void mutex_lock_double(struct mutex *a, struct mutex *b)
+{
+ if (b < a)
+ swap(a, b);
+
+ mutex_lock(a);
+ mutex_lock_nested(b, SINGLE_DEPTH_NESTING);
+}
+
/**
* sys_perf_event_open - open a performance event, associate it to a task/cpu
*
@@ -7322,7 +7476,7 @@
struct perf_event *group_leader = NULL, *output_event = NULL;
struct perf_event *event, *sibling;
struct perf_event_attr attr;
- struct perf_event_context *ctx;
+ struct perf_event_context *ctx, *uninitialized_var(gctx);
struct file *event_file = NULL;
struct fd group = {NULL, 0};
struct task_struct *task = NULL;
@@ -7386,6 +7540,16 @@
group_leader = NULL;
}
+ /*
+ * Take the group_leader's group_leader_mutex before observing
+ * anything in the group leader that leads to changes in ctx,
+ * many of which may be changing on another thread.
+ * In particular, we want to take this lock before deciding
+ * whether we need to move_group.
+ */
+ if (group_leader)
+ mutex_lock(&group_leader->group_leader_mutex);
+
if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) {
task = find_lively_task_by_vpid(pid);
if (IS_ERR(task)) {
@@ -7526,9 +7690,14 @@
}
if (move_group) {
- struct perf_event_context *gctx = group_leader->ctx;
+ gctx = group_leader->ctx;
- mutex_lock(&gctx->mutex);
+ /*
+ * See perf_event_ctx_lock() for comments on the details
+ * of swizzling perf_event::ctx.
+ */
+ mutex_lock_double(&gctx->mutex, &ctx->mutex);
+
perf_remove_from_context(group_leader, false);
/*
@@ -7543,15 +7712,19 @@
perf_event__state_init(sibling);
put_ctx(gctx);
}
- mutex_unlock(&gctx->mutex);
- put_ctx(gctx);
+ } else {
+ mutex_lock(&ctx->mutex);
}
WARN_ON_ONCE(ctx->parent_ctx);
- mutex_lock(&ctx->mutex);
if (move_group) {
+ /*
+ * Wait for everybody to stop referencing the events through
+ * the old lists, before installing it on new lists.
+ */
synchronize_rcu();
+
perf_install_in_context(ctx, group_leader, group_leader->cpu);
get_ctx(ctx);
list_for_each_entry(sibling, &group_leader->sibling_list,
@@ -7563,7 +7736,14 @@
perf_install_in_context(ctx, event, event->cpu);
perf_unpin_context(ctx);
+
+ if (move_group) {
+ mutex_unlock(&gctx->mutex);
+ put_ctx(gctx);
+ }
mutex_unlock(&ctx->mutex);
+ if (group_leader)
+ mutex_unlock(&group_leader->group_leader_mutex);
put_online_cpus();
@@ -7600,6 +7780,8 @@
if (task)
put_task_struct(task);
err_group_fd:
+ if (group_leader)
+ mutex_unlock(&group_leader->group_leader_mutex);
fdput(group);
err_fd:
put_unused_fd(event_fd);
@@ -7670,7 +7852,11 @@
src_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, src_cpu)->ctx;
dst_ctx = &per_cpu_ptr(pmu->pmu_cpu_context, dst_cpu)->ctx;
- mutex_lock(&src_ctx->mutex);
+ /*
+ * See perf_event_ctx_lock() for comments on the details
+ * of swizzling perf_event::ctx.
+ */
+ mutex_lock_double(&src_ctx->mutex, &dst_ctx->mutex);
list_for_each_entry_safe(event, tmp, &src_ctx->event_list,
event_entry) {
perf_remove_from_context(event, false);
@@ -7678,11 +7864,9 @@
put_ctx(src_ctx);
list_add(&event->migrate_entry, &events);
}
- mutex_unlock(&src_ctx->mutex);
synchronize_rcu();
- mutex_lock(&dst_ctx->mutex);
list_for_each_entry_safe(event, tmp, &events, migrate_entry) {
list_del(&event->migrate_entry);
if (event->state >= PERF_EVENT_STATE_OFF)
@@ -7692,6 +7876,7 @@
get_ctx(dst_ctx);
}
mutex_unlock(&dst_ctx->mutex);
+ mutex_unlock(&src_ctx->mutex);
}
EXPORT_SYMBOL_GPL(perf_pmu_migrate_context);
diff --git a/mm/gup.c b/mm/gup.c
index 377a5a7..bef4bb0f 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -32,6 +32,16 @@
return NULL;
}
+/*
+ * FOLL_FORCE can write to even unwritable pte's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+{
+ return pte_write(pte) ||
+ ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
+}
+
static struct page *follow_page_pte(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmd, unsigned int flags)
{
@@ -66,7 +76,7 @@
}
if ((flags & FOLL_NUMA) && pte_numa(pte))
goto no_page;
- if ((flags & FOLL_WRITE) && !pte_write(pte)) {
+ if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags)) {
pte_unmap_unlock(ptep, ptl);
return NULL;
}
@@ -315,7 +325,7 @@
* reCOWed by userspace write).
*/
if ((ret & VM_FAULT_WRITE) && !(vma->vm_flags & VM_WRITE))
- *flags &= ~FOLL_WRITE;
+ *flags |= FOLL_COW;
return 0;
}
diff --git a/mm/percpu.c b/mm/percpu.c
index 88bb6c9..5ae6e02 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -110,7 +110,7 @@
int map_used; /* # of map entries used before the sentry */
int map_alloc; /* # of map entries allocated */
int *map; /* allocation map */
- struct work_struct map_extend_work;/* async ->map[] extension */
+ struct list_head map_extend_list;/* on pcpu_map_extend_chunks */
void *data; /* chunk data */
int first_free; /* no free below this */
@@ -160,10 +160,13 @@
static int pcpu_reserved_chunk_limit;
static DEFINE_SPINLOCK(pcpu_lock); /* all internal data structures */
-static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop */
+static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop, map ext */
static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */
+/* chunks which need their map areas extended, protected by pcpu_lock */
+static LIST_HEAD(pcpu_map_extend_chunks);
+
/*
* The number of empty populated pages, protected by pcpu_lock. The
* reserved chunk doesn't contribute to the count.
@@ -397,13 +400,19 @@
{
int margin, new_alloc;
+ lockdep_assert_held(&pcpu_lock);
+
if (is_atomic) {
margin = 3;
if (chunk->map_alloc <
- chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW &&
- pcpu_async_enabled)
- schedule_work(&chunk->map_extend_work);
+ chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW) {
+ if (list_empty(&chunk->map_extend_list)) {
+ list_add_tail(&chunk->map_extend_list,
+ &pcpu_map_extend_chunks);
+ pcpu_schedule_balance_work();
+ }
+ }
} else {
margin = PCPU_ATOMIC_MAP_MARGIN_HIGH;
}
@@ -437,6 +446,8 @@
size_t old_size = 0, new_size = new_alloc * sizeof(new[0]);
unsigned long flags;
+ lockdep_assert_held(&pcpu_alloc_mutex);
+
new = pcpu_mem_zalloc(new_size);
if (!new)
return -ENOMEM;
@@ -469,20 +480,6 @@
return 0;
}
-static void pcpu_map_extend_workfn(struct work_struct *work)
-{
- struct pcpu_chunk *chunk = container_of(work, struct pcpu_chunk,
- map_extend_work);
- int new_alloc;
-
- spin_lock_irq(&pcpu_lock);
- new_alloc = pcpu_need_to_extend(chunk, false);
- spin_unlock_irq(&pcpu_lock);
-
- if (new_alloc)
- pcpu_extend_area_map(chunk, new_alloc);
-}
-
/**
* pcpu_fit_in_area - try to fit the requested allocation in a candidate area
* @chunk: chunk the candidate area belongs to
@@ -742,7 +739,7 @@
chunk->map_used = 1;
INIT_LIST_HEAD(&chunk->list);
- INIT_WORK(&chunk->map_extend_work, pcpu_map_extend_workfn);
+ INIT_LIST_HEAD(&chunk->map_extend_list);
chunk->free_size = pcpu_unit_size;
chunk->contig_hint = pcpu_unit_size;
@@ -897,6 +894,9 @@
return NULL;
}
+ if (!is_atomic)
+ mutex_lock(&pcpu_alloc_mutex);
+
spin_lock_irqsave(&pcpu_lock, flags);
/* serve reserved allocations from the reserved chunk if available */
@@ -969,12 +969,9 @@
if (is_atomic)
goto fail;
- mutex_lock(&pcpu_alloc_mutex);
-
if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) {
chunk = pcpu_create_chunk();
if (!chunk) {
- mutex_unlock(&pcpu_alloc_mutex);
err = "failed to allocate new chunk";
goto fail;
}
@@ -985,7 +982,6 @@
spin_lock_irqsave(&pcpu_lock, flags);
}
- mutex_unlock(&pcpu_alloc_mutex);
goto restart;
area_found:
@@ -995,8 +991,6 @@
if (!is_atomic) {
int page_start, page_end, rs, re;
- mutex_lock(&pcpu_alloc_mutex);
-
page_start = PFN_DOWN(off);
page_end = PFN_UP(off + size);
@@ -1007,7 +1001,6 @@
spin_lock_irqsave(&pcpu_lock, flags);
if (ret) {
- mutex_unlock(&pcpu_alloc_mutex);
pcpu_free_area(chunk, off, &occ_pages);
err = "failed to populate";
goto fail_unlock;
@@ -1047,6 +1040,8 @@
/* see the flag handling in pcpu_blance_workfn() */
pcpu_atomic_alloc_failed = true;
pcpu_schedule_balance_work();
+ } else {
+ mutex_unlock(&pcpu_alloc_mutex);
}
return NULL;
}
@@ -1131,6 +1126,7 @@
if (chunk == list_first_entry(free_head, struct pcpu_chunk, list))
continue;
+ list_del_init(&chunk->map_extend_list);
list_move(&chunk->list, &to_free);
}
@@ -1148,6 +1144,25 @@
pcpu_destroy_chunk(chunk);
}
+ /* service chunks which requested async area map extension */
+ do {
+ int new_alloc = 0;
+
+ spin_lock_irq(&pcpu_lock);
+
+ chunk = list_first_entry_or_null(&pcpu_map_extend_chunks,
+ struct pcpu_chunk, map_extend_list);
+ if (chunk) {
+ list_del_init(&chunk->map_extend_list);
+ new_alloc = pcpu_need_to_extend(chunk, false);
+ }
+
+ spin_unlock_irq(&pcpu_lock);
+
+ if (new_alloc)
+ pcpu_extend_area_map(chunk, new_alloc);
+ } while (chunk);
+
/*
* Ensure there are certain number of free populated pages for
* atomic allocs. Fill up from the most packed so that atomic
@@ -1648,7 +1663,7 @@
*/
schunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0);
INIT_LIST_HEAD(&schunk->list);
- INIT_WORK(&schunk->map_extend_work, pcpu_map_extend_workfn);
+ INIT_LIST_HEAD(&schunk->map_extend_list);
schunk->base_addr = base_addr;
schunk->map = smap;
schunk->map_alloc = ARRAY_SIZE(smap);
@@ -1678,7 +1693,7 @@
if (dyn_size) {
dchunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0);
INIT_LIST_HEAD(&dchunk->list);
- INIT_WORK(&dchunk->map_extend_work, pcpu_map_extend_workfn);
+ INIT_LIST_HEAD(&dchunk->map_extend_list);
dchunk->base_addr = base_addr;
dchunk->map = dmap;
dchunk->map_alloc = ARRAY_SIZE(dmap);
diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c
index 3100ebd..ad357098 100644
--- a/net/ipc_router/ipc_router_core.c
+++ b/net/ipc_router/ipc_router_core.c
@@ -2785,6 +2785,9 @@
if (!port_ptr || !name)
return -EINVAL;
+ if (port_ptr->type != CLIENT_PORT)
+ return -EINVAL;
+
if (name->addrtype != MSM_IPC_ADDR_NAME)
return -EINVAL;
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 59f8d47..f65379c 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -656,7 +656,7 @@
void *user_icmph, size_t icmph_len) {
u8 type, code;
- if (len > 0xFFFF)
+ if (len > 0xFFFF || len < icmph_len)
return -EMSGSIZE;
/*
diff --git a/security/keys/gc.c b/security/keys/gc.c
index c795237..addf060 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -134,6 +134,12 @@
kdebug("- %u", key->serial);
key_check(key);
+ /* Throw away the key data if the key is instantiated */
+ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
+ !test_bit(KEY_FLAG_NEGATIVE, &key->flags) &&
+ key->type->destroy)
+ key->type->destroy(key);
+
security_key_free(key);
/* deal with the user's key tracking and quota */
@@ -148,10 +154,6 @@
if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
atomic_dec(&key->user->nikeys);
- /* now throw away the key memory */
- if (key->type->destroy)
- key->type->destroy(key);
-
key_user_put(key->user);
kfree(key->description);