2019-01-29 11:19:37 +05:30
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2019 Linaro Ltd .
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/kernel.h>
# include <linux/slab.h>
2024-03-25 16:11:01 +01:00
# include <linux/tee_core.h>
2019-01-29 11:19:37 +05:30
# include <linux/uuid.h>
# include "optee_private.h"
static int optee_ctx_match ( struct tee_ioctl_version_data * ver , const void * data )
{
if ( ver - > impl_id = = TEE_IMPL_ID_OPTEE )
return 1 ;
else
return 0 ;
}
static int get_devices ( struct tee_context * ctx , u32 session ,
2020-06-18 16:52:50 +03:00
struct tee_shm * device_shm , u32 * shm_size ,
u32 func )
2019-01-29 11:19:37 +05:30
{
2019-02-19 15:04:28 +08:00
int ret = 0 ;
2019-02-19 02:15:20 -07:00
struct tee_ioctl_invoke_arg inv_arg ;
struct tee_param param [ 4 ] ;
memset ( & inv_arg , 0 , sizeof ( inv_arg ) ) ;
memset ( & param , 0 , sizeof ( param ) ) ;
2019-01-29 11:19:37 +05:30
2020-06-18 16:52:50 +03:00
inv_arg . func = func ;
2019-01-29 11:19:37 +05:30
inv_arg . session = session ;
inv_arg . num_params = 4 ;
/* Fill invoke cmd params */
param [ 0 ] . attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT ;
param [ 0 ] . u . memref . shm = device_shm ;
param [ 0 ] . u . memref . size = * shm_size ;
param [ 0 ] . u . memref . shm_offs = 0 ;
ret = tee_client_invoke_func ( ctx , & inv_arg , param ) ;
if ( ( ret < 0 ) | | ( ( inv_arg . ret ! = TEEC_SUCCESS ) & &
( inv_arg . ret ! = TEEC_ERROR_SHORT_BUFFER ) ) ) {
pr_err ( " PTA_CMD_GET_DEVICES invoke function err: %x \n " ,
inv_arg . ret ) ;
return - EINVAL ;
}
* shm_size = param [ 0 ] . u . memref . size ;
return 0 ;
}
2021-10-12 13:01:16 +05:30
static void optee_release_device ( struct device * dev )
{
struct tee_client_device * optee_device = to_tee_client_device ( dev ) ;
kfree ( optee_device ) ;
}
2023-11-02 13:00:55 +05:30
static ssize_t need_supplicant_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
return 0 ;
}
static DEVICE_ATTR_RO ( need_supplicant ) ;
static int optee_register_device ( const uuid_t * device_uuid , u32 func )
2019-01-29 11:19:37 +05:30
{
struct tee_client_device * optee_device = NULL ;
int rc ;
optee_device = kzalloc ( sizeof ( * optee_device ) , GFP_KERNEL ) ;
if ( ! optee_device )
return - ENOMEM ;
optee_device - > dev . bus = & tee_bus_type ;
2021-10-12 13:01:16 +05:30
optee_device - > dev . release = optee_release_device ;
2020-06-18 16:52:49 +03:00
if ( dev_set_name ( & optee_device - > dev , " optee-ta-%pUb " , device_uuid ) ) {
kfree ( optee_device ) ;
return - ENOMEM ;
}
2019-01-29 11:19:37 +05:30
uuid_copy ( & optee_device - > id . uuid , device_uuid ) ;
rc = device_register ( & optee_device - > dev ) ;
if ( rc ) {
pr_err ( " device registration failed, err: %d \n " , rc ) ;
2022-11-09 22:01:24 +08:00
put_device ( & optee_device - > dev ) ;
tee: optee: Fix kernel panic caused by incorrect error handling
The error path while failing to register devices on the TEE bus has a
bug leading to kernel panic as follows:
[ 15.398930] Unable to handle kernel paging request at virtual address ffff07ed00626d7c
[ 15.406913] Mem abort info:
[ 15.409722] ESR = 0x0000000096000005
[ 15.413490] EC = 0x25: DABT (current EL), IL = 32 bits
[ 15.418814] SET = 0, FnV = 0
[ 15.421878] EA = 0, S1PTW = 0
[ 15.425031] FSC = 0x05: level 1 translation fault
[ 15.429922] Data abort info:
[ 15.432813] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
[ 15.438310] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 15.443372] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 15.448697] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000d9e3e000
[ 15.455413] [ffff07ed00626d7c] pgd=1800000bffdf9003, p4d=1800000bffdf9003, pud=0000000000000000
[ 15.464146] Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP
Commit 7269cba53d90 ("tee: optee: Fix supplicant based device enumeration")
lead to the introduction of this bug. So fix it appropriately.
Reported-by: Mikko Rapeli <mikko.rapeli@linaro.org>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218542
Fixes: 7269cba53d90 ("tee: optee: Fix supplicant based device enumeration")
Cc: stable@vger.kernel.org
Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2024-03-01 20:07:31 +05:30
return rc ;
2019-01-29 11:19:37 +05:30
}
2023-11-02 13:00:55 +05:30
if ( func = = PTA_CMD_GET_DEVICES_SUPP )
device_create_file ( & optee_device - > dev ,
& dev_attr_need_supplicant ) ;
tee: optee: Fix kernel panic caused by incorrect error handling
The error path while failing to register devices on the TEE bus has a
bug leading to kernel panic as follows:
[ 15.398930] Unable to handle kernel paging request at virtual address ffff07ed00626d7c
[ 15.406913] Mem abort info:
[ 15.409722] ESR = 0x0000000096000005
[ 15.413490] EC = 0x25: DABT (current EL), IL = 32 bits
[ 15.418814] SET = 0, FnV = 0
[ 15.421878] EA = 0, S1PTW = 0
[ 15.425031] FSC = 0x05: level 1 translation fault
[ 15.429922] Data abort info:
[ 15.432813] ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
[ 15.438310] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 15.443372] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 15.448697] swapper pgtable: 4k pages, 48-bit VAs, pgdp=00000000d9e3e000
[ 15.455413] [ffff07ed00626d7c] pgd=1800000bffdf9003, p4d=1800000bffdf9003, pud=0000000000000000
[ 15.464146] Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP
Commit 7269cba53d90 ("tee: optee: Fix supplicant based device enumeration")
lead to the introduction of this bug. So fix it appropriately.
Reported-by: Mikko Rapeli <mikko.rapeli@linaro.org>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218542
Fixes: 7269cba53d90 ("tee: optee: Fix supplicant based device enumeration")
Cc: stable@vger.kernel.org
Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
2024-03-01 20:07:31 +05:30
return 0 ;
2019-01-29 11:19:37 +05:30
}
2020-06-18 16:52:50 +03:00
static int __optee_enumerate_devices ( u32 func )
2019-01-29 11:19:37 +05:30
{
const uuid_t pta_uuid =
UUID_INIT ( 0x7011a688 , 0xddde , 0x4053 ,
0xa5 , 0xa9 , 0x7b , 0x3c , 0x4d , 0xdf , 0x13 , 0xb8 ) ;
2019-02-19 02:15:20 -07:00
struct tee_ioctl_open_session_arg sess_arg ;
2019-01-29 11:19:37 +05:30
struct tee_shm * device_shm = NULL ;
const uuid_t * device_uuid = NULL ;
struct tee_context * ctx = NULL ;
u32 shm_size = 0 , idx , num_devices = 0 ;
int rc ;
2019-02-19 02:15:20 -07:00
memset ( & sess_arg , 0 , sizeof ( sess_arg ) ) ;
2019-01-29 11:19:37 +05:30
/* Open context with OP-TEE driver */
ctx = tee_client_open_context ( NULL , optee_ctx_match , NULL , NULL ) ;
if ( IS_ERR ( ctx ) )
return - ENODEV ;
/* Open session with device enumeration pseudo TA */
2020-04-22 16:00:47 +03:00
export_uuid ( sess_arg . uuid , & pta_uuid ) ;
2019-01-29 11:19:37 +05:30
sess_arg . clnt_login = TEE_IOCTL_LOGIN_PUBLIC ;
sess_arg . num_params = 0 ;
rc = tee_client_open_session ( ctx , & sess_arg , NULL ) ;
if ( ( rc < 0 ) | | ( sess_arg . ret ! = TEEC_SUCCESS ) ) {
/* Device enumeration pseudo TA not found */
rc = 0 ;
goto out_ctx ;
}
2020-06-18 16:52:50 +03:00
rc = get_devices ( ctx , sess_arg . session , NULL , & shm_size , func ) ;
2019-01-29 11:19:37 +05:30
if ( rc < 0 | | ! shm_size )
goto out_sess ;
2022-02-04 10:33:54 +01:00
device_shm = tee_shm_alloc_kernel_buf ( ctx , shm_size ) ;
2019-01-29 11:19:37 +05:30
if ( IS_ERR ( device_shm ) ) {
2022-02-04 10:33:54 +01:00
pr_err ( " tee_shm_alloc_kernel_buf failed \n " ) ;
2019-01-29 11:19:37 +05:30
rc = PTR_ERR ( device_shm ) ;
goto out_sess ;
}
2020-06-18 16:52:50 +03:00
rc = get_devices ( ctx , sess_arg . session , device_shm , & shm_size , func ) ;
2019-01-29 11:19:37 +05:30
if ( rc < 0 )
goto out_shm ;
device_uuid = tee_shm_get_va ( device_shm , 0 ) ;
if ( IS_ERR ( device_uuid ) ) {
pr_err ( " tee_shm_get_va failed \n " ) ;
rc = PTR_ERR ( device_uuid ) ;
goto out_shm ;
}
num_devices = shm_size / sizeof ( uuid_t ) ;
for ( idx = 0 ; idx < num_devices ; idx + + ) {
2023-11-02 13:00:55 +05:30
rc = optee_register_device ( & device_uuid [ idx ] , func ) ;
2019-01-29 11:19:37 +05:30
if ( rc )
goto out_shm ;
}
out_shm :
tee_shm_free ( device_shm ) ;
out_sess :
tee_client_close_session ( ctx , sess_arg . session ) ;
out_ctx :
tee_client_close_context ( ctx ) ;
return rc ;
}
2020-06-18 16:52:50 +03:00
int optee_enumerate_devices ( u32 func )
{
return __optee_enumerate_devices ( func ) ;
}
2021-10-12 13:01:16 +05:30
static int __optee_unregister_device ( struct device * dev , void * data )
{
if ( ! strncmp ( dev_name ( dev ) , " optee-ta " , strlen ( " optee-ta " ) ) )
device_unregister ( dev ) ;
return 0 ;
}
void optee_unregister_devices ( void )
{
bus_for_each_dev ( & tee_bus_type , NULL , NULL ,
__optee_unregister_device ) ;
}