郭健(譯) Linux閱碼場 2018-01-31數組
本文由郭健郭大俠翻譯,將分爲三次連載完成,這是第二部分。郭大俠是蝸窩科技(http://www.wowotech.net/)的創始人,倡導"慢下來,享受技術"的健康理念,俠之大者,爲國爲民。緩存
前文:
宇宙最強,meltdown論文中英文對照版(一)
5、熔斷(Meltdown)
In this section, present Meltdown, a powerful attack allowing to readarbitrary physical memory from an unprivileged user program, comprised of thebuilding blocks presented in Section 4. First, we discuss the attack setting toemphasize the wide applicability of this attack. Second, we present an attackoverview, showing how Meltdown can be mounted on both Windows and Linux onpersonal computers as well as in the cloud. Finally, we discuss a concreteimplementation of Meltdown allowing to dump kernel memory with up to 503KB/s.
在這一章咱們將向您展現meltdown的威力:經過一個普通的用戶程序讀取系統中任意位置的物理內存。整個***過程的框架圖已經在第4章描述。首先,咱們討論***設置,經過設置咱們能夠看出meltdown這種***具備很是普遍的適用性。其次,咱們對meltdown***進行概述,並展現了它如何對安裝Windows和Linux的我的計算機上以及雲服務器展開***。最後,咱們討論了一個具體的實現,該Meltdown的實現容許以503kB/s的速度dump內核空間的內存。
Attack setting.
In our attack, we consider personal computersand virtual machines in the cloud. In the attack scenario, the attacker hasarbitrary unprivileged code execution on the attacked system, i.e., the attacker can run any code withthe privileges of a normal user. However, the attacker has no physical accessto the machine. Further, we assume that the system is fully protected withstate-of-the-art software-based defenses such as ASLR and KASLR as well as CPUfeatures like SMAP, SMEP, NX, and PXN. Most importantly, we assume a completelybug-free operating system, thus, no software vulnerability exists that can beexploited to gain kernel privileges or leak information. The attacker targets secretuser data, e.g., passwords and private keys, or any other valuable information.
***設定以下:
咱們考慮我的計算機和雲服務器上的虛擬機兩種應用場景。在***過程當中,***者只使用未受權的代碼來***系統,也就是說***者只能以一個普通用戶的權限來運行代碼。另外,***者沒有對機器進行物理訪問。進一步,咱們假設咱們準備***的系統是已經有了很是好的基於軟件的防護措施,例如ASLR和KASLR,同時CPU也包含了像SMAP,SMEP,NX,和PXN的功能。最重要的是,咱們假設被***系統是一個徹底無bug的操做系統,沒有軟件漏洞能夠被利用來得到root權限或泄露信息。***者的目標是用戶的祕密數據,例如密碼和私鑰,或任何其餘有價值的信息。
一、概述
Meltdown combines the two building blocks discussed in Section 4. First,an attacker makes the CPU execute a transient instruction sequence which usesan inaccessible secret value stored somewhere in physical memory (cf. Section4.1). The transient instruction sequence acts as the transmitter of a covertchannel (cf. Section 4.2), ultimately leaking the secret value to the attacker.
Meltdown使用了第4章中討論***架構圖。首先,***者讓CPU執行一個瞬態指令序列,該指令序列會操做保存在物理內存中不可訪問的祕密數據(參見第4.1節)。瞬態指令序列充當隱蔽通道的發送端(參見第4.2節),最終將祕密數據泄漏給***者。
Meltdown consists of 3 steps:
Step 1 The content of anattacker-chosen memory location,which is inaccessible to the attacker, isloaded into a register.
Step 2 Atransient instruction accesses a cache line based on the secret content of theregister.
Step 3 The attacker usesFlush+Reload to determine the accessed cache line and hence the secret storedat the chosen memory location.
By repeating these steps for different memory locations, the attacker candump the kernel memory, including the entire physical memory.
Meltdown***包括3個步驟:
步驟1:***者訪問祕密數據所在的內存位置(該內存是***者沒有權限訪問的),並加載到一個寄存器中。
步驟2,瞬態指令基於寄存器中保存的祕密數據內容訪問cache line。
步驟3:***者使用Flush+Reload來肯定在步驟2中訪問的cache line,從而恢復在步驟1中讀取的祕密數據。
在不一樣的內存地址上不斷重複上面的步驟,***者能夠dump整個內核地址空間的數據,這也就包括了整個物理內存。
Listing 2 shows the basic implementation of the transient instructionsequence and the sending part of the covert channel, using x86 assemblyinstructions. Note that this part of the attack could also be implementedentirely in higher level languages like C. In the following, we will discuss eachstep of Meltdown and the corresponding code line in Listing 2.
上面的列表顯示了瞬態指令序列和隱蔽通道發送部分的基本實現(使用x86彙編指令)。須要注意的是:這部分***的代碼也能夠徹底用C這樣的高級語言來實現。在隨後的文章中,咱們會討論列表中的每一行代碼是如何完成meltdown***的。
Step 1: Reading the secret. To load data from the main memory into a register, thedata in the main memory is referenced using a virtual address. In parallel to translatinga virtual address into a physical address, the CPU also checks the permissionbits of the virtual address, i.e., whether this virtual address is user accessible or onlyaccessible by the kernel. As already discussed in Section 2.2, thishardware-based isolation through a permission bit is considered secure andrecommended by the hardware vendors. Hence, modern operating systems always mapthe entire kernel into the virtual address space of every user process.
步驟1:
讀內存中的祕密數據。爲了將數據從主存儲器加載到寄存器中,咱們使用虛擬地址來訪問主存中的數據。在將虛擬地址轉換爲物理地址的同時,CPU還會檢查虛擬地址的權限位:這個虛擬地址能否被用戶態訪問,仍是隻能在內核態中訪問。正如在第2.2節中已經討論過的那樣,咱們都認爲這個基於硬件的地址空間隔離是安全的,而且硬件廠商也推薦使用這種隔離方法。所以,現代操做系統老是將整個內核地址空間映射到每一個用戶進程的虛擬地址空間。
As a consequence, all kernel addresses lead to a valid physical addresswhen translating them, and the CPU can access the content of such addresses.The only difference to accessing a user space address is that the CPU raises anexception as the current permission level does not allow to access such an address.Hence, the user space cannot simply read the contents of such an address. However,Meltdown exploits the out-of-order execution of modern CPUs, which stillexecutes instructions in the small time window between the illegal memoryaccess and the raising of the exception.
訪問內核地址空間的時候,只要建立了虛擬地址的映射(便可以經過頁表翻譯出一個有效的物理地址),CPU均可以訪問這些地址的內容。和訪問用戶地址空間惟一不一樣是會進行權限檢查,因爲當前CPU權限級別不夠而訪問內核空間地址的時候會觸發異常。所以,用戶空間不能簡單地經過讀取內核地址的內容來得到祕密數據。然而,亂序執行的特性容許CPU在一個很小的時間窗口內(從執行了非法內存訪問的指令到觸發異常),仍然會繼續執行指令。Meltdown就是利用了亂序執行的特性完成了***。
In line 4 of Listing 2, we load the byte value located at the targetkernel address, stored in the RCX register, into the least significantbyte of the RAX register represented by AL. As explained in more detail inSection 2.1, the MOV instruction is fetched by the core,decoded into μOPs, allocated, and sent to thereorder buffer. There, architectural registers (e.g., RAX and RCX in Listing 2) are mapped to underlyingphysical registers enabling out-of-order execution. Trying to utilize thepipeline as much as possible, subsequent instructions (lines 5-7) are already decodedand allocated as μOPs as well. The μOPs are further sent to thereservation station holding the μOPs while they wait to be executed by the correspondingexecution unit. The execution of a μOP can be delayed if execution units are already used totheir corresponding capacity or operand values have not been calculated yet.
在上面代碼列表中的第4行,咱們訪問了位於內核地址空間的memory(地址保存在RCX寄存器),獲取了一個字節的數據,保存在AL寄存器(即RAX寄存器的8個LSB比特)。根據2.1節中的描述,MOV指令由CPU core取指,解碼成μOPS,分配併發送到重排序緩衝區。在那裏,architecturalregister(軟件可見的寄存器,例如RAX和RCX)會被映射成底層的物理寄存器以便實現亂序執行。爲了儘量地利用流水線,隨後的指令(5-7的代碼)已經解碼並分配爲uOPs。該uOPs會進一步送到保留站(暫存uOPs),在保留站中,uOPs會等待相應的執行單元空閒,若是執行單元準備好,該uOPs會馬上執行,若是執行單元已經達到了容量的上限(例若有3個加法器,那麼能夠同時進行3個加法運算,第四個加法uOPs就須要等待了)或uOPs操做數值還沒有計算出來,uOPs則被延遲執行。
When the kernel address is loaded in line 4, it is likely that the CPUalready issued the subsequent instructions as part of the out-or-orderexecution, and that their corresponding μOPs wait in the reservation stationfor the content of the kernel address to arrive. As soon as the fetched data isobserved on the common data bus, the μOPs can begin their execution.
當在程序第4行加載內核地址到寄存器的時候,因爲亂序執行,極可能CPU已經把後續指令發射出去,而且它們相應的μOPs會在保留站中等待內核地址的內容到來。一旦在公共數據總線上觀察到所獲取的內核地址數據,這些μOPs就會馬上開始執行。
When the μOPs finish their execution, theyretire in order, and, thus, their results are committed to the architectural state.During the retirement, any interrupts and exception that occurred during theexecution of the instruction are handled. Thus, if the MOV instruction that loads the kernel address is retired, theexception is registered and the pipeline is flushed to eliminate all results ofsubsequent instructions which were executed out of order. However, there is arace condition between raising this exception and our attack step 2 which wedescribe below.
當μOPs執行完畢後,它們就按順序進行retire(這個術語叫作retire,很難翻譯,這裏就不翻譯了,可是和commit是一個意思),所以,μOPs的結果會被提交併體如今體系結構狀態上。在提交過程當中,在執行指令期間發生的任何中斷和異常都會被處理。所以,在提交MOV指令的時候發現該指令操做的是內核地址,這時候會觸發異常。這時候CPU流水線會執行flush操做,因爲亂序執行而提早執行的那些指令(Mov指令以後)結果會被清掉。然而,在觸發這個異常和咱們執行的***步驟2之間有一個競爭條件(race condition),咱們在下面描述。
As reported by Gruss et al. [9], prefetching kernel addresses sometimessucceeds. We found that prefetching the kernel address can slightly improve theperformance of the attack on some systems.
根據Gruss等人的研究[ 9 ],預取內核地址有時成功。咱們發現:預取內核地址能夠略微改善某些系統的***性能。
Step 2: Transmitting the secret. The instruction sequence from step 1 which is executedout of order has to be chosen in a way that it becomes a transient instruction sequence.If this transient instruction sequence is executed before the MOV instruction is retired (i.e., raises the exception), and thetransient instruction sequence performed computations based on the secret, itcan be utilized to transmit the secret to the attacker.
步驟2:傳送祕密數據
在步驟1中亂序執行的指令序列可否成爲瞬態指令序列是須要條件的。若是的確是瞬態指令序列,那麼它必需要在MOV指令retirement以前被執行(即在觸發異常以前),並且瞬態指令序列會基於祕密數據進行計算,而這個計算的反作用能夠用來向***者傳遞祕密數據。
As already discussed, we utilize cache attacks that allow to build fastand low-noise covert channel using the CPU’s cache. Thus, the transientinstruction sequence has to encode the secret into the microarchitectural cachestate, similarly to the toy example in Section 3.
正如以前已經討論過的,咱們利用緩存***,即利用CPU的高速緩存創建快速和低噪聲的隱蔽通道。而後,瞬態指令序列必需要把祕密數據編碼在微架構緩存狀態中。這個過程相似於第三節中的那個簡單示例程序。
We allocate a probe array in memory and ensure that no part of this arrayis cached. To transmit the secret, the transient instruction sequence containsan indirect memory access to an address which is calculated based on the secret(inaccessible) value. In line 5 of Listing 2 the secret value from step 1 ismultiplied by the page size, i.e., 4 KB. The multiplication of the secret ensures thataccesses to the array have a large spatial distance to each other. Thisprevents the hardware prefetcher from loading adjacent memory locations intothe cache as well. Here, we read a single byte at once, hence our probe array is256×4096 bytes, assuming 4KB pages.
咱們在內存中分配一個探測數組,並確保該數組的全部內存都沒有被cached。爲了傳遞祕密數據,瞬態指令序列包含對探測數組的間接內存訪問,具體的訪問地址是基於那個祕密數據的(該祕密數據是用戶態不可訪問的)。具體能夠參考上面列表中的第5行代碼:第1步獲取的祕密數據會乘以頁面大小,即4 KB(代碼使用了移位操做,是同樣的意思)。這個乘法操做確保了對數組的訪問具備較大的空間距離。這能夠防止硬件prefetcher把相鄰存儲單元的數據加載到緩存中。在這示例中,因爲一次只讀出一個字節,因此咱們的探測數組是256×4096字節(假設頁面大小是4KB)。
Note that in the out-of-order execution we have a noise-bias towardsregister value ‘0’. Wediscuss the reasons for this in Section 5.2. However, for this reason, we introducea retry-logic into the transient instruction sequence. In case we read a ‘0’, we try to read the secret again (step1). In line 7, the multiplied secret is added to the base address of the probearray, forming the target address of the covert channel. This address is readto cache the corresponding cache line. Consequently, our transient instructionsequence affects the cache state based on the secret value that was read instep 1.
注意:在亂序執行中,咱們對寄存器值「0」有一個噪聲偏置(noise-bias)。咱們在第5.2節討論了具體的緣由。正是因爲這個緣由,咱們在瞬態指令序列中引入了重試邏輯。若是咱們讀到了「0」值,咱們試着從新讀這個祕密數據(第1步)。在代碼的第7行中,將祕密數據乘以4096並累加到探測數組的基地址中,從而造成隱蔽信道的目標地址。讀取該目標地址能夠將數據加載到對應的cacheline中。所以,瞬態指令序列根據第1步中讀取的祕密數據修改了探測數組對應的緩存狀態。
Since the transient instruction sequence in step 2 races against raisingthe exception, reducing the runtime of step 2 can significantly improve theperformance of the attack. For instance, taking care that the addresstranslation for the probe array is cached in the TLB increases the attackperformance on some systems.
因爲步驟2中的瞬態指令序列須要和異常的觸發相競爭,所以減小步驟2的運行時間能夠顯著提升***的性能。例如:把探測數組的地址翻譯預先緩存在TLB中。
Step 3: Receiving the secret. In step 3, the attacker recovers the secret value (step1) by leveraging a microarchitectural side-channel attack (i.e., the receiving end of a microarchitecturalcovert channel) that transfers the cache state (step 2) back into anarchitectural state. As discussed in Section 4.2, Meltdown relies onFlush+Reload to transfer the cache state into an architectural state.
步驟3:接收祕密數據。
在步驟3中,***者利用微架構側信道***(即微架構隱蔽信道的接收端)將cache state轉換成了軟件能夠感知的體系結構狀態(architectural state),從而恢復了祕密數據。正如第4.2節中所討論的,meltdown依賴於Flush+Reload來將緩存狀態轉換爲CPU體系結構狀態。
When the transient instruction sequence of step 2 is executed, exactly onecache line of the probe array is cached. The position of the cached cache linewithin the probe array depends only on the secret which is read in step 1.Thus, the attacker iterates over all 256 pages of the probe array and measuresthe access time for every first cache line (i.e., offset) on the page. The number of thepage containing the cached cache line corresponds directly to the secret value.
在步驟2中執行的瞬態指令序列時,整個探測數組只有一個頁面的cacheline被加載了。具體加載的cacheline的在探測數組中的位置僅取決於步驟1中讀取的祕密數據。所以,***者遍歷全部探測數組中的256個頁面,測試每一個頁面第一個cacheline的訪問時間,已經預先加載了cacheline的那個page index就直接對應着祕密數據的數值。
Dumping the entire physical memory. By repeating all 3 steps of Meltdown,the attacker can dump the entire memory by iterating over all differentaddresses. However, as the memory access to the kernel address raises an exceptionthat terminates the program, we use one of the methods described in Section 4.1to handle or suppress the exception.
Dump整個物理內存:
經過重複上面的3個步驟,同時修改不一樣的***地址,***者能夠dump全部內存。可是,因爲對內核地址的內存訪問引起了一個終止程序的異常,因此咱們使用第4.1節中描述的方法來處理或抑制這個異常。
As all major operating systems also typically map the entire physicalmemory into the kernel address space (cf. Section 2.2) in every user process,Meltdown is not only limited to reading kernel memory but it is capable ofreading the entire physical memory of the target machine.
在目前全部的主流操做系統中,咱們一般會把整個物理內存映射到內核地址空間(參見第2.2節),而每一個用戶進程中又包括內核地址空間部分。所以Meltdown不只能讀取內核地址空間的內存值,並且可以讀取整個系統的物理內存。
二、優化和限制(optimizations and limitations)
The case of 0. If the exception is triggered while trying to read from an inaccessiblekernel address, the register where the data should be stored, appears to bezeroed out. This is reasonable because if the exception is unhandled, the userspace application is terminated, and the value from the inaccessible kerneladdress could be observed in the register contents stored in the core dump ofthe crashed process. The direct solution to fix this problem is to zero out thecorresponding registers. If the zeroing out of the register is faster than theexecution of the subsequent instruction (line 5 inListing 2), the attacker may read a false value in the third step. To preventthe transient instruction sequence from continuing with a wrong value, i.e., ‘0’, Meltdown retries reading the address until itencounters a value different from ‘0’(line 6). As the transient instruction sequence terminates after the exception israised, there is no cache access if the secret value is 0. Thus, Meltdownassumes that the secret value is indeed ‘0’if there is no cache hit at all.
讀出數值是0的場景。
根據前面的描述,在instruction commit階段,當檢測到用戶態訪問內核地址的時候,除了觸發異常,CPU還會清除指令的操做結果,也就是說AL寄存器會被清零。若是瞬態指令序列在和異常的競爭中失敗了(寄存器清零早於上面程序列表中第五行代碼執行),那麼極可能從內核地址讀出的並不是其真是值,而是清零後的數值。對寄存器清零也是合理的,由於若是異常沒有被處理,用戶空間的應用程序會終止,該進程的core dump文件中會保留寄存器的內容,若是不清零,那麼內核空間的數據能夠經過core dump文件泄露出去。清零能夠修正這個issue,保證內核空間數據的安全。爲了防止瞬態指令序列繼續操做錯誤的「0」值,Meltdown會重讀地址直到讀出非「0」值(第6行代碼)。
你可能會問:若是祕密數據就是0怎麼辦?其實當異常觸發後,瞬態指令序列終止執行,若是祕密數據確實等於0,則不存在任何cacheline被加載。所以,meltdown在進行探測數據cacheline掃描過程當中,若是沒有任何cacheline命中,那麼祕密數據實際上就是「0」。
The loop is terminated by either the read value not being ‘0’ or by the raised exception of theinvalid memory access. Note that this loop does not slow down the attackmeasurably, since, in either case, the processor runs ahead of the illegalmemory access, regardless of whether ahead is a loop or ahead is a linearcontrol flow. In either case, the time until the control flow returned fromexception handling or exception suppression remains the same with and withoutthis loop. Thus, capturing read ‘0’sbeforehand and recovering early from a lost race condition vastly increases thereading speed.
不管是讀出數值非「0」或無效地址訪問觸發了異常,代碼中的循環邏輯都會終止。注意,這個循環不會下降***的性能,由於,在上面兩種狀況中,CPU會提早容許非法內存訪問指令以後的代碼指令,而CPU並不關心這些指令是一個循環控制或是一個線性的控制流。不管哪種狀況,從異常處理函數(或者異常抑制)返回的時間都是同樣的,和有沒有循環控制是無關的。所以,儘早發現讀出值是「0」,也就是說盡早發現本身在和異常的競爭中失敗並恢復,能夠大大提升了讀取速度。
Single-bit transmission :
In the attack description in Section 5.1, the attacker transmitted 8 bitsthrough the covert channel at once and performed 28 = 256 Flush+Reload measurements to recover the secret.However, there is a clear trade-off between running more transient instructionsequences and performing more Flush+Reload measurements. The attacker couldtransmit an arbitrary number of bits in a single transmission through thecovert channel, by either reading more bits using a MOV instruction for a larger data value. Furthermore, the attackercould mask bits using additional instructions in the transient instructionsequence. We found the number of additional instructions in the transientinstruction sequence to have a negligible influence on the performance of theattack.
單個bit數據的發送:
在第5.1節的描述中,***者經過隱蔽通道一次能夠傳輸8個bit,接收端執行2^8=256次Flush+Reload命令來恢復祕密數據。不過,咱們須要在運行更多的瞬態指令序列和執行更多的Flush+Reload測量之間進行平衡。***者能夠經過隱蔽通道在一次傳輸中發送任意比特的數據,固然這須要使用MOV指令去讀取更多bit的祕密數據。此外,***者能夠在瞬態指令序列中增長mask的操做(這樣能夠傳送更少的bit,從而減小接收端Flush+Reload的次數)。咱們發如今瞬態指令序列中增長的指令數對***的性能影響是微不足道的。
The performance bottleneck in the generic attack description above isindeed, the time spent on Flush+Reload measurements. In fact, with thisimplementation, almost the entire time will be spent on Flush+Reload measurements.By transmitting only a single bit, we can omit all but one Flush+Reloadmeasurement, i.e., the measurement on cache line 1. Ifthe transmitted bit was a ‘1’,then we observe a cache hit on cache line 1. Otherwise, we observe no cache hiton cache line 1.
上面描述的meltdown***中的性能瓶頸主要是在經過Flush+Reload恢復祕密數據上所花費的時間。實際上在本章中的meltdown代碼實現中,幾乎全部的時間都將花費在Flush+Reload上了。若是隻發送一個bit,那麼除了一次Flush+Reload測量時間,其餘的咱們均可以忽略。在這種狀況下,咱們只須要檢測一個cacheline的狀態,若是cache hit,那麼傳輸的bit是「1」,若是cache miss,那麼傳輸的bit是「0」。
Transmitting only a single bit at once also has drawbacks. As describedabove, our side channel has a bias towards a secret value of ‘0’. If we read and transmit multiple bitsat once, the likelihood that all bits are ‘0’may quite small for actual user data. The likelihood that a single bit is ‘0’ is typically close to 50 %. Hence, thenumber of bits read and transmitted at once is a tradeoff between some impliciterror-reduction and the overall transmission rate of the covert channel.
一次只傳輸一個比特也有缺點。如上所述,咱們的側通道更偏向於「0」值。若是咱們一次讀取多個比特的祕密數據併發送出去,那麼全部bit都是「0」的可能性應該說是至關小。單個bit等於「0」的可能性一般接近50%。所以,一次傳輸的比特數是須要在隱蔽信道的總傳輸速率和減小差錯之間進行平衡。
However, since the error rates are quite small in either case, ourevaluation (cf. Section 6) is based on the single-bit transmission mechanics.
不過,因爲兩種狀況下的錯誤率都很小,所以咱們的評估(參見第6節)是基於單比特傳輸機制的。
Exception Suppression using IntelTSX.
和Intel的TSX相關,暫時沒有興趣瞭解。
Dealing with KASLR.
In 2013, kernel address space layoutrandomization (KASLR) had been introduced to the Linux kernel (starting fromversion 3.14 [4]) allowing to randomize the location of the kernel code at boottime. However, only as recently as May 2017, KASLR had been enabled by defaultin version 4.12 [27]. With KASLR also the direct-physical map is randomizedand, thus, not fixed at a certain address such that the attacker is required toobtain the randomized offset before mounting the Meltdown attack. However, therandomization is limited to 40 bit.
處理KASLR。
2013年,內核地址空間佈局隨機化(KASLR)已被合併到Linux內核中(從3.14版開始[ 4 ]),這個特性容許在開機的時候把內核代碼加載到一個隨機化地址上去。在最近的(2017年5月)4.12版的內核中,KASLR已經被默認啓用[27 ]。而且直接映射部分的地址也是隨機的,並不是固定在某個地址上。所以,在利用meltdown漏洞對內核進行***以前,***者須要須要得到一個40-bit的隨機偏移值。
Thus, if we assume a setup of the target machine with 8GB of RAM, it issufficient to test the address space for addresses in 8GB steps. This allows tocover the search space of 40 bit with only 128 tests in the worst case. If theattacker can successfully obtain a value from a tested address, the attackercan proceed dumping the entire memory from that location. This allows to mount Meltdownon a system despite being protected by KASLR within seconds.
假設目標機有8GB內存,那麼咱們實際上是可使用8G的步長來進行地址空間的探測。即使是在最壞的狀況下也只有128次就能夠肯定這個40-bit的隨機偏移值。***者一旦可以成功地***某個測試地址,那麼他也能夠繼續從該位置dump整個內存。儘管系統受到KASLR的保護,實際上利用meltdown漏洞,***者也能夠在幾秒鐘內完成***。
本文未完待續安全