From nobody Mon Feb 9 07:39:36 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1A16B2BE029 for ; Thu, 29 Jan 2026 03:22:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769656959; cv=none; b=TQgFfn/8i1WgOpGlblbRadgfdrKWChjfRBeFvMcUxD6KuIlORoDia5rfhcIr3BpsPxe021mcVDvBWpOOkx4PpSEGDvKjkGgVnaiM6lMRAulZaQnzUBHp9IBl7pwBrBM36lWCzzJdF7P+SZ/rXzyv2inzWDXjYx2+SWpJOh9n9r8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769656959; c=relaxed/simple; bh=K6xHAGvgu/oTkp0qkaSIMKOft3xeCJMfJ9YElrFUBq4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=DbwFib+QUkDAGipuCc+meR/zcQw3Qf4z0d0KqSeX77doYPKEFX7Bgv0gwqiHaOeB7wVVPDrdQQRX/ftNIrxZuD0ZwlYKbzxE5cbhaZTnW6onXblNdIU6rSeD0WSbimJTOCh2f72O5taos7lkgX3HVE7+jIUq+sBjfi5v700lY/c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=k+Ms+3GB; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=XhYPKEt6; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="k+Ms+3GB"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="XhYPKEt6" Received: from pps.filterd (m0279872.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 60T2oi8l2033208 for ; Thu, 29 Jan 2026 03:22:36 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:message-id :mime-version:subject:to; s=qcppdkim1; bh=EGC6VyU3/KJZdVzczXkLfj sqQ9gqC5V6TvXxA7UoqKY=; b=k+Ms+3GBUaK4qeBkSHi9DxqKaczhPGv5bivkP6 vP6Le9UXyd0vYPLigYwNWB3V5X4mI93nJb+h/Uy8CX6wHl2Ccm/wBqBqYj5HAqTU XO1wRMXy2wR8aDhMlgUDeVSEY46IQziGkhFUwbYppj1ycSZygckeFaA8q3KVeg/5 wlIY1LI9avvtC6w0/6VmKsKjH4LJpJr22iWJLd9m3nHr7XcPIgE7g9kZcNhHcK+F QjEk2Ysg82p0Vzhmhxf6ITlMqPKa+C0fj0r5kxSZ0cH1uWL285DnfzUR7AVb+th5 /8mwkIybMsT5/6czEz8jX2HFUZIFzDLZZXiJMMoiJCH8KjoQ== Received: from mail-dl1-f69.google.com (mail-dl1-f69.google.com [74.125.82.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4bytqy0tus-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Thu, 29 Jan 2026 03:22:35 +0000 (GMT) Received: by mail-dl1-f69.google.com with SMTP id a92af1059eb24-124aa710af7so3399100c88.1 for ; Wed, 28 Jan 2026 19:22:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1769656955; x=1770261755; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=EGC6VyU3/KJZdVzczXkLfjsqQ9gqC5V6TvXxA7UoqKY=; b=XhYPKEt659qIRf4gt/nVgR4wK1w5VHX3QRtWum/TlAiFKePIw8GNlghq600MNYBgtS ct9DImagRW3TPHSLku1QboA+hg4hyUY6jImQFyp92rgcCFPdswfXTS0cNCXWNlZkGN6w N37Ci/KvdS0t+dPLkFJykoOOyVcZDgmkyhshbS/UncSI+wXdoRuDxQ90C6zVD/9HisU5 GZRbhcFsY5HI2K8CT2kIZrd09Fev8IA4JFxJiYdAxG1Wiwp3Udb1+9hwm4q9Xq00s5fo JvQT1ERkHijj/nhxCqaZvhFVkn1Taxf0+XBgSec/PzRkFlEKHweC1w3nyqBq8Q6H1bpR D1/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769656955; x=1770261755; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=EGC6VyU3/KJZdVzczXkLfjsqQ9gqC5V6TvXxA7UoqKY=; b=kDqzNCkh01+jaG266KkHkiLWQXK7uGlS37BfQTV6cwD680GV9ETiZA9gNvKfNfzTyi vPpfAM1/qCPhx6UFu4KtqUbnh1dUTocns4vwbK8xAJiBidCvLJz6le8LapkX2YpW121/ JqIFj0bDeKTuVHQCyx0yoOJBeSBUdkh91PdcnybeeWnADjDMgqxNtMUAcs10PTZfXE5l jRtrmmm1it7/xdITrLIpwy8nK9wZsOtb04LIKDjay8gDpnp+3gifb45uhIpBEY/9irBd v2EgbokfN2yoJOAH5DV7zLCOgdq9j6cEVxzmxqUZAzqDQ41y1FiQdwjgwBUw3LV6VJw2 fmgQ== X-Forwarded-Encrypted: i=1; AJvYcCVx+aBz3eFy70ntcqJr9m20fxlboi4hWTRprIsrlm93IKxZ635BqK9cmwLxNmkyfbX10B8xzAkzm3N/M8o=@vger.kernel.org X-Gm-Message-State: AOJu0YwngdwM+5VmKyntvhCtGYD+35DR10IZrntKm3Aua4dYK8OiCVnA /KvIjI5aaj4f9E9+TkAd0OZb6ZByggxhrvfxvuod5u3piRDxuKZOhkSE1NYKBuCJnntRICpGTWj yY11YbZnAb35H9mf32g2Xw80r2j1KoMJ01YDp52GPeCSi2DVpBgLGiV/CXdlSUU1vOg== X-Gm-Gg: AZuq6aLEBLqZUfQg8OxQXHaqTHEkmy/UpZtqVHxShYdkCWaygfbhgFbDU+y1jzZ5FMo 1oM9JzX5Ta3vzue/xxUlhppqqKv2d6Q+nv3bElj8uscrSagbUscxswggfhQ9/PFmdDRwobwF5Mp Rh1VTkP5ppj8RstXcbGY9XqpILmtF4EOEQ5qBfRqDrk56AFbzV+/6Sz57//9KAbGUvmFJ0QXYc6 4dL+SeGc1cb8DPGKGznHSRb+9stevM/Yis+Du+YAlRxdGV0mAXe2Gy0gFT1ggpncDmH1hBZn/at Bji5/OsLOfHA+WG2l5bWIdSaMimO8cfgjLC0cwwAjm6dLDjuXYImpu+DqjWT+T3KYog0aRwOa7s MEsjl1uvPImV/mUDaWenXBqPTtbtNHv14j6cl0qQL4MmrvWCIsg2cKD3FUM1zVThhGWsZ X-Received: by 2002:a05:7022:41a7:b0:11a:f5e0:dc8 with SMTP id a92af1059eb24-124a00aeb09mr3570773c88.28.1769656954830; Wed, 28 Jan 2026 19:22:34 -0800 (PST) X-Received: by 2002:a05:7022:41a7:b0:11a:f5e0:dc8 with SMTP id a92af1059eb24-124a00aeb09mr3570755c88.28.1769656954128; Wed, 28 Jan 2026 19:22:34 -0800 (PST) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-124a9efd3b8sm4740532c88.17.2026.01.28.19.22.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 28 Jan 2026 19:22:33 -0800 (PST) From: Amirreza Zarrabi Date: Wed, 28 Jan 2026 19:22:20 -0800 Subject: [PATCH v3] tee: optee: prevent use-after-free when the client exits before the supplicant Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260128-fix-use-after-free-v3-1-b0786670d927@oss.qualcomm.com> X-B4-Tracking: v=1; b=H4sIAGvSemkC/23NwQ6CMAwG4FchO1vCBnPoyfcwHgZrZYkw3WDRE N7dQWLigUuTv/n7dWYBvcXAztnMPEYbrBtSKA8Zazs93BGsSZmJQsjiWFRA9g1TQNA0ogfyiFA T8UYaaZSqWDp8ekytDb3eUu5sGJ3/bD8iX7c/Tu5xkQMHrQojyoZIVPXFhZC/Jv1oXd/nabBVj eJP4mpXEkni1JAmbOWJqx1pWZYvLNZWAgUBAAA= To: Jens Wiklander , Sumit Garg , Arnd Bergmann Cc: Michael Wu , linux-arm-msm@vger.kernel.org, op-tee@lists.trustedfirmware.org, linux-kernel@vger.kernel.org, Amirreza Zarrabi X-Mailer: b4 0.13.0 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMTI5MDAxOSBTYWx0ZWRfX//w8lofJ70oW z5f58uusby1xnxC3b++sXxUIJZH4yvmo3mS2Ib9MzBjNAamrVDJ9fvLVjW3FuXIx8V9XfVNWoLW qpdcvfchUBhmiTtlzoy5GOVe9cAT6tvbtAg132m6Mh00BuCXAaoOzU7A77zuHccfln6M2PfLHzE vV3p6ReJCbWWDqIJxqi6eMQuhtSU75QnU+BFyWYW808lxNdIt2dRIuKE/2QK5yFJdSO3xPRO68Z yz3wU8uqUD0itbiSQv6WpR3DjJrsDmwElckK87puntWpdx89Fh3NeXGlWVJkhQt8JGr4n0I2Njw ibW/Fzfxqp19Gp9A0/TT6rjkOA7yP+dwrghg3Rxq0C9sQVRfrUd7FTK/bV4VNdofYvM/HvWaO8j ffmGQenlLbe18WLNIdno6O08y3JKBxYtO5TBwb1f885Ubl47Fhg6tz121vn0fbRiQSrKS4B2W4K grOP+TCBiVYv5PvrSXA== X-Authority-Analysis: v=2.4 cv=Je2xbEKV c=1 sm=1 tr=0 ts=697ad27b cx=c_pps a=kVLUcbK0zfr7ocalXnG1qA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=vUbySO9Y5rIA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=VwQbUJbxAAAA:8 a=EUspDBNiAAAA:8 a=6MCoFBzevOMPZS9IYwYA:9 a=QEXdDO2ut3YA:10 a=vr4QvYf-bLy2KjpDp97w:22 X-Proofpoint-ORIG-GUID: xogtmvIG9Im-yD7Rl7IhTsY-OHn0EXEX X-Proofpoint-GUID: xogtmvIG9Im-yD7Rl7IhTsY-OHn0EXEX X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-01-28_06,2026-01-28_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 adultscore=0 priorityscore=1501 phishscore=0 lowpriorityscore=0 spamscore=0 impostorscore=0 clxscore=1011 bulkscore=0 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2601290019 Commit 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") made the client wait as killable so it can be interrupted during shutdown or after a supplicant crash. This changes the original lifetime expectations: the client task can now terminate while the supplicant is still processing its request. If the client exits first it removes the request from its queue and kfree()s it, while the request ID remains in supp->idr. A subsequent lookup on the supplicant path then dereferences freed memory, leading to a use-after-free. Serialise access to the request with supp->mutex: * Hold supp->mutex in optee_supp_recv() and optee_supp_send() while looking up and touching the request. * Let optee_supp_thrd_req() notice that the client has terminated and signal optee_supp_send() accordingly. With these changes the request cannot be freed while the supplicant still has a reference, eliminating the race. Fixes: 70b0d6b0a199 ("tee: optee: Fix supplicant wait loop") Signed-off-by: Amirreza Zarrabi --- Changes in v3: - Introduce processed flag instead of -1 for req->id. - Update optee_supp_release() as reported by Michael Wu. - Use mutex instead of guard. - Link to v2: https://lore.kernel.org/r/20250617-fix-use-after-free-v2-1-1f= bfafec5917@oss.qualcomm.com Changes in v2: - Replace the static variable with a sentinel value. - Fix the issue with returning the popped request to the supplicant. - Link to v1: https://lore.kernel.org/r/20250605-fix-use-after-free-v1-1-a7= 0d23bff248@oss.qualcomm.com --- drivers/tee/optee/supp.c | 122 +++++++++++++++++++++++++++++++++----------= ---- 1 file changed, 86 insertions(+), 36 deletions(-) diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c index d0f397c90242..0ec66008df19 100644 --- a/drivers/tee/optee/supp.c +++ b/drivers/tee/optee/supp.c @@ -10,7 +10,11 @@ struct optee_supp_req { struct list_head link; =20 + int id; + bool in_queue; + bool processed; + u32 func; u32 ret; size_t num_params; @@ -19,6 +23,9 @@ struct optee_supp_req { struct completion c; }; =20 +/* It is temporary request used for invalid pending request in supp->idr. = */ +#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-ENOENT)) + void optee_supp_init(struct optee_supp *supp) { memset(supp, 0, sizeof(*supp)); @@ -46,6 +53,10 @@ void optee_supp_release(struct optee_supp *supp) /* Abort all request retrieved by supplicant */ idr_for_each_entry(&supp->idr, req, id) { idr_remove(&supp->idr, id); + /* Skip if request was already marked invalid */ + if (IS_ERR(req)) + continue; + req->ret =3D TEEC_ERROR_COMMUNICATION; complete(&req->c); } @@ -102,6 +113,7 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 fu= nc, size_t num_params, mutex_lock(&supp->mutex); list_add_tail(&req->link, &supp->reqs); req->in_queue =3D true; + req->processed =3D false; mutex_unlock(&supp->mutex); =20 /* Tell an eventual waiter there's a new request */ @@ -117,21 +129,40 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 = func, size_t num_params, if (wait_for_completion_killable(&req->c)) { mutex_lock(&supp->mutex); if (req->in_queue) { + /* Supplicant has not seen this request yet. */ list_del(&req->link); req->in_queue =3D false; + + ret =3D TEEC_ERROR_COMMUNICATION; + } else if (req->processed) { + /* + * Supplicant has processed this request. Ignore the + * kill signal for now and submit the result. + */ + ret =3D req->ret; + } else { + /* + * Supplicant is in the middle of processing this + * request. Replace req with INVALID_REQ_PTR so that + * the ID remains busy, causing optee_supp_send() to + * fail on the next call to supp_pop_req() with this ID. + */ + idr_replace(&supp->idr, INVALID_REQ_PTR, req->id); + ret =3D TEEC_ERROR_COMMUNICATION; } + mutex_unlock(&supp->mutex); - req->ret =3D TEEC_ERROR_COMMUNICATION; + } else { + ret =3D req->ret; } =20 - ret =3D req->ret; kfree(req); =20 return ret; } =20 static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp, - int num_params, int *id) + int num_params) { struct optee_supp_req *req; =20 @@ -153,8 +184,8 @@ static struct optee_supp_req *supp_pop_entry(struct op= tee_supp *supp, return ERR_PTR(-EINVAL); } =20 - *id =3D idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); - if (*id < 0) + req->id =3D idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); + if (req->id < 0) return ERR_PTR(-ENOMEM); =20 list_del(&req->link); @@ -214,7 +245,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func,= u32 *num_params, struct optee *optee =3D tee_get_drvdata(teedev); struct optee_supp *supp =3D &optee->supp; struct optee_supp_req *req =3D NULL; - int id; size_t num_meta; int rc; =20 @@ -224,15 +254,48 @@ int optee_supp_recv(struct tee_context *ctx, u32 *fun= c, u32 *num_params, =20 while (true) { mutex_lock(&supp->mutex); - req =3D supp_pop_entry(supp, *num_params - num_meta, &id); - mutex_unlock(&supp->mutex); =20 - if (req) { - if (IS_ERR(req)) - return PTR_ERR(req); - break; + req =3D supp_pop_entry(supp, *num_params - num_meta); + if (!req) { + mutex_unlock(&supp->mutex); + goto wait_for_request; + } + + if (IS_ERR(req)) { + rc =3D PTR_ERR(req); + mutex_unlock(&supp->mutex); + + return rc; } =20 + /* + * Process the request while holding the lock, so that + * optee_supp_thrd_req() doesn't pull the request from under us. + */ + + if (num_meta) { + /* + * tee-supplicant support meta parameters -> + * requests can be processed asynchronously. + */ + param->attr =3D TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | + TEE_IOCTL_PARAM_ATTR_META; + param->u.value.a =3D req->id; + param->u.value.b =3D 0; + param->u.value.c =3D 0; + } else { + supp->req_id =3D req->id; + } + + *func =3D req->func; + *num_params =3D req->num_params + num_meta; + memcpy(param + num_meta, req->param, + sizeof(struct tee_param) * req->num_params); + + mutex_unlock(&supp->mutex); + return 0; + +wait_for_request: /* * If we didn't get a request we'll block in * wait_for_completion() to avoid needless spinning. @@ -243,29 +306,10 @@ int optee_supp_recv(struct tee_context *ctx, u32 *fun= c, u32 *num_params, */ if (wait_for_completion_interruptible(&supp->reqs_c)) return -ERESTARTSYS; - } =20 - if (num_meta) { - /* - * tee-supplicant support meta parameters -> requsts can be - * processed asynchronously. - */ - param->attr =3D TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | - TEE_IOCTL_PARAM_ATTR_META; - param->u.value.a =3D id; - param->u.value.b =3D 0; - param->u.value.c =3D 0; - } else { - mutex_lock(&supp->mutex); - supp->req_id =3D id; - mutex_unlock(&supp->mutex); + /* Check for the next request in the queue. */ } =20 - *func =3D req->func; - *num_params =3D req->num_params + num_meta; - memcpy(param + num_meta, req->param, - sizeof(struct tee_param) * req->num_params); - return 0; } =20 @@ -297,12 +341,18 @@ static struct optee_supp_req *supp_pop_req(struct opt= ee_supp *supp, if (!req) return ERR_PTR(-ENOENT); =20 + /* optee_supp_thrd_req() already returned to optee. */ + if (IS_ERR(req)) + goto failed_req; + if ((num_params - nm) !=3D req->num_params) return ERR_PTR(-EINVAL); =20 + *num_meta =3D nm; +failed_req: idr_remove(&supp->idr, id); supp->req_id =3D -1; - *num_meta =3D nm; + =20 return req; } @@ -328,9 +378,8 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u= 32 num_params, =20 mutex_lock(&supp->mutex); req =3D supp_pop_req(supp, num_params, param, &num_meta); - mutex_unlock(&supp->mutex); - if (IS_ERR(req)) { + mutex_unlock(&supp->mutex); /* Something is wrong, let supplicant restart. */ return PTR_ERR(req); } @@ -355,9 +404,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, = u32 num_params, } } req->ret =3D ret; - + req->processed =3D true; /* Let the requesting thread continue */ complete(&req->c); + mutex_unlock(&supp->mutex); =20 return 0; } --- base-commit: 3f24e4edcd1b8981c6b448ea2680726dedd87279 change-id: 20250604-fix-use-after-free-8ff1b5d5d774 Best regards, --=20 Amirreza Zarrabi