<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Normal World與Secure World的地址空間隔離是如何實現的

jf_EksNQtU6 ? 來源:談思實驗室 ? 2023-09-05 09:36 ? 次閱讀

前言

眾所周知,Normal World的用戶態與內核態的地址空間隔離是基于MMU分頁來實現的,那么Normal World與Secure World的地址空間隔離是如何實現的呢?

這篇文章將從CPU和OS的角度進行深入分析,并分析其中存在的安全風險。

硬件隔離機制

閱讀ARM TrustZone手冊可知,內存的隔離是由TZASC(TrustZone Address Space Controller)來控制 ,TZASC可以把外部DDR分成多個區域,每個區域可以單獨配置為安全區域或非安全區域 ,Normal World的代碼只能訪問非安全區域。

5bd08582-4b09-11ee-97a6-92fbcf53809c.png

下面以TZC-380這款地址空間控制器來進行說明,其它型號控制器的原理也大同小異。

通過配置 TZASC的寄存器來設置不同屬性的region,

?一個region表示 一段連續的物理地址空間,

?TZASC給每個region提供了一個可編程的安全屬性域,

?只有在Secure狀態下才允許修改這些寄存器,

?TZASC的基址不是固定的,不同廠商實現可能不同,但是每個寄存器的offset是固定的,如下所示:

5be95652-4b09-11ee-97a6-92fbcf53809c.png

CODE-TEEOS內存管理

下面結合【OP-TEE代碼】[1]對配置 TZASC進行分析:

core/drivers/tzc380.c

通過對region對應的控制寄存器進行設置來配置安全內存地址空間:tzc_configure_region

/*
*`tzc_configure_region`isusedtoprogramregionsintotheTrustZone
*controller.
*/
voidtzc_configure_region(uint8_tregion,vaddr_tregion_base,uint32_tattr)
{
assert(tzc.base);

assert(regionRegister
//注意:regionn的基址寄存器的[14:0]永遠為0,因為TZASC不允許regionsize小于32KB
tzc_write_region_base_low(tzc.base,region,
addr_low(region_base));
//設置RegionSetupHighRegister,第n個region基址的[63:32]位
//和上面的lowaddr拼成完整的region基址
tzc_write_region_base_high(tzc.base,region,
addr_high(region_base));
//設置RegionAttributesRegister
//控制permissions,regionsize,subregiondisable,andregionenable
tzc_write_region_attributes(tzc.base,region,attr);
}else{
//第0個region的基址不需要設置,只需要設置region的屬性
tzc_write_region_attributes(tzc.base,region,
attr&TZC_ATTR_SP_MASK);
}
}
//設置RegionSetupLowRegister的值
staticvoidtzc_write_region_base_low(vaddr_tbase,uint32_tregion,
uint32_tval)
{
//定位到第region個Region對應的寄存器,即上圖中的region_setup_low_n
//tzasc基址寄存器+regioncontrol寄存器的偏移(0x100)+regionn寄存器的size
io_write32(base+REGION_SETUP_LOW_OFF(region),val);
}

通過閱讀代碼可知,tzc_configure_region是對第n個region的基址、大小和屬性進行設置 ,其中屬性寄存器的格式如下:

5c0e0470-4b09-11ee-97a6-92fbcf53809c.png

?sp

: 第n個region的權限設置 ,當發生訪問region時,sp控制TZASC是否允許訪問region。

?size

:第n個region的大小 。

?subregion_disable

: region被劃分為8個相同大小的sub-regions,第一位表示相應的subregion是否disabled。

?en

: 第n個region是否開啟。

imx_configure_tzasc函數中對region進行了配置 :

staticTEE_Resultimx_configure_tzasc(void)
{
vaddr_taddr[2]={0};
intend=1;
inti=0;
//TZASC基址
addr[0]=core_mmu_get_va(TZASC_BASE,MEM_AREA_IO_SEC);
......

for(i=0;i

Region 0用來設置整個地址空間的默認屬性,它的基址為0,Size是由AXI_ADDRESS_MSB來配置,因此Region 0除了安全屬性字段之外,其它字段不允許設置。

下面以第一個region為例,對安全屬性進行分析: 第一個region的屬性為TZC_ATTR_SP_NS_RW:

#defineTZC_SP_NS_WBIT(0)
#defineTZC_SP_NS_RBIT(1)
#defineTZC_SP_S_WBIT(2)
#defineTZC_SP_S_RBIT(3)

#defineTZC_ATTR_SP_SHIFT28//屬性位[28:31]

#defineTZC_ATTR_SP_NS_RW((TZC_SP_NS_W|TZC_SP_NS_R)<

根據手冊可知,TZC_SP_NS_W(b0001)是Non-secure write和 Secure write,TZC_SP_NS_R(b0010)是Non-secure read和Secure read,所以TZC_ATTR_SP_NS_RW 表示 Non-secure和Secure狀態可讀寫,即配置了DRAM地址空間的屬性為非安全和安全狀態都可以讀寫。

5c299dca-4b09-11ee-97a6-92fbcf53809c.png

總結:

以上代碼配置了CFG_TZDRAM_START開始的CFG_TZDRAM_SIZE大小的地址空間為安全內存,即只有安全狀態下(TCR.NS=0)可以訪問。

CFG_DRAM_BASE開始的CFG_DRAM_SIZE大小的地址空間為普通內存,安全和非安全狀態下都可以訪問。

CFG_SHMEM_START開始的CFG_SHMEM_SIZE大小的地址空間為共享內存,安全和非安全狀態都可以 訪問 。

【OP-TEE物理內存布局:】[2]

core/arch/arm/include/mm/generic_ram_layout.h

*TEERAMlayoutwithoutCFG_WITH_PAGER
*_
*+----------------------------------+<--?CFG_TZDRAM_START
?*??|?TEE?core?secure?RAM?(TEE_RAM)????|
?*??+----------------------------------+
?*??|?Trusted?Application?RAM?(TA_RAM)?|
?*??+----------------------------------+
?*??|?SDP?test?memory?(optional)???????|
?*??+----------------------------------+?<--?CFG_TZDRAM_START?+?CFG_TZDRAM_SIZE
?*
?*??+----------------------------------+?<--?CFG_SHMEM_START
?*??|?Non-secure?static?SHM????????????|
?*??+----------------------------------+?<--?CFG_SHMEM_START?+?CFG_SHMEM_SIZE

至此,已經完成了安全內存的配置,接下來我們再來看下安全OS是如何使用這些物理內存的。

CODE-TEEOS內存管理

core/arch/arm/kernel/entry_a64.S

【TEE OS啟動時會調用core_init_mmu_map對安全內存地址空間進行映射 :】[3]

#ifdefCFG_CORE_ASLR
movx0,x20
blget_aslr_seed#x0用來保存開啟aslr的seed
#else
movx0,#0
#endif

adrx1,boot_mmu_config
blcore_init_mmu_map#記錄PA和VA的對應關系,并初始化頁表

......

bl__get_core_pos
blenable_mmu#設置ttbr0_el1、tcr_el1,開啟分頁,在開啟頁之前,VA==PA

core_init_mmu_map函數根據編譯時注冊的物理內存地址信息對頁表進行初始化,也就是對物理內存進行內存映射:

void__weakcore_init_mmu_map(unsignedlongseed,structcore_mmu_config*cfg)
{
#ifndefCFG_VIRTUALIZATION
//__nozi_start在鏈接腳本中指定,一級頁表的地址
vaddr_tstart=ROUNDDOWN((vaddr_t)__nozi_start,SMALL_PAGE_SIZE);
#else
vaddr_tstart=ROUNDDOWN((vaddr_t)__vcore_nex_rw_start,
SMALL_PAGE_SIZE);
#endif
vaddr_tlen=ROUNDUP((vaddr_t)__nozi_end,SMALL_PAGE_SIZE)-start;
structtee_mmap_region*tmp_mmap=get_tmp_mmap();
unsignedlongoffs=0;
//檢查安全和非安全區域是否有重疊,如果有重疊,則系統panic
check_sec_nsec_mem_config();
//static_memory_map記錄mmap_region的PA、VA,用來PA/VA轉換
//第一個mmap_region記錄的是一級頁表的PA和VA
static_memory_map[0]=(structtee_mmap_region){
.type=MEM_AREA_TEE_RAM,//region的內存類型
.region_size=SMALL_PAGE_SIZE,//內存粒度
.pa=start,
.va=start,
.size=len,
.attr=core_mmu_type_to_attr(MEM_AREA_IDENTITY_MAP_RX),
};

COMPILE_TIME_ASSERT(CFG_MMAP_REGIONS>=13);
//初始化內存信息表,即記錄下各region的PA/VA,用來PV/VA轉換
//后面也會根據這些信息對頁表進行初始化
offs=init_mem_map(tmp_mmap,ARRAY_SIZE(static_memory_map),seed);

check_mem_map(tmp_mmap);
core_init_mmu(tmp_mmap);//初始化頁表,進行內存映射
dump_xlat_table(0x0,1);
core_init_mmu_regs(cfg);//記錄頁表基址,用來設置TTBR0
cfg->load_offset=offs;
memcpy(static_memory_map,tmp_mmap,sizeof(static_memory_map));
}

上面函數首先調用init_mem_map初始化一個內存信息表,記錄下各Region的PA和VA,此表用來物理地址和虛擬地址轉換,后面頁表初始化時也會根據此表進行填充。

staticunsignedlonginit_mem_map(structtee_mmap_region*memory_map,
size_tnum_elems,unsignedlongseed)
{
/*
*@id_map_startand@id_map_enddescribesaphysicalmemoryrange
*thatmustbemappedRead-OnlyeXecutableatidenticalvirtual
*addresses.
*/
vaddr_tid_map_start=(vaddr_t)__identity_map_init_start;
vaddr_tid_map_end=(vaddr_t)__identity_map_init_end;
unsignedlongoffs=0;
size_tlast=0;
//根據已注冊的物理地址空間信息來設置memory_map中tee_mmap_region的物理地址范圍(即PA、SIZE)
last=collect_mem_ranges(memory_map,num_elems);
//設置memory_map中tee_mmap_region的region_size(內存粒度)
//如果是tee側的安全內存,則設置region_size為SMALL_PAGE_SIZE(4K)
assign_mem_granularity(memory_map);

/*
*Toeasemappingandloweruseofxlattables,sortmapping
*descriptionmovingsmall-pageregionsafterthepgdirregions.
*/
qsort(memory_map,last,sizeof(structtee_mmap_region),
cmp_init_mem_map);
//添加一個MEM_AREA_PAGER_VASPACE類型的tee_mmap_region
add_pager_vaspace(memory_map,num_elems,&last);
if(IS_ENABLED(CFG_CORE_ASLR)&&seed){
//如果開啟了ASLR,則將安全內存起始地址加上一個隨機值
vaddr_tbase_addr=TEE_RAM_START+seed;
constunsignedintva_width=get_va_width();
constvaddr_tva_mask=GENMASK_64(va_width-1,
SMALL_PAGE_SHIFT);
vaddr_tba=base_addr;
size_tn=0;

for(n=0;n

其中,collect_mem_ranges根據編譯時保存到phys_mem_map節中物理內存信息來設置memory_map中tee_mmap_region的物理地址范圍 。

//根據已注冊的物理地址空間信息設置memory_map數組中tee_mmap_region的物理地址范圍
staticsize_tcollect_mem_ranges(structtee_mmap_region*memory_map,
size_tnum_elems)
{
conststructcore_mmu_phys_mem*mem=NULL;
size_tlast=0;
//根據phys_mem_map設置memory_map(用于記錄region的PA/VA的對應關系)的PA、SIZE和attr
//phys_mem_map_begin是phys_mem_map數組的起始地址
for(mem=phys_mem_map_begin;mem

通過 register_phys_mem 這個宏將TEE、非安全的共享內存的物理地址空間編譯到phys_mem_map這個section。

register_phys_mem(MEM_AREA_TEE_RAM,TEE_RAM_START,TEE_RAM_PH_SIZE);
register_phys_mem(MEM_AREA_TA_RAM,TA_RAM_START,TA_RAM_SIZE);
register_phys_mem(MEM_AREA_NSEC_SHM,TEE_SHMEM_START,TEE_SHMEM_SIZE);
register_sdp_mem(CFG_TEE_SDP_MEM_BASE,CFG_TEE_SDP_MEM_SIZE);
register_phys_mem_ul(MEM_AREA_TEE_RAM_RW,VCORE_UNPG_RW_PA,VCORE_UNPG_RW_SZ);
.....

register_phys_mem這個宏使用關鍵字”section”將修飾的變量按照core_mmu_phys_mem結構體編譯到phys_mem_map這個section中。

phys_mem_map_begin指向phys_mem_map這個section的起始地址 。

collect_mem_ranges會根據這個section的信息初始化static_memory_map內存信息數組,這個數組用來 記錄各region的PA、VA、內存屬性、地址空間范圍等信息。

#defineregister_phys_mem(type,addr,size)
__register_memory(#addr,(type),(addr),(size),
phys_mem_map)

#define__register_memory(_name,_type,_addr,_size,_section)
SCATTERED_ARRAY_DEFINE_ITEM(_section,structcore_mmu_phys_mem)=
{.name=(_name),.type=(_type),.addr=(_addr),
.size=(_size)}

值得注意的是,上面注冊的TEE_RAM_START開始的物理地址空間就是TZC-380配置的Region 2,即安全內存地址空間。

#defineTEE_RAM_STARTTZDRAM_BASE
#defineTEE_RAM_PH_SIZETEE_RAM_VA_SIZE
#defineTZDRAM_BASECFG_TZDRAM_START
#defineTZDRAM_SIZECFG_TZDRAM_SIZE

接下來, core_init_mmu調用core_init_mmu_ptn來對整個注冊的內存地址空間進行VA到PA的映射,即根據PA和VA填充頁表。

voidcore_init_mmu_prtn(structmmu_partition*prtn,structtee_mmap_region*mm)
{
size_tn;

assert(prtn&&mm);

for(n=0;!core_mmap_is_end_of_table(mm+n);n++){
debug_print("%010"PRIxVA"%010"PRIxPA"%10zx%x",
mm[n].va,mm[n].pa,mm[n].size,mm[n].attr);

if(!IS_PAGE_ALIGNED(mm[n].pa)||!IS_PAGE_ALIGNED(mm[n].size))
panic("unalignedregion");
}

/*Cleartablebeforeuse*/
memset(prtn->l1_tables,0,sizeof(l1_xlation_table));

for(n=0;!core_mmap_is_end_of_table(mm+n);n++)
//如果不是動態虛擬地址空間,則進行填充頁表(映射內存)
if(!core_mmu_is_dynamic_vaspace(mm+n))
//根據PA/VA填充頁表,即做內存映射
core_mmu_map_region(prtn,mm+n);

/*
*Primarymappingtableisreadyatindex`get_core_pos()`
*whosevaluemaynotbeZERO.Takethisindexascopysource.
*/
//根據已設置的頁表設置所有核的頁表
for(n=0;nl1_tables[0][n],
prtn->l1_tables[0][get_core_pos()],
XLAT_ENTRY_SIZE*NUM_L1_ENTRIES);
}
}

到這里,TEE側OS已經完成了對物理內存的映射,包括安全內存和共享內存。在開啟分頁后,TEEOS就可以訪問這些虛擬內存地址空間了。

CODE-安全側地址校驗

下面以符合GP規范的TEE接口為例,簡單介紹下CA和TA的通信流程:

5c50e718-4b09-11ee-97a6-92fbcf53809c.png

篇幅所限,這里僅分析Secure World側的調用流程,重點關注TA_InvokeCommandEntryPoint調用流程,此函數用來處理所有來自Normal World側的請求,安全側可信應用的漏洞挖掘也是從這個函數開始入手,這里我們只分析地址校驗相關流程。

?1.在TEEC_OpenSession中會去加載TA的elf文件,并設置相應的函數操作表,最終調用目標TA的TA_OpenSessionEntryPoint。__tee_entry_std
-->entry_open_session
-->tee_ta_open_session
-->tee_ta_init_session-->tee_ta_init_user_session-->set_ta_ctx_ops
-->ctx->ops->enter_open_session(user_ta_enter_open_session)
-->user_ta_enter
-->tee_mmu_map_param
-->thread_enter_user_mode
-->__thread_enter_user_mode//返回到S_EL0,調用目標TA的TA_OpenSessionEntryPoint

?2.TA_InvokeCommandEntryPoint調用流程如下,在此函數中會對REE傳入的地址進行校驗。__tee_entry_std
-->entry_invoke_command
-->copy_in_param
-->set_tmem_param//如果是memref類型,則調用set_tmem_param分配共享內存
-->msg_param_mobj_from_nocontig
-->mobj_mapped_shm_alloc
-->mobj_reg_shm_alloc//最終會調用core_pbuf_is來檢查RRE傳入的PA是否在非安全內存地址范圍內
-->tee_ta_get_session
-->tee_ta_invoke_command
-->check_params
-->sess->ctx->ops->enter_invoke_cmd(user_ta_enter_invoke_cmd)
-->user_ta_enter
-->tee_mmu_map_param//映射用戶空間地址(S_EL0)
-->tee_ta_push_current_session
-->thread_enter_user_mode//返回S_EL0相應的TA中執行TA_InvokeCommandEntryPoint

通過以上代碼分析可知,在調用TA的TA_InvokeCommandEntryPoint函數之前會對REE側傳入的參數類型進行檢查 ,在TA代碼中使用REE傳入參數作為內存地址的場景下,如果未校驗對應的參數類型或者參數類型為TEEC_VALUE_INPUT(與實際使用參數類型不匹配),則會繞過上面core_pbuf_is對REE傳入PA的檢查 ,可以傳入任意值,這個值可以為安全內存PA,這樣就可以導致以S_EL0權限讀寫任意安全內存。

總結

TEE作為可信執行環境,通常用于運行處理指紋、人臉、PIN碼等關鍵敏感信息的可信應用,即使手機被ROOT,攻擊者也無法獲取這些敏感數據。

因此TEE側程序的安全至關重要,本文深入分析了TRUSTZONE物理內存隔離、TEEOS內存管理及TEE側對REE傳入地址的校驗。

在了解了這些原理之后,我們就可以進行漏洞挖掘了, 當然也能寫出簡單有效的FUZZ工具。只有對漏洞原理、攻擊方法進行深入的理解 ,才能進行有效的防御。

FUZZ是一個模糊測試工具,用于在漏洞挖掘過程中進行重要的一步。它能夠檢查常見的漏洞,如緩沖區溢出、格式串漏洞、整數溢出等。

模糊測試是一種通過輸入大量隨機產生的數據來檢測程序異常的自動化測試方法。在模糊測試中,測試用例是隨機生成的,而不是手動創建的。這種方法可以幫助發現一些常見的問題,如邊界條件錯誤、類型錯誤、內存泄漏等。

FUZZ-COV是另一個流行的模糊測試工具,它使用覆蓋引導技術來提高模糊測試的效率。該工具能夠檢測出更多的漏洞,并且比其他工具更快。

除了FUZZ和FUZZ-COV,還有其他一些模糊測試工具,如BETA、BAP和LibFuzzer。這些工具在設計和實現上略有不同,但它們的目標是相同的,即發現程序中的漏洞。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 控制器
    +關注

    關注

    112

    文章

    15334

    瀏覽量

    172344
  • 寄存器
    +關注

    關注

    30

    文章

    5141

    瀏覽量

    118055
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10509

    瀏覽量

    207139
  • 內存管理
    +關注

    關注

    0

    文章

    163

    瀏覽量

    14065

原文標題:參考

文章出處:【微信號:談思實驗室,微信公眾號:談思實驗室】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    隔離器按照封裝形式分為在線型隔離器和自由空間隔離

    自由空間隔離器按照對輸入光的偏振要求,又分為偏振相關隔離器和偏振無光隔離器。由于激光器輸出光的偏振態是確定的,因此光組件中用量最大的是偏振相關自由空間隔離器。
    的頭像 發表于 07-15 14:39 ?1w次閱讀

    在armv8下如何在secure world里開發裸機驅動?

    使用的是Hikey開發板,現在需要在secure world里面開發一個驅動,去直接操作比如鍵盤什么的,但是不知道在狀態為secure的時候,能不能訪問這些硬件。不知道有沒有大神做過,可否指點一下。謝謝!
    發表于 03-08 01:10

    Arduino Hello World實驗

    `先來練習一個不需要其他輔助元件,只需要一塊Arduino 和一根下載線的簡單實驗,讓我們的Arduino 說出“Hello World!”,這是一個讓Arduino和PC 機通信的實驗,這也是一個
    發表于 08-06 09:06

    基于SAFERTOS系統的時間隔離實現

    SAFECheckpoints基于SAFERTOS的功能安全系統中,除了空間隔離外,針對不同的安全標準,可能還需要時間隔離功能,確保軟件的時間處理需求。在單核處理器中,可以使用軟件組件來檢測對系統
    發表于 07-11 11:18

    【精彩回顧】HarmonyOS先行者技術沙龍—— Hello New World!

    ,比如:一個完整的嵌入式系統都有什么?操作系統怎么“同時運行”多個任務?支持MMU的操作系統,怎么實現空間隔離?支持MMU的操作系統,怎么實現權限控制?移植一個最小系統要做什么事情?以及HDF驅動程序介紹
    發表于 10-27 15:49

    【HarmonyOS】HarmonyOS先行者技術沙龍—— Hello New World!

    ,怎么實現空間隔離?支持MMU的操作系統,怎么實現權限控制?移植一個最小系統要做什么事情?以及HDF驅動程序介紹。精彩回顧(四)為OpenHarmony移植MCU芯片簡介:中科院軟件所智能軟件研究中心
    發表于 10-27 19:35

    基于Nios II的hello world相關資料分享

    目錄一、基于Nios II的hello world1、NiosII實現hello world1.1硬件設計1.2軟件設計1.3下載硬件和軟件一、基于Nios II的hello world
    發表于 12-27 08:13

    如何利用Niso ||實現hello world

    基于Nios || 的 hello world一、Qsys二、Nios ||介紹三、利用Niso ||實現hello world(一)硬件設計(二)軟件設計(三)下載硬件和軟件一、Qsys簡介
    發表于 01-25 06:24

    如何在Arm計算平臺中實現機密計算

    執行和數據訪問方面,Realm 能與 Normal world 完全隔離。Arm CCA 通過將架構硬件擴展和固件相結合實現了這種隔離。在
    發表于 08-05 14:40

    Android開發之“hello World”的實現

    按照慣例,同時也是為了更好地引導讀者進入精彩的Android世界,我們接下來要實現一個簡單的“hello World”例子。
    發表于 08-24 11:20 ?5504次閱讀
    Android開發之“hello <b class='flag-5'>World</b>”的<b class='flag-5'>實現</b>

    基于ARC SDE擴展World Wind Java空間檢索能力的方法

    ARC SDE提供的空間數據檢索函數開發的服務接口擴展實現World Wind Java的空間數據檢索功能,并在北海區海洋綜合信息一張圖系統中進行了實際應用,驗證了方法的有效性。
    發表于 11-27 17:23 ?0次下載

    基于Nios 的 hello world

    基于Nios || 的 hello world一、Qsys二、Nios ||介紹三、利用Niso ||實現hello world(一)硬件設計(二)軟件設計(三)下載硬件和軟件一、Qsys簡介
    發表于 11-30 17:36 ?9次下載
    基于Nios  的 hello <b class='flag-5'>world</b>

    HELLO WORLD!

    HELLO WORLD!
    發表于 12-03 16:21 ?8次下載
    HELLO <b class='flag-5'>WORLD</b>!

    STM32開發入門(二)——Hello World

    STM32開發入門(二)——Hello World
    發表于 12-07 18:51 ?11次下載
    STM32開發入門(二)——Hello <b class='flag-5'>World</b>

    Engineering-the-5G-World

    Engineering-the-5G-World,是德公司關于5G的理解和測試項解釋。
    發表于 05-15 10:21 ?0次下載
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>