dri-devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
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

  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