From: sashiko-bot@kernel.org
To: "Sumit Garg" <sumit.garg@kernel.org>
Cc: dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v8 03/14] firmware: qcom: Add a PAS TEE service
Date: Sat, 27 Jun 2026 13:42:28 +0000 [thread overview]
Message-ID: <20260627134229.2B72D1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260626133440.692849-4-sumit.garg@kernel.org>
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [Critical] Heap buffer overflow in `qcom_pas_tee_get_rsc_table` when copying the input resource table.
- [High] Out-of-bounds read and info leak in `qcom_pas_tee_get_rsc_table` when duplicating the returned resource table.
- [High] The first TEE invocation fails to pass the input resource table data to the TA, resulting in an invalid parameter error.
- [High] Unsynchronized mutation of the global operations structure and unconditional unregistration during remove.
- [Medium] The `output_rt_size` pointer is left uninitialized if the TEE returns a size of 0.
- [Medium] The driver incorrectly treats the expected `TEEC_ERROR_SHORT_BUFFER` response as a fatal error.
Pre-existing issues:
- [High] Missing protection for `ops_ptr` reads causes a TOCTOU NULL pointer dereference.
--
commit f2659330f38d92cd91647244dc269a73194079c0
Author: Sumit Garg <sumit.garg@oss.qualcomm.com>
firmware: qcom: Add a PAS TEE service
This patch adds support for a Peripheral Authentication Service (PAS)
driver based on the TEE bus, using OP-TEE as the backend implementation.
> diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c
> new file mode 100644
> index 0000000000000..a2ba3af05a502
> --- /dev/null
> +++ b/drivers/firmware/qcom/qcom_pas_tee.c
[ ... ]
> +static void *qcom_pas_tee_get_rsc_table(struct device *dev,
> + struct qcom_pas_context *ctx,
> + void *input_rt, size_t input_rt_size,
> + size_t *output_rt_size)
> +{
> + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> + struct tee_ioctl_invoke_arg inv_arg = {
> + .func = TA_QCOM_PAS_GET_RESOURCE_TABLE,
> + .session = data->session_id,
> + .num_params = TEE_NUM_PARAMS
> + };
> + struct tee_param param[4] = {
> + [0] = {
> + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
> + .u.value.a = ctx->pas_id,
> + },
> + [1] = {
> + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT,
> + .u.memref.size = input_rt_size,
> + }
> + };
[Severity: High]
Does this first tee_client_invoke_func() invocation pass an invalid memory
reference to the TA?
In qcom_pas_tee_get_rsc_table(), param[1] is initialized with
u.memref.size = input_rt_size, but u.memref.shm is left uninitialized (NULL).
If the firmware has an embedded input resource table (input_rt_size > 0), will
the TEE subsystem reject this call with an invalid parameter error before the
TA is even invoked?
> + void *rt_buf = NULL;
> + int ret;
> +
> + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> + if (ret < 0 || inv_arg.ret != 0) {
[Severity: Medium]
Will this error check abort the loading process if the TA follows the standard
GlobalPlatform TEE Client API specification?
When queried for a buffer size, a standard TA is expected to return
TEEC_ERROR_SHORT_BUFFER (a non-zero error code) since the initial buffer is
NULL or too small. Since this check treats any non-zero inv_arg.ret as a
failure, does this prevent the code from proceeding to the second pass to
allocate the correctly sized buffer?
> + dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
> + ctx->pas_id, ret, inv_arg.ret);
> + return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
> + }
> +
> + if (param[1].u.memref.size) {
[Severity: Medium]
Is it possible for output_rt_size to remain uninitialized here?
If the TA legitimately returns param[1].u.memref.size as 0 during the first
invocation (indicating no resources), this block is skipped and the function
returns NULL. Since output_rt_size is never assigned a value, callers like
those in qcom_q6v5_pas.c might read garbage stack data for the table size.
> + struct tee_shm *rt_shm __free(shm_free) =
> + tee_shm_alloc_kernel_buf(data->ctx,
> + param[1].u.memref.size);
> + void *rt_shm_va;
> +
> + if (IS_ERR_OR_NULL(rt_shm)) {
> + dev_err(dev, "rt_shm allocation failed\n");
> + rt_shm = NULL;
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + rt_shm_va = tee_shm_get_va(rt_shm, 0);
> + if (IS_ERR(rt_shm_va)) {
> + dev_err(dev, "rt_shm get VA failed\n");
> + return ERR_CAST(rt_shm_va);
> + }
> + memcpy(rt_shm_va, input_rt, input_rt_size);
[Severity: Critical]
Can this memcpy overflow the allocated rt_shm buffer?
The rt_shm buffer is allocated using the size requested by the TA from the
first invocation (param[1].u.memref.size). However, this memcpy
unconditionally copies input_rt_size bytes. If the TA returns a size smaller
than input_rt_size, wouldn't this write past the bounds of the allocated
kernel heap buffer?
> +
> + param[1].u.memref.shm = rt_shm;
> + ret = tee_client_invoke_func(data->ctx, &inv_arg, param);
> + if (ret < 0 || inv_arg.ret != 0) {
> + dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n",
> + ctx->pas_id, ret, inv_arg.ret);
> + return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL);
> + }
> +
> + if (param[1].u.memref.size) {
> + *output_rt_size = param[1].u.memref.size;
> + rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL);
[Severity: High]
Could this kmemdup read out of bounds of the initially allocated rt_shm
buffer?
During the second tee_client_invoke_func() call, the TA can update
param[1].u.memref.size to a value larger than the initially allocated rt_shm
capacity. If output_rt_size is updated to this larger value, kmemdup will read
past the end of the rt_shm_va buffer, potentially leaking adjacent sensitive
kernel heap data to the caller.
> + if (!rt_buf)
> + return ERR_PTR(-ENOMEM);
> + }
> + }
> +
> + return rt_buf;
> +}
[ ... ]
> +static int qcom_pas_tee_probe(struct tee_client_device *pas_dev)
> +{
[ ... ]
> + data->session_id = sess_arg.session;
> + dev_set_drvdata(dev, data);
> + qcom_pas_ops_tee.dev = dev;
> + qcom_pas_ops_register(&qcom_pas_ops_tee);
[Severity: High]
Is it safe to mutate the static qcom_pas_ops_tee.dev singleton without
synchronization?
If qcom_pas_ops_register() is called when another backend (like SCM) is
already registered, it fails silently but the probe still succeeds.
Could this lead to conflicting states if multiple backends probe concurrently?
[Severity: High]
This isn't a bug introduced by this patch, but is there a TOCTOU race
condition when reading ops_ptr in qcom_pas.c?
In functions like qcom_pas_init_image(), ops_ptr is checked for NULL and
subsequently dereferenced:
if (!ops_ptr)
return -ENODEV;
return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx);
Since ops_ptr is not protected by RCU, a lock, or READ_ONCE(), a concurrent
call to qcom_pas_ops_unregister() (e.g., via module unload) can set ops_ptr to
NULL between the check and the dereference, causing a NULL pointer
dereference.
> +
> + return ret;
> +}
> +
> +static void qcom_pas_tee_remove(struct tee_client_device *pas_dev)
> +{
> + struct device *dev = &pas_dev->dev;
> + struct qcom_pas_tee_private *data = dev_get_drvdata(dev);
> +
> + qcom_pas_ops_unregister();
[Severity: High]
Does this unconditional unregister break the SCM backend?
If the TEE module is unloaded, qcom_pas_tee_remove() forcefully clears the
global ops_ptr. If the SCM backend was the active registered backend instead
of TEE, wouldn't this destroy the active SCM registration and break PAS
functionality globally?
> + tee_client_close_session(data->ctx, data->session_id);
> + tee_client_close_context(data->ctx);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260626133440.692849-1-sumit.garg@kernel.org?part=3
next prev parent reply other threads:[~2026-06-27 13:42 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-26 13:34 [PATCH v8 00/14] firmware: qcom: Add OP-TEE PAS service support Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-26 13:34 ` [PATCH v8 01/14] firmware: qcom: Add a generic PAS service Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 02/14] firmware: qcom_scm: Migrate to " Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-26 17:05 ` Julian Braha
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 03/14] firmware: qcom: Add a PAS TEE service Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-27 13:42 ` sashiko-bot [this message]
2026-06-26 13:34 ` [PATCH v8 04/14] remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 05/14] remoteproc: qcom_q6v5_mss: Switch " Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 06/14] remoteproc: qcom_wcnss: " Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 07/14] remoteproc: qcom: Select QCOM_PAS generic service Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 08/14] drm/msm: Switch to generic PAS TZ APIs Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 09/14] media: qcom: " Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 10/14] media: qcom: Pass proper PAS ID to set_remote_state API Sumit Garg via OP-TEE
2026-06-26 13:34 ` Sumit Garg
2026-06-26 13:34 ` [PATCH v8 11/14] net: ipa: Switch to generic PAS TZ APIs Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 12/14] wifi: ath12k: " Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-27 13:42 ` sashiko-bot
2026-06-26 13:34 ` [PATCH v8 13/14] firmware: qcom_scm: Remove SCM PAS wrappers Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
2026-06-26 13:34 ` [PATCH v8 14/14] MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service Sumit Garg
2026-06-26 13:34 ` Sumit Garg via OP-TEE
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260627134229.2B72D1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sumit.garg@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.