remoteproc: qcom_q6v5_mss: Use a carveout to authenticate modem headers
[ Upstream commit57f72170a2
] 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:
Родитель
bd57756a7e
Коммит
d4f4aa9ec1
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче