remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers

[ Upstream commit 57f72170a2 ]

Any access to the dynamically allocated metadata region by the application
processor after assigning it to the remote Q6 will result in a XPU
violation. Fix this by replacing the dynamically allocated memory region
with a no-map carveout and unmap the modem metadata memory region before
passing control to the remote Q6.

Reported-and-tested-by: Amit Pundir <amit.pundir@linaro.org>
Fixes: 6c5a9dc248 ("remoteproc: qcom: Make secure world call for mem ownership switch")
Signed-off-by: Sibi Sankar <quic_sibis@quicinc.com>
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230117085840.32356-7-quic_sibis@quicinc.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Sibi Sankar 2023-01-17 14:28:35 +05:30 коммит произвёл Greg Kroah-Hartman
Родитель bd57756a7e
Коммит d4f4aa9ec1
1 изменённых файлов: 53 добавлений и 6 удалений

Просмотреть файл

@ -17,6 +17,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
@ -192,6 +193,9 @@ struct q6v5 {
size_t mba_size; size_t mba_size;
size_t dp_size; size_t dp_size;
phys_addr_t mdata_phys;
size_t mdata_size;
phys_addr_t mpss_phys; phys_addr_t mpss_phys;
phys_addr_t mpss_reloc; phys_addr_t mpss_reloc;
size_t mpss_size; size_t mpss_size;
@ -832,15 +836,35 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
if (IS_ERR(metadata)) if (IS_ERR(metadata))
return PTR_ERR(metadata); return PTR_ERR(metadata);
if (qproc->mdata_phys) {
if (size > qproc->mdata_size) {
ret = -EINVAL;
dev_err(qproc->dev, "metadata size outside memory range\n");
goto free_metadata;
}
phys = qproc->mdata_phys;
ptr = memremap(qproc->mdata_phys, size, MEMREMAP_WC);
if (!ptr) {
ret = -EBUSY;
dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n",
&qproc->mdata_phys, size);
goto free_metadata;
}
} else {
ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs);
if (!ptr) { if (!ptr) {
kfree(metadata); ret = -ENOMEM;
dev_err(qproc->dev, "failed to allocate mdt buffer\n"); dev_err(qproc->dev, "failed to allocate mdt buffer\n");
return -ENOMEM; goto free_metadata;
}
} }
memcpy(ptr, metadata, size); memcpy(ptr, metadata, size);
if (qproc->mdata_phys)
memunmap(ptr);
/* Hypervisor mapping to access metadata by modem */ /* Hypervisor mapping to access metadata by modem */
mdata_perm = BIT(QCOM_SCM_VMID_HLOS); mdata_perm = BIT(QCOM_SCM_VMID_HLOS);
ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, true, ret = q6v5_xfer_mem_ownership(qproc, &mdata_perm, false, true,
@ -869,7 +893,9 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
"mdt buffer not reclaimed system may become unstable\n"); "mdt buffer not reclaimed system may become unstable\n");
free_dma_attrs: free_dma_attrs:
if (!qproc->mdata_phys)
dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs); dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs);
free_metadata:
kfree(metadata); kfree(metadata);
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
@ -1615,6 +1641,7 @@ static int q6v5_init_reset(struct q6v5 *qproc)
static int q6v5_alloc_memory_region(struct q6v5 *qproc) static int q6v5_alloc_memory_region(struct q6v5 *qproc)
{ {
struct device_node *child; struct device_node *child;
struct reserved_mem *rmem;
struct device_node *node; struct device_node *node;
struct resource r; struct resource r;
int ret; int ret;
@ -1661,6 +1688,26 @@ static int q6v5_alloc_memory_region(struct q6v5 *qproc)
qproc->mpss_phys = qproc->mpss_reloc = r.start; qproc->mpss_phys = qproc->mpss_reloc = r.start;
qproc->mpss_size = resource_size(&r); qproc->mpss_size = resource_size(&r);
if (!child) {
node = of_parse_phandle(qproc->dev->of_node, "memory-region", 2);
} else {
child = of_get_child_by_name(qproc->dev->of_node, "metadata");
node = of_parse_phandle(child, "memory-region", 0);
of_node_put(child);
}
if (!node)
return 0;
rmem = of_reserved_mem_lookup(node);
if (!rmem) {
dev_err(qproc->dev, "unable to resolve metadata region\n");
return -EINVAL;
}
qproc->mdata_phys = rmem->base;
qproc->mdata_size = rmem->size;
return 0; return 0;
} }