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: 48+ 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 ` [PATCH v8 01/14] firmware: qcom: Add a generic PAS service Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:14 ` Konrad Dybcio
2026-07-01 7:17 ` Sumit Garg
2026-06-30 12:21 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 02/14] firmware: qcom_scm: Migrate to " Sumit Garg
2026-06-26 17:05 ` Julian Braha
2026-07-01 7:21 ` Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:26 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 03/14] firmware: qcom: Add a PAS TEE service Sumit Garg
2026-06-27 13:42 ` sashiko-bot [this message]
2026-07-01 7:33 ` Sumit Garg
2026-06-26 13:34 ` [PATCH v8 04/14] remoteproc: qcom_q6v5_pas: Switch over to generic PAS TZ APIs Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:34 ` Konrad Dybcio
2026-07-01 7:35 ` Sumit Garg
2026-06-26 13:34 ` [PATCH v8 05/14] remoteproc: qcom_q6v5_mss: Switch " Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:35 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 06/14] remoteproc: qcom_wcnss: " Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:36 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 07/14] remoteproc: qcom: Select QCOM_PAS generic service Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:37 ` Konrad Dybcio
2026-07-01 5:36 ` Sumit Garg
2026-06-26 13:34 ` [PATCH v8 08/14] drm/msm: Switch to generic PAS TZ APIs Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:39 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 09/14] media: qcom: " Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:41 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 10/14] media: qcom: Pass proper PAS ID to set_remote_state API Sumit Garg
2026-06-30 12:42 ` Konrad Dybcio
2026-07-01 7:44 ` Sumit Garg
2026-07-01 11:01 ` Konrad Dybcio
2026-07-01 12:19 ` Sumit Garg
2026-06-26 13:34 ` [PATCH v8 11/14] net: ipa: Switch to generic PAS TZ APIs Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:43 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 12/14] wifi: ath12k: " Sumit Garg
2026-06-27 13:42 ` sashiko-bot
2026-06-30 12:44 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 13/14] firmware: qcom_scm: Remove SCM PAS wrappers Sumit Garg
2026-06-30 12:45 ` Konrad Dybcio
2026-06-26 13:34 ` [PATCH v8 14/14] MAINTAINERS: Add maintainer entry for Qualcomm PAS TZ service Sumit Garg
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox