From nobody Wed Feb 11 03:02:44 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.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 1DCC82DB7A8 for ; Tue, 10 Feb 2026 02:47:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770691679; cv=none; b=A64v/4uBcysuhPQF3hEOOnY2rdsLaS+IrG9RKoJeamosH+NV7jtp97EsF6RYu7F1Fs52P3QlVM3+lCR4WAQxU0GkG6a9mxRu6ASwB/pxMmfn9PkrdF9XM2I98g4CK1QRKaENhURJUEX30hwlyylwUe/F5Gy/n4xoPS6fXBafLW4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770691679; c=relaxed/simple; bh=h+JnRI8smI0eCXdUK54XyM6HFxQxQx3HmRZnOYLL2xA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=LPkND4CUfdQOj4eWZkOmbL1QsUY0tMG2XhwsNVBFlSvBz5/yY0fRRrPyeiZBaDC9wfqpvBmOrUUeOoqF19GyBNe2vsycw89g5yCM9rDl06v0jAjgg9oQhrVgqePZFyeDA4mJzKcpw0M4xBE7ijAwL9NEWseEQ9GAUs9HPbdOq5s= 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=dKFN8JjR; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=jW79TEZz; arc=none smtp.client-ip=205.220.168.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="dKFN8JjR"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="jW79TEZz" Received: from pps.filterd (m0279862.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 619IRP423253955 for ; Tue, 10 Feb 2026 02:47:57 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=WobcuadDUEwcwFCrS42OUs ld9H6nDDwqCccmcCmcFak=; b=dKFN8JjR4ee1h6sLwKH52X07CVFZGI4SOdqesK 8GMrswRp1to6tHFf1sTMpefWSu7E1aZZCkj/74SyZLJ6ZPn0COz9D519RiUAlKRl mGkhsXdWvLN3Bbj98pZOzqKqUxY4D2pbnvcPhi/EQI+dek2PIVMr2Rrl4+pNzFGs ZtDwcj+00K9nZHmtPOJdIksVAmCX+cCBlUwqoo1mTTLmD5z9XAzfoYQ2JQreGjFK nXJAgETqqkQr71moZzggR7tfGvjwdynf4Bl3l3TgVQ4as+DsWnRMKQbRZqCgeJhU iKV+NTyP1SobnlaAboVe4m/sGTgThGnev8+UmAv8EQvOataA== Received: from mail-dy1-f198.google.com (mail-dy1-f198.google.com [74.125.82.198]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4c79f6c0e9-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 10 Feb 2026 02:47:57 +0000 (GMT) Received: by mail-dy1-f198.google.com with SMTP id 5a478bee46e88-2ba87c0e198so336689eec.1 for ; Mon, 09 Feb 2026 18:47:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1770691676; x=1771296476; 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=WobcuadDUEwcwFCrS42OUsld9H6nDDwqCccmcCmcFak=; b=jW79TEZz9EFdQ/tdS7qW3ue4H4nw3npaVj0wcp32arHmgINm6Ci4T1T1orGlcok8N6 ztbVA4L4Atrgy4Sa4445D84eAfDmFUHcThaX5HVL19CN71qSF47vgg70mvn8R8Axt7U8 VGb4r0k24Sb39yzr23ejrR/fix02PRqO4Vu7sSP5jV6uHEE753jHieZEKFIjsD+Wcf6l JAy4mOV922oJkqH8jUPGunb/2SI4t4G0Tjie4xgfjqS/K8+53PT3I76qVPi8Op+72zxY JDOZw171lDTYnkDiWfKKdc6EKrT486QxKnbtbMOep8QngZVIiJTEc6JL+ZOLJjGx/H+n NCSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770691676; x=1771296476; 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=WobcuadDUEwcwFCrS42OUsld9H6nDDwqCccmcCmcFak=; b=spd92vnVlFA14b48Lm5YYwoAGzMdAyhQaeR9lwu6ovJZGg/GbxTYzxMBZ9j/mf6hck UjUm4mfEWUuvS2Pk570Mw6RIIv45MyJBmaVzpaRqOo4z51xau2pn4/lJz3ASq/U/o/X5 XJKnUed5ZfEF1JurBhDCfD2Iko92ysV0iGb7n7GGjB9gLm819AeCDVID/J5CgJJJFjDV jxZ/KGdz3+8VOhOG/yvFyLtUkaUP0op5ziDlY+Q6tCobArKJhTuw3jjbL8nEEbfQlLiw SOyk1YyfmkzmqdnrCtR7jmSClP25tTll7VYg7D4AI7KWjd7kyw7fCXVAOuGIiUurLlLO UkAA== X-Forwarded-Encrypted: i=1; AJvYcCVnSfKZrF75FFXJBJog7IgdViZn1eBtes/2w6lHWBl4IANd0upQcfMM0bLt1MkcZ0pJUaOQUcuBkxn8Zo0=@vger.kernel.org X-Gm-Message-State: AOJu0Ywc/F7kFdUm/+BJdIqULCv1Varzs80mn0aIOF4UuSHUWZDZffLz TJJjbgQVamDhRK8sAy+IHBNE/jCCSl/5I3Seb7m3WBvh2Ytj/9A3KqCv3sc+ze3aJ5KVWgsqBOC tBHSBgyrrJiVq+nAITywClphV0AmtgnlWTWbOjtFTRLSjD3DIiK/XPOu4wY4HvZAl61MUEmjItQ == X-Gm-Gg: AZuq6aIATVXw/i6D98SUYFpgFAmRZYrvjVAdMvB17qefPnd2IAMRKVkH0o/3IQUt/yB DS5spLbewWSaXvCE2k4FeTnNcZevgAWt/OpwVtL5UD5DE8hUqUhYsBOff/Q9YZZ22ER9hQQpTGe qSc4eRZqz3VHu+zcolEKcxHVhEtDppYZWxg7+O4Gax0UxEDu0ohkgyjp3NN/JVOmurgppEPBuMZ AVcJ9JHFCdQIo6PJSVWQ9Am1lUG/2ByVPTKRo1LOIIS9A81pbgOzykY2x/NuJdmSjqVXEbcUDzE hzD5VZIyKzp6tFfA0jT1tgQ+00RRKCFVXiToVlmflDPnQqkMS/uFPvgU0cEmcmHKsWSn2wzc0uc H6UgiFKhh88lEqx9xge6pbL2VnRbzMteXymT2fYOpizQbT3j2Vmuig2kK8cb6wt7ka/4ywbRIFr txE25w X-Received: by 2002:a05:7300:570d:b0:2ba:7a5f:9e54 with SMTP id 5a478bee46e88-2ba8a867c13mr300248eec.42.1770691676149; Mon, 09 Feb 2026 18:47:56 -0800 (PST) X-Received: by 2002:a05:7300:570d:b0:2ba:7a5f:9e54 with SMTP id 5a478bee46e88-2ba8a867c13mr300221eec.42.1770691674894; Mon, 09 Feb 2026 18:47:54 -0800 (PST) Received: from hu-azarrabi-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2b855c8a8f6sm8673747eec.32.2026.02.09.18.47.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Feb 2026 18:47:54 -0800 (PST) From: Amirreza Zarrabi Date: Mon, 09 Feb 2026 18:47:39 -0800 Subject: [PATCH v4] 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: <20260209-fix-use-after-free-v4-1-7c4c4b02368f@oss.qualcomm.com> X-B4-Tracking: v=1; b=H4sIAEqcimkC/3XOwQqDMAwG4FeRnldpq7W6095j7FA1mYWpW6uyI b77oiDs4C6BPyRfMrMA3kFg52hmHiYXXN9RSE8Rqxrb3YG7mjJTQmmRiZSje/MxALc4gOfoAXi OKEtd69qYlNHi0wNNbej1RrlxYej9Z7sxybW7c/qImySX3BpRq6REVGl+6UOIX6N9VH3bxlTYq k7qR5LmUFIkSSzRIlS6kOaPlOxSJqTKD6WEpFKYPMvosUIdScuyfAH8G67RTwEAAA== 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-GUID: Ay1Cq350qSH1FSAKsVrrwJWqSgPxrLRJ X-Proofpoint-ORIG-GUID: Ay1Cq350qSH1FSAKsVrrwJWqSgPxrLRJ X-Authority-Analysis: v=2.4 cv=W581lBWk c=1 sm=1 tr=0 ts=698a9c5d cx=c_pps a=wEP8DlPgTf/vqF+yE6f9lg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=HzLeVaNsDn8A:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=Mpw57Om8IfrbqaoTuvik:22 a=GgsMoib0sEa3-_RKJdDe:22 a=VwQbUJbxAAAA:8 a=EUspDBNiAAAA:8 a=6MCoFBzevOMPZS9IYwYA:9 a=QEXdDO2ut3YA:10 a=bBxd6f-gb0O0v-kibOvt:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjEwMDAyMiBTYWx0ZWRfXyLbkeUaVx35g Ge6NDuQokGlxX7V2zBG5+NmXMUjhHtl43oyonWS4L4PIRMvd0+T2nUhMP5Ql1bZcLeqecVPljod e/2yq2SUaioBOh/mEwiGyX7i6S+Hliq8jVs3wJyG83g7Nl6ZwfMQBxlPaRDw1sW2NjXWuvxh1Ky yHr/XELqGnUQpyfZYJ2msLg/yEIWDtU8jNT4jwP2H9PEEZetyIe7Azet1ZtwbfyDI2J/HzM0wpp Pz2yVabty2mn+y6JHZIGSRdElX08dWF3/ezJWDsSl1ua41HqLQ3QsbVfmU5PGuUT6u86huvOadq Yh4vqnHpUVoBjo5JX8TMQYpkYy7itPNBX2/JeHX3Chrb8H6GZZ9lXsdOJqdZF3iPgiPOKV557md wG8BCAUKUkbjnxRmIHC9keo0okNOESeKSMU1X6m4MH8jUFjfB1SnWtf0QZU42n2kw3lpkSvZMBY ukWQ1T7uHbyDPI6jFqw== 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-02-09_01,2026-02-09_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 spamscore=0 bulkscore=0 lowpriorityscore=0 phishscore=0 impostorscore=0 adultscore=0 malwarescore=0 clxscore=1015 suspectscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2601150000 definitions=main-2602100022 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 v4: - Pre-allocate request ID when allocating the request. - Cleanup the loop in optee_supp_recv(). - Update the return value for revoked request from -ENOENT to -EBADF. - Link to v3: https://lore.kernel.org/r/20260128-fix-use-after-free-v3-1-b0= 786670d927@oss.qualcomm.com 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 | 106 ++++++++++++++++++++++++++++++++-----------= ---- 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c index d0f397c90242..c1ae76df7067 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 revoked pending request in supp->idr. = */ +#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF)) + void optee_supp_init(struct optee_supp *supp) { memset(supp, 0, sizeof(*supp)); @@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp) { int id; struct optee_supp_req *req; - struct optee_supp_req *req_tmp; =20 mutex_lock(&supp->mutex); =20 - /* Abort all request retrieved by supplicant */ + /* Abort all request */ idr_for_each_entry(&supp->idr, req, id) { idr_remove(&supp->idr, id); - req->ret =3D TEEC_ERROR_COMMUNICATION; - complete(&req->c); - } + /* Skip if request was already marked invalid */ + if (IS_ERR(req)) + continue; =20 - /* Abort all queued requests */ - list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) { - list_del(&req->link); - req->in_queue =3D false; + /* For queued requests where supplicant has not seen it */ + if (req->in_queue) { + list_del(&req->link); + req->in_queue =3D false; + } + + req->processed =3D true; req->ret =3D TEEC_ERROR_COMMUNICATION; complete(&req->c); } @@ -93,6 +102,12 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 fu= nc, size_t num_params, if (!req) return TEEC_ERROR_OUT_OF_MEMORY; =20 + req->id =3D idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); + if (req->id < 0) { + kfree(req); + return TEEC_ERROR_OUT_OF_MEMORY; + } + init_completion(&req->c); req->func =3D func; req->num_params =3D num_params; @@ -102,6 +117,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 +133,43 @@ 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. */ + idr_remove(&supp->idr, req->id); 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. req is not + * in supp->reqs (removed by supp_pop_entry()) nor in + * supp->idr (removed by supp_pop_req()). + */ + 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,10 +191,6 @@ static struct optee_supp_req *supp_pop_entry(struct o= ptee_supp *supp, return ERR_PTR(-EINVAL); } =20 - *id =3D idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL); - if (*id < 0) - return ERR_PTR(-ENOMEM); - list_del(&req->link); req->in_queue =3D false; =20 @@ -214,7 +248,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 +257,11 @@ 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); + req =3D supp_pop_entry(supp, *num_params - num_meta); + if (req) + break; /* Keep mutex held. */ mutex_unlock(&supp->mutex); =20 - if (req) { - if (IS_ERR(req)) - return PTR_ERR(req); - break; - } - /* * If we didn't get a request we'll block in * wait_for_completion() to avoid needless spinning. @@ -245,6 +274,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func= , u32 *num_params, return -ERESTARTSYS; } =20 + /* supp->mutex held and req !=3D NULL. */ + + if (IS_ERR(req)) { + mutex_unlock(&supp->mutex); + return PTR_ERR(req); + } + if (num_meta) { /* * tee-supplicant support meta parameters -> requsts can be @@ -252,13 +288,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *fun= c, u32 *num_params, */ param->attr =3D TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | TEE_IOCTL_PARAM_ATTR_META; - param->u.value.a =3D id; + param->u.value.a =3D req->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); + supp->req_id =3D req->id; } =20 *func =3D req->func; @@ -266,6 +300,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func,= u32 *num_params, memcpy(param + num_meta, req->param, sizeof(struct tee_param) * req->num_params); =20 + mutex_unlock(&supp->mutex); return 0; } =20 @@ -297,12 +332,17 @@ 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,10 +368,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, = u32 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)) { - /* Something is wrong, let supplicant restart. */ + mutex_unlock(&supp->mutex); + /* Something is wrong, let supplicant handel it. */ return PTR_ERR(req); } =20 @@ -355,9 +394,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