Science, Faculty of
Computer Science, Department of
DSpace
UBCV
Wang, Yayu
Master of Science - MSc
University of British Columbia
Cache side-channel attacks are a class of attacks where an attacker co-located with a victim application on a server infers the victim’s secrets from observations of the victim’s usage of shared caches. Conventionally, cache side-channel attacks have been used to leak sensitive information from applications written in statically typed languages (e.g., C) and compiled into binary. However, cache side-channel vulnerabilities in applications using language runtimes have received less attention. Language runtimes introduce several barriers to performing cache side-channel attacks. First, with language runtimes, the application code is converted into a bytecode sequence, which is then interpreted as a sequence of machine instructions during execution. The attacker therefore needs to identify the cache lines that uniquely map to the sequence of machine instructions corresponding to specific bytecode operations in the victim’s logic. Second, the control flow in runtime interpretation logic might influence the state of the cache, which is shared between the attacker, the victim application, and the runtime. Consequently, the runtime induces noise in the cache measurements that prevents the attacker from accurately inferring the victim’s execution logic. We address the above challenges and demonstrate that cache side-channel attacks can be exploited on applications executed with language runtimes. We present two well-known types of cache side-channel attacks, namely Prime+Scope and Flush+Reload, on a JavaScript implementation of RSA that is run on QuickJS. We show that even if the RSA source code is hardened to have secret-independent execution time, an attacker can derive the secret key via cache side-channel observations on RSA’s bytecode interpretation with 99% accuracy after only 32 runs of the RSA.
Cache Side-Channel Attacks on Language RuntimesbyYayu WangB. Engineering, Beijing University of Posts and Telecommunications, 2021A THESIS SUBMITTED IN PARTIAL FULFILLMENTOF THE REQUIREMENTS FOR THE DEGREE OFMaster of ScienceinTHE FACULTY OF GRADUATE AND POSTDOCTORALSTUDIES(Computer Science)The University of British Columbia(Vancouver)April 2025© Yayu Wang, 2025The following individuals certify that they have read, and recommend to the Fac-ulty of Graduate and Postdoctoral Studies for acceptance, the thesis entitled:Cache Side-Channel Attacks on Language Runtimessubmitted by Yayu Wang in partial fulfillment of the requirements for the degreeof Master of Science in Computer Science.Examining Committee:Aastha Mehta, Assistant Professor, Computer Science, UBCSupervisorMargo Seltzer, Professor, Computer Science, UBCSupervisory Committee MemberReto Achermann, Assistant Professor, Computer Science, UBCSupervisory Committee MemberiiAbstractCache side-channel attacks are a class of attacks where an attacker co-located witha victim application on a server infers the victim’s secrets from observations ofthe victim’s usage of shared caches. Conventionally, cache side-channel attackshave been used to leak sensitive information from applications written in staticallytyped languages (e.g., C) and compiled into binary. However, cache side-channelvulnerabilities in applications using language runtimes have received less attention.Language runtimes introduce several barriers to performing cache side-channelattacks. First, with language runtimes, the application code is converted into abytecode sequence, which is then interpreted as a sequence of machine instruc-tions during execution. The attacker therefore needs to identify the cache lines thatuniquely map to the sequence of machine instructions corresponding to specificbytecode operations in the victim’s logic. Second, the control flow in runtime in-terpretation logic might influence the state of the cache, which is shared betweenthe attacker, the victim application, and the runtime. Consequently, the runtimeinduces noise in the cache measurements that prevents the attacker from accuratelyinferring the victim’s execution logic.We address the above challenges and demonstrate that cache side-channel at-tacks can be exploited on applications executed with language runtimes. We presenttwo well-known types of cache side-channel attacks, namely Prime+Scope andFlush+Reload, on a JavaScript implementation of RSA that is run on QuickJS.We show that even if the RSA source code is hardened to have secret-independentexecution time, an attacker can derive the secret key via cache side-channel obser-vations on RSA’s bytecode interpretation with 99% accuracy after only 32 runs ofthe RSA.iiiLay SummaryIn cache side-channel attacks, an attacker can gain access to a victim’s privateinformation by observing how the victim’s application uses shared cache memoryon a computer. Traditionally, these attacks have targeted applications written inlanguages such as C and natively running on computers, but less attention hasbeen given to applications relying on language runtime systems (e.g., JavaScriptprograms running in a browser). In this work, we demonstrate how cache sidechannels can be exploited to leak sensitive information from an application writtenin languages, such as JavaScript, and executed in a language runtime system, suchas QuickJS. We target the QuickJS runtime and successfully attack the OpenPGP.jsJavaScript cryptographic library. Despite OpenPGP.js adopting mitigations againstinformation leakage, we extract the secret key with 99% accuracy using only 32runs.ivPrefaceThis thesis is original, unpublished, and independent work by the author, YayuWang. Some figures and text are derived from a paper I authored, which has beensubmitted to ASPLOS 2026 and is currently under review. ChatGPT was used toenhance clarity, refine grammar, and improve conciseness.vTable of ContentsAbstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiiLay Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ivPreface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vTable of Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viList of Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viiiList of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ixAcknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Background and Related Work . . . . . . . . . . . . . . . . . . . . . 72.1 Memory and Cache Architecture . . . . . . . . . . . . . . . . . . 72.2 Cache Side-Channel Attacks . . . . . . . . . . . . . . . . . . . . 102.3 Runtime Systems . . . . . . . . . . . . . . . . . . . . . . . . . . 132.4 Side-Channel Attacks on Runtime Systems . . . . . . . . . . . . 153 Cache Side-Channel Attack on Language Runtime . . . . . . . . . . 173.1 Threat Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.2 Attack Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . 183.3 Identifying Leakage within the QuickJS Runtime . . . . . . . . . 20vi3.3.1 Sources of Leakage in QuickJS Internals . . . . . . . . . 203.3.2 OpenPGP.js RSA Algorithm . . . . . . . . . . . . . . . . 233.3.3 Leakage in OpenPGP.js within the Context of QuickJS . . 263.4 Identifying Cache Sets to Monitor . . . . . . . . . . . . . . . . . 273.5 Recovering secrets from cache access traces . . . . . . . . . . . . 303.5.1 Identifying the Invocation Trace From Cache Access Traces 303.5.2 Sources of Noise . . . . . . . . . . . . . . . . . . . . . . 323.5.3 Countermeasures to Noise . . . . . . . . . . . . . . . . . 334 Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374.1 Attack Accuracy . . . . . . . . . . . . . . . . . . . . . . . . . . 374.2 Required Runs for Secret Key Recovery . . . . . . . . . . . . . . 384.3 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414.3.1 Limitations of the Evaluation . . . . . . . . . . . . . . . . 414.3.2 Noise due to Prediction . . . . . . . . . . . . . . . . . . . 425 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445.1 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445.2 Future Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455.2.1 Other Runtime Systems and Applications . . . . . . . . . 455.2.2 Mitigation Strategies . . . . . . . . . . . . . . . . . . . . 455.2.3 Speculative Execution Attacks . . . . . . . . . . . . . . . 47Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49viiList of TablesTable 2.1 Parameters of the IceLake-SP cache hierarchy. . . . . . . . . . 8Table 4.1 Attack accuracy metrics for different threshold pairs. . . . . . . 40Table 4.2 Number of runs required for full key recovery of different keylengths and threshold pairs. . . . . . . . . . . . . . . . . . . . 40viiiList of FiguresFigure 1.1 Compilation and interpretation pipelines. . . . . . . . . . . . 3Figure 3.1 QuickJS interpretation pipeline. . . . . . . . . . . . . . . . . 20Figure 3.2 QuickJS bytecode instructions of modExp while loop and thememory layout of QuickJS runtime system. . . . . . . . . . . 25Figure 3.3 A snippet of bytecode handler invocation trace collected by in-strumenting QuickJS. Each dot represents one bytecode han-dler invocation. The secret bits lsb extracted from the plot are00101000. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27Figure 3.4 The left plot shows the PSD spectrogram of cache accesseswithin goto8’s cache set during modExp’s execution. Theright plot shows the PSD of an unrelated cache set. The redscatters indicate the local peaks. . . . . . . . . . . . . . . . . 30Figure 3.5 STFT spectrogram of goto8’s invocations. The bright lines be-tween the start and end correspond to the fundamental and har-monic frequencies during modExp. The dim lines indicate noise. 31Figure 3.6 Distribution of the Predicted Positive Rate of N=4096 bits se-cret key in M=4096 runs. . . . . . . . . . . . . . . . . . . . . 35Figure 4.1 Attack accuracy across different 4096-bit keys. . . . . . . . . 38Figure 4.2 Attack accuracy with increasing number of runs. The thresholdis set to (90%, 90%) and the x-axis is presented on a logarith-mic scale. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39ixFigure 4.3 Number of uncertain bits the attacker shall enumerate to achievea complete and accurate key recovery. . . . . . . . . . . . . . 41Figure 4.4 The distributions of PPRi for {ek}ii−4 corresponding to {00000}and {11110}. . . . . . . . . . . . . . . . . . . . . . . . . . . 43xAcknowledgmentsI would like to sincerely thank my advisor, Prof. Aastha Mehta, for her constantsupport and insightful guidance throughout this research.I also appreciate Prof. Margo Seltzer and Prof. Reto Achermann for servingon my committee. Their thoughtful feedback and constructive suggestions havegreatly improved the quality and clarity of this work.Many thanks to Kjell Dankert, Aidan Shields, Marcus Lai, and Ngoc Bui, fortheir help in this project.I’m thankful to all my friends and Systopians for their support and companyover the years.Finally, I want to thank my parents. I wouldn’t have made it this far withouttheir encouragement and support.xiChapter 1IntroductionIn Cache-timing (or simply cache) side-channel attacks, an attacker is co-locatedwith a victim on a physical machine without direct access to the victim’s secretdata. However, the attacker can infer secrets from the victim program by exploit-ing observable cache side effects of the victim program’s execution. When theCPU executes the victim program, the CPU accesses the program’s instructionsand input data, loading them from memory into the cache. The attacker monitorsthese cache activities, identifies correlations between the program’s cache behaviorand its inputs, and infers the secret input to the program.Cache side-channel attacks come in several variants, each exploiting differ-ent mechanisms. Some leverage shared memory to monitor cache lines [YF14,GMWM16, GSM15, BMME20]. Some do not require shared memory, insteadrelying on a cache set contention [LYG+15, PTV21, DKPT17, OST06, Per05,IES15]. Typically, these attacks target the last-level cache (LLC), because theLLC is shared across all physical cores, enabling the attacker to attack a victimon a different physical core, or even a different processor in a cache-coherencemulti-processor system.All cache side-channel attack variants generally follow a similar sequence ofsteps:1. The attacker identifies the instruction execution sequence or data access pat-tern corresponding to secret-dependent computations in the victim applica-tion.12. The attacker determines the access latency thresholds for each cache leveland DRAM on the target machine.3. The attacker identifies the target cache lines or cache sets to which the targetinstruction sequence or data segment maps at execution time.4. The attacker prepares the shared cache by setting it to a specific initial state.5. The attacker observes the changes in the cache state via the access latenciesto the target cache lines or sets.6. Based on the cache state changes, the attacker deduces the instruction se-quence or data segment accessed by the victim, and subsequently, the secretthat triggered such accesses.Cache side-channel attacks often target cryptographic libraries, particularlythose implemented in statically typed languages such as C [LZJZ21], where eachsource code statement is directly compiled into a corresponding sequence of ma-chine code instructions. Specifically, control flows in the source code map tobranch instructions, while array accesses translate into memory load and store op-erations. During program execution, attackers can monitor which machine codeinstructions are accessed to deduce the control flow and infer the predicate value ofa conditional branch or the target address of an indirect branch. They can also ana-lyze memory accesses to specific data segments to learn array subscripts. In cryp-tographic libraries, these conditional branch values and array subscripts frequentlycontain information about secret keys. For instance, during modular exponentia-tion in RSA algorithms [Gor98], the secret key directly determines the program’scontrol flow through secret-dependent conditional branches. Similarly, in AES en-cryption, the substitution-box lookup results in distinct data access patterns basedon the secret key [BM06].Despite the widespread use of language runtime systems in cloud environmentsand browser-based applications, cache side-channel attacks have rarely been stud-ied in the context of runtime systems. Applications relying on these systems—typically written in dynamically typed languages such as JavaScript or Python—arenot directly compiled into native machine code but are translated into intermedi-ate representations (i.e., bytecode) and executed through interpretation. Figure21.1 shows the typical compilation and interpretation pipelines. During interpre-tation, the runtime system maintains a virtual machine that decodes the bytecodeand processes the bytecode operations with the built-in bytecode handlers. Theruntime system itself becomes the program that is directly running on the CPU.Since the runtime system executes instructions on behalf of the application, it isdifficult for the attacker to identify which instruction sequences correspond to ap-plication logic. Additionally, runtime systems manage dynamic memory allocationfor the application and translate source-level object accesses into dynamic memoryoperations, making it harder for attackers to correlate memory access patterns withspecific object operands. These extra abstractions of interpretation in the runtimesystem complicate the correlation between cache behavior and secret inputs.Figure 1.1: Compilation and interpretation pipelines.To exploit cache side-channel attacks against applications running within lan-guage runtime systems, attackers have to adopt a different attack strategy. Unlikeattacks on native applications, simply observing the runtime system’s access tobytecode instructions of the application running within the runtime system pro-vides limited information. This is because bytecode instructions are highly com-3pact, and for many branch statements (e.g., if-statement) in the source code, neitherof the two translated bytecode execution paths occupies a single cache line exclu-sively. Since the cache line is the basic unit of the cache, subtle differencesin execution paths within one cache line are indistinguishable using cache side-channel attacks. To address this observation limitation, the attacker can focus onmonitoring the execution of individual bytecode handlers. Each bytecode handlercorresponds directly to a specific bytecode instruction, and since bytecode handlersare compiled into native machine code, they often span one or more cache lines,making them highly observable in cache side-channel attacks.However, targeting the bytecode handlers of the runtime system introducesadditional challenges. First, bytecode instructions are general. Individual byte-code instructions often appear in multiple parts of an application, including bothsecret-dependent and secret-independent computations. The attacker then needs toidentify a sequence of bytecode instructions that distinctly correspond to a secret-dependent computation and distinguish it from the rest of the computations in theapplication.Second, the execution of the language runtime system introduces additionalnoise to cache side-channel attacks. Beyond the regular system and backgroundnoise from kernel activities and other programs, speculative execution in the run-time system creates significant speculation noise. This is a consequence of howthe runtime system orchestrates control flow between bytecode handlers throughindirect jumps. Modern CPUs use the indirect branch predictor to optimize theindirect jumps and a wrong prediction leads to speculation noise. For example, ifthe CPU finds that the runtime system jumps from bytecode handler h1 to h2 inthe recent jump history, it may speculatively fetch and execute h2 after executingh1. However, when the runtime system should jump to h3 after h1, the CPUmight still speculatively execute h2 based on the jump history. In this case, thecache state changes due to the speculation noise rather than the actual executionof the victim application. Such noise prevents the attacker from making accurateinferences about the victim application’s execution.In this work, we address the above challenges and answer the question:“Can cache side-channel attacks be exploited against applications executed withinlanguage runtimes?”. We perform a case study on a cryptographic library4OpenPGP.js [Ope24b] over a popular JavaScript runtime, QuickJS [BG24]. Weidentify the cache side-channel vulnerability in the RSA implementation ofOpenPGP.js running on QuickJS and demonstrate an end-to-end attack to exploitit.Specifically, we make the following contributions:- We analyze the QuickJS runtime system and the modular exponentiation func-tion in the OpenPGP.js RSA implementation, identifying the cache side-channelvulnerabilities. In particular, although the modular exponentiation functionadopts timing side-channel mitigations in the source code, it remains vulnera-ble to cache side-channel attacks. This is because the secret-dependent branchin the implementation leads to two different execution paths that differ in onebytecode instruction. Based on the difference of one bytecode instruction, weidentify the distinct sequences of bytecode instructions that correspond to thesecret-dependent branch and infer the secret key.- We develop an approach to identify the target cache set for the bytecode handlers.We combine the short-time Fourier transform [Gab46] and power spectral den-sity [Wel67] to identify the fixed-frequency access patterns of bytecode handlersby the victim application within a specific time window.- We analyze the sources of noise when attacking the language runtime systemand develop methods to mitigate its impact. To address system and backgroundnoise, we monitor multiple cache lines simultaneously and thereby reduce theeffect of noise in an individual cache line. Regarding speculation noise, we ob-serve that mispredictions during the interpretation of the RSA algorithm occur asprobabilistic events rather than deterministic ones. By repeating the experimentand analyzing the probability of occurrence, we can statistically differentiate be-tween actual execution and wrong speculation, effectively overcoming the noise.- We demonstrate an end-to-end attack on the RSA implementation in OpenPGP.jsexecuted within QuickJS on the modern Intel Ice Lake SP processor with twoexisting cache side-channel attack primitives, namely Flush+Reload [YF14] andPrime+Scope [PTV21]. Under the interference of speculation noise, our attackachieves 75% accuracy in a single run. We show that speculation noise can be5eliminated through an iterative process of repeated experimentation, and achieve99% accuracy within only 32 runs.The rest of the thesis is organized as follows: In Chapter 2, we provide the nec-essary background on cache side-channel attacks, language runtime systems, andexisting research on side-channel attacks targeting language runtime systems. InChapter 3, we present our method for attacking language runtime systems. Chapter4 shows the evaluation of our attack. Finally, we conclude the thesis and discussthe future work in Chapter 5.6Chapter 2Background and Related WorkThis chapter begins with a brief overview of the memory hierarchy and cache ar-chitecture of modern Intel processors in Section 2.1, followed by an introduction tocache side-channel attacks on non-inclusive cache hierarchy in Section 2.2. Section2.3 explores runtime systems and their internal interpretation. Finally, we reviewthe related work on leveraging side-channel attacks against language runtimes inSection 2.4.2.1 Memory and Cache ArchitectureIn modern Intel architectures, memory hierarchy is typically structured in layers,with each layer differing in access latency, size, and cost. Registers provide thefastest access latencies, followed by various levels of cache (L1, L2, and L3, withL4 available in certain architectures), and finally the main memory. L1 and L2caches, being private and close to the CPU cores, offer the quickest access timesbut are limited in size. The last-level cache (or simply LLC), most commonly L3,offers larger capacities and is shared among multiple CPU cores. The L1 cachefurther consists of separate data (L1D) and instruction caches (L1I), while L2 andLLC caches are unified for data and instructions caching. In addition to accessingthe L1, L2, LLC, and DRAM, a core can also fetch data from the private cacheof another core. We refer to such an access as a “remote L2 access” [YSG+19].A remote L2 access is slower than an L3 access but faster than a DRAM access.7Table 2.1 shows the key parameters of the IceLake-SP cache hierarchy utilized inour study.Component SpecificationL1 Instruction Cache 32 KB, 8-way associativeL1 Data Cache 48 KB, 12-way associativeL2 Cache 1.25 MB, 20-way associativeLLC (L3) Two 12-way non-inclusive LLCs, 12 MB eachAccess Latencies CPU CyclesL1 Cache [61, 66]L2 Cache [67, 90]L3 Cache [91, 160]Remote L2 [161, 300]DRAM [301, 600]Table 2.1: Parameters of the IceLake-SP cache hierarchy.Intel’s cache design involves the following important aspects: cache placementpolicy, cache replacement policy, cache slices, cache inclusion policy, and cachecoherence.Cache Placement Policy Cache placement policies describe where a particularmemory can be placed in the cache. The basic unit of cache placement is the cacheline, each of size B byte, with 64 bytes being a common standard. All memory isviewed as partitioned into blocks equal to the cache line size for cache transfer.As caches do not support partially-filled cache lines, even if the CPU requests asingle byte, the entire block containing the target byte will be cached. Intel cachesare implemented to have W ways of set associativity, with each way consisting ofS sets of cache lines [Int23]. The low-order log2B bits of a memory address arethe cache line offset. The next log2S bits are the cache index to which the memoryaddress belongs.Cache Replacement Policy Entering a new cache line into a full cache set requiresevicting one existing cache line from the set. Contemporary Intel processors usea complex replacement algorithm, which approximates least-recently-used (LRU),to deterministically identify the eviction candidate based on access patterns within8the cache set [PTV21].Cache Inclusion Policy In the multi-level cache hierarchy, the cache inclusionpolicy describes whether all cache lines in a higher level (e.g., L2) cache are presentin a lower level cache (e.g., LLC). Broadly, there are three types of policies: in-clusive, exclusive, and non-inclusive. An inclusive cache contains all cache linesin the higher level cache. For example, if an LLC is inclusive of the L2 cache,all cache lines in the L2 are also present in the inclusive LLC. An exclusive cachedoes not contain any cache line in the higher level cache. A non-inclusive cachemay or may not contain a cache line in the higher level cache. With the increase incore count on modern CPUs, the replication of cache lines in private caches and aninclusive LLC leads to inefficient cache utilization. Therefore, Intel transitioned tousing a non-inclusive LLC starting with Skylake architecture [TMH+18].Cache Slices Modern Intel CPUs divide the last-level cache into cache slicesconnected by a ring interconnect. The number of cache slices may corre-spond to the number of physical cores or logical cores, although starting fromthe Alder Lake architecture, it can also be a non-power-of-two count [GSFS24].To achieve a more balanced and efficient utilization of these cache slices, physicaladdresses are distributed among the cache by an undocumented non-linear hashfunction [GSFS24, MSN+15, YSG+19].Cache Coherence Intel processors use the MESI (modified, exclusive, shared,invalid) cache protocol to maintain consistency with internal caches and cachesin other processors [Int24]. When a private cache holds a dirty cache line, thecache line has a modified coherence state (M). If the cache line is clean and is notpresent in any other cache, the coherence state is exclusive (E). When multipleprivate caches share the cache lines, the cache lines are in the shared state (S).The Snoop Filter (SF) [TMH+18], a distributed in-memory directory structure,is implemented to maintain the coherence state of each cache line. The coherencestate is stored in metadata stored within the line itself in memory. According toprior work [YSG+19], the SF has the same number of slices, sets, and the slice9hash function as the LLC. SF tracks the cache lines in the states of M and E,and the LLC tracks the cache lines in the state of S. When a cache line transitionsbetween S and either M or E, the corresponding entries in the LLC and SF are freedand allocated accordingly. Most of the time, the SF evicts cache lines like a first-in-first-out (FIFO) queue, irrespective of the actual replacement policy [PTV21].2.2 Cache Side-Channel AttacksCache side-channel attacks [Koc96] are a type of side-channel attack that allowsan attacker to infer secret information from a running program by monitoring itsuse of caches.Prior research has revealed three main types of exploitation: time-driven, trace-driven, and access-driven. In time-driven attacks [OST06], the attacker observesthe overall execution time of an operation. In trace-driven attacks [cK06], anattacker profiles a trace of cache hits and misses during the program’s execution.In access-driven attacks, the attacker determines the cache sets accessed by thecipher and infers which element the victim accessed [GBK11, NS07]. Modernside-channel attacks usually target the shared LLC and combine all the timing,trace, and access information to construct a comprehensive attack.In an end-to-end LLC side-channel attack, the attacker must first analyze thevictim’s source code, either manually or automatically [GSM15], to identify thetarget addresses to monitor. Then the attacker has to achieve co-location withthe victim on the same physical host, and locate the corresponding cache lines tothe target addresses. Finally, the attacker repeatedly executes the following threeattack steps to monitor access to the target cache line over a period of time:1. The attacker forces eviction of a victim’s cache line, typically to DRAM,leveraging the interference between the attacker and the victim.2. The attacker waits a short period for the victim to perform computation. Thevictim’s cache access pattern may vary according to different secret inputsduring this period, potentially bringing the target cache line into a differentmemory level, typically private L1 and L2 caches.3. The attacker times certain access to the target or related addresses. Depend-10ing on the access latency, the attacker infers which memory level the targetcache line is in and thus whether the victim has accessed the target cacheline in the waiting period.Based on the type of interference: sharing or contention in the first step, an-other classification method divides cache side-channel attacks into reuse-based at-tacks and contention-based attacks. Reuse-based attacks rely on shared memorybetween the attacker and the victim. The attacker can evict its own address toachieve eviction of the victim’s cache line. Such sharing is usually a consequenceof dynamic library or memory deduplication. The contention-based attacks relyon contention between the attacker’s and victim’s cache lines in the same cachesets. The attacker achieves eviction by exploiting the cache set contention andcache replacement policy. Reuse-based attacks are less feasible as these attacksrely on memory de-duplication techniques [AEW09, Wal02, FHN+07, GLV+08],which are usually disabled due to security concerns [Bro24, AWS24a, SKLG22].In contrast, contention-based attacks are widely applicable, because they target thephysically shared LLC across multiple physical cores.We now introduce three well-known cache attack primitives: Flush+Reload,Prime+Probe, and Prime+Scope. Our evaluation includes both Flush+Reload andPrime+Scope, with the primary focus on Prime+Scope.Flush+Reload Flush+Reload [OST06] is the most well-known reuse-based at-tack. It leverages the clflush instruction, which is accessible to all privilegelevels, to interfere with the victim’s cache line. In the first attack step, the attackeruses clflush to force the target cache line and all its copies in the cache hierar-chy into a state of Invalid I. In the second step, the victim may load the cache lineand perform computation, causing the cache line to return to caches. Lastly, theattacker reloads the cache line again and checks if the cache line is from DRAMor cache measuring the access latency. Because clflush and memory read oper-ation can target a single cache line, the Flush+Reload attack has a cache line levelgranularity and will not result in cache latency when the victim has not accessedthe target address. Yet, when the victim’s memory operation to the target cacheline overlaps with the attacker’s clflush or reload operations, the attacker may11still miss the victim’s access.Prime+Probe Prime+Probe [OST06] is a representative of contention-based at-tacks. It constructs an eviction set to evict the target cache line, cl, from certaincache levels. The eviction set consists of addresses that are mapped to differentcache lines belonging to the same cache set s as the target cache line cl. Onceaccessing the eviction set, any cache lines in s will be evicted. For a W -way setassociative cache, an eviction set contains at least W addresses that are mapped tos, and if the eviction set contains exactly W addresses, it is a minimal eviction set.The attacker has to construct a minimal eviction set, ev set, to create a mutual evic-tion relation between the eviction set and the target cache line. In the first attackstep, the attacker accesses ev set to occupy the entire cache set and also evict thetarget cache line cl. In the second step, the victim’s access to the target cache linewill evict one of the addresses in ev set. In the third step, the attacker accesses allthe addresses in ev set again and times the overall access latency to check if anyaddresses in ev set are evicted from the cache. Since multiple addresses share asingle cache set, system or other user activities between Prime and Probe phasescan evict some addresses in ev set and make the attacker falsely infer the victim’sactivity. Moreover, the aggregation of the access latency to all addresses in ev setamplifies single latency variation, making the measurement sensitive to the systemnoise.Prime+Scope Prime+Scope [PTV21] extends the Prime+Probe attack by exploit-ing the cache replacement policy. Prime+Scope uses a special access pattern to en-sure that a specific address, called the eviction candidate , EVC, in the eviction set,has the highest eviction priority. As a result, when the victim accesses the targetcache line, EVC will be the first to be evicted. Instead of examining all addressesin ev set, the attacker examines the presence of the EVC in the cache to determineif the victim has accessed the target cache line. Prime+Scope therefore reduces theprobe overhead and obtains better resilience to noise.12Side-Channel Attacks on Non-inclusive Cache Hierarchy A non-inclusive cachehierarchy makes cache side-channel attacks more complicated. In an inclusivecache, evictions in the higher-level cache can trigger evictions in the lower-levelcache, and the presence of data in the lower-level cache can ensure its presencein the higher-level cache, enabling attackers to carry out cross-core attacks usingFlush+Reload [YF14] and Prime+Probe [LYG+15].However, modifications are needed to adopt those attacks on a non-inclusivecache hierarchy. Flush+Reload attacks do not need to change in their first andsecond steps for non-inclusive LLC because clflush instruction, the cornerstoneof Flush+Reload, invalidates the cache line from all levels of the processor cachehierarchy. The invalidation is broadcast throughout the coherence domain [Int23],including all the private caches in different physical cores. The only change innon-inclusive LLC is that the target cache line is not necessarily present in LLC,after the victim’s access in the second attack step. Thus, the attacker has to classifythe remote-l2 access latency to the victim’s access and DRAM access latency to novictim’s access.Prime+Probe attacks require an LLC eviction set to interfere with the victim’scache line. Such interference does not exist in a non-inclusive LLC, as the victim’scache lines in the private caches will not be affected by the contention in the LLC.However, prior research discovered that the cache line will be evicted from theprivate cache when it is evicted from the snoop filter (SF) [YSG+19]. Thus, theattacker can build an SF eviction set and exploit the shared SF contentions to inferthe victim’s activity. Additionally, Prime+Scope demonstrates that the FIFO-likeeviction behavior of SF can be leveraged to identify the EVC and execute attackson non-inclusive cache hierarchies.2.3 Runtime SystemsA runtime system, or runtime for short, refers to the software framework respon-sible for the dynamic management of program execution [Sco09]. A runtime me-diates interaction between the application and the OS whilst managing language-specific components, such as memory management, garbage collection, variableaccess, parameter passing, dynamic linking, and exception handling.13Some languages have extensive runtime systems and are heavily dependenton the language runtime system for execution. These are usually referred to asvirtual machines, e.g., JVM [LYBB14], or interpreters, e.g., V8 [Goo24] andCPython [Fou24]. Such language runtime systems use an intermediate represen-tation (IR) to decouple symbolic programming language representation from thetarget instruction set architecture [LYBB14]. Language runtimes can interpret theIR in a virtual machine without translating the IR to machine code. Some runtimesmay use a just-in-time (JIT) compiler to translate the IR to machine code based ondynamic profiling of the running program and avoid the overhead of interpretingthe IR.For the interpretation pipeline, the language runtime typically uses bytecode asthe intermediate representation and implements a virtual machine embedded in itsbytecode interpreter. The bytecode is the conceptual machine code for the inter-preter’s virtual machine. Each bytecode instruction starts with an opcode followedby a fixed number of operands. For each opcode, the runtime system uses a spe-cific bytecode handler to simulate the execution of the bytecode instruction in itsvirtual machine. To manage the control flow of bytecode instructions, the inter-preter maintains the addresses of all bytecode handlers in a dispatch table. At theend of each bytecode handler’s execution, the interpreter will fetch the opcode ofthe next bytecode instruction and look up the dispatch table to find the correspond-ing bytecode handler for the next bytecode instruction. The control is then handedoff to the next handler via an indirect jump. In the entire interpretation path, thebytecode is never compiled into native machine code and all the computations hap-pen in the interpreter’s virtual machine. The execution of different bytecode han-dlers leaves different cache access traces, which an attacker can observe, furtherleading to a cache side-channel leakage.For the JIT compilation pipeline, the language runtime may generate and op-timize the machine code tailored to the specific architecture by profiling the run-ning application. The runtime system for a dynamically-typed language, such asJavaScript engine V8 [Goo24], typically relies on JIT compilation. Before JITcompilation, the runtime still interprets the bytecode and collects the required in-formation for compilation. Once the runtime system has collected enough infor-mation, it further compiles the bytecode instructions into native machine code. At14this stage, the machine code execution is similar to the execution of native appli-cations. In this work, we ignore the JIT pipeline of the language runtime system,particularly the behavior of machine code execution, as it has already been coveredin prior side-channel research.QuickJS QuickJS is a small and embeddable Javascript engine, used in AWSLLRT (Low Latency Runtime)[4]. The full support for the JavaScript specifica-tion, ECMAScript [TC323], and the lightweight design of QuickJS make it adesired solution to address the growing demand for efficient memory usage andswift startup for serverless applications.QuickJS does not have a JIT compilation pipeline, it does pure interpretation ofthe bytecodes as a stack machine. The internal bytecode handlers are structured asa dispatch table, each element of which is an address to a bytecode handler. At theend of each bytecode handler, the interpreter decodes the next bytecode instruction,looks up the dispatch table using the opcode, makes an indirect jump to the nextbytecode handler, and continues interpretation.2.4 Side-Channel Attacks on Runtime SystemsLanguage runtime systems are extensively used in both cloud and browser environ-ments. In cloud environments, the co-location and hardware sharing between mu-tually untrusted tenants create the foundational conditions for cache side-channelattacks [AWS24a, ZMFT24b, ZMFT24a, FWN+22]. In browser environments, theexecution of scripts from different origins within the same machine enables poten-tial side-channel exploitation [OKSK15, SAO+21]. These scenarios highlight thefeasibility of side-channel attacks targeting runtime systems.Daniel et al. [GPTY18] demonstrated the feasibility of conducting cacheside-channel attacks with portable JavaScript code in a browser environment.They show Elliptic’s [Ind24] Point Multiplication function, a supposedly secureconstant-time algorithm, is vulnerable. However, they claim that leaking the key-dependent if-else control flow in the Elliptic Point Multiplication function is notfeasible, since both cases call the same functions in the same order and have thesame length.15Instead, they identify the secret-dependent control flow by the runtime’s se-lection of different execution paths on different operands. However, our analysisshows that the secret-dependent control flow in the intermediate bytecode repre-sentation can be leaked through the use of bytecode handlers.Timing leakages in the runtime systems have been more extensively stud-ied. Researchers have identified that JIT compilation can induce timingside channels [BRB20, BSB20] and explored mitigation to JIT-induced timingleaks [QJS+22]. Their focus has been primarily on timing side channels, withoutaddressing cache-related leakage. In our evaluation, we show that the applicationwith timing side-channel mitigation is still vulnerable to cache-timing side-channelattacks.16Chapter 3Cache Side-Channel Attack onLanguage RuntimeWe present our insights on attacking the language runtime to indirectly infer thesecrets of the application running on the runtime. We focus on the interpretationpipeline of the language runtime and use a lightweight JavaScript engine, QuickJS,as the underlying language runtime system in this work. We also perform a casestudy on the implementation of the RSA algorithm in OpenPGP.js.We first describe the threat model in Section 3.1 and explain the workflow ofan end-to-end attack in Section3.2. In Section 3.3, we analyze the different secret-dependent behaviors that QuickJS runtime may exhibit during interpretation, andwe use the OpenPGP.js RSA as a running example. In Section 3.4, we study theapproach to differentiate the cache set that reflects the invocation of specific byte-code handlers. Last, we examine how to recover secrets from cache access tracesin Section 3.5.3.1 Threat ModelWe assume that the victim deploys an application that is interpreted and ex-ecuted in a language runtime (e.g., CPython [Fou24], Node.js [Ope24a], orLLRT [AWS24b]) and runs vulnerable open-source libraries to handle confiden-tial computations. In our case, we use QuickJS [BG24] as the language runtime17and OpenPGP.js [Ope24b] as the vulnerable library. The attacker knows and hasaccess to the source code of the vulnerable library and language runtime the vic-tim is using, such that the attacker can analyze and profile to collect the necessaryinformation locally to launch an attack.The end goal of the attack is to infer confidential information, such as the en-cryption key of a running application interpreted in the language runtime. Theattacker runs a process on the same host but on physical cores different from thevictim application, with the last-level cache and snoop filter shared among the at-tacker and the victim’s physical cores. We assume the attacker cannot compromisethe kernel to elevate their privileges or obtain any form of direct access to the vic-tim’s memory, but they can access the x86-64 unprivileged instruction RDTSCP asa high-resolution timer.We assume the attacker can invoke the victim application as they want to triggerthe secret-dependent computation. However, the requirement is not necessary in areal attacker scenario where there exists a third-party user or entity that invokes thevictim applications and the attacker can monitor the victim application’s activitypassively.We primarily focus on the contention-based attack primitive Prime+Scope forthe remainder of this thesis, as we do not assume any sharing of memory betweenthe attacker and the victim. The assumption is consistent with current policies oncloud platforms that disallow any sharing of memory between mutually distrustingtenants [AWS24a]. However, if the attacker knows that such memory sharing isavailable in their attack scenario, they may use reused-based attack primitives tosimplify the attack. When memory sharing is not available, the attacker also hasno information on the actual physical addresses to which the language runtime ismapped. The attacker may know the virtual address and memory layout of thecode segment of the language runtime since the language runtime’s source and itsbinary file are publicly available.3.2 Attack WorkflowThe attack workflow of an end-to-end cache side-channel attack depends on thevictim’s application, while in general, an end-to-end attack consists of two phases:18the profiling phase and the attack phase.In the profiling phase, the attacker gathers all necessary information for theattack through static analysis or dynamic profiling. The attacker first identifiesthe target application, which, in the context of language runtime systems, con-sists of both the language runtime system and the application running on top ofit. The target application must contain a source of leakage, commonly throughsecret-dependent computations, such as secret-dependent control flow or data ac-cess. The attacker must identify the memory addresses involved in these computa-tions, analyze their access patterns, and develop a method to extract the secret fromthe observed memory access. Furthermore, since cache side-channel attacks typi-cally have the cache line or cache set granularity with a fixed time resolution, theattacker must examine whether the memory accesses align with these constraintsby experimentally profiling the target application. The attack then determines ac-cess latency thresholds for each cache level and DRAM, depending on the specificcache side-channel attack primitive employed. Finally, the attacker must find thetarget cache lines or cache sets that target memory addresses map to at the victim’sexecution time.In the attack phase, the attacker executes the attack primitives (e.g.,Flush+Reload and Prime+Scope), collects the cache access trace, and recovers thesecrets from the trace. Each attack primitive monitors the target cache line or cacheset and reports a detection when access to the cache line or set is observed. The at-tacker executes the attack primitive over a period of time to collect a time series ofdetections, forming the cache access trace. This trace may include cache accessesresulting from secret-dependent computations in the target application, as well asnoise from unrelated computations in the target application, system, or other appli-cations. The attacker must identify whether the trace contains accesses related tothe target’s secret-dependent computation, and if so, filter out the noise and recoverthe secret from the trace.193.3 Identifying Leakage within the QuickJS Runtime3.3.1 Sources of Leakage in QuickJS InternalsTo understand the sources of leakage in language runtime systems, we first explainthe entire execution pipeline in QuickJS. QuickJS executes a JavaScript programin a pure interpretation pipeline. It first parses the JavaScript source code andtranslates the source code into bytecode instructions. As indicated in Figure 3.1,each bytecode instruction begins with its opcode followed by a certain number ofoperands. For each opcode, QuickJS implements a specific bytecode handler func-tion to parse the operands and simulate the opcode operation. All bytecode handlerfunctions are maintained in a dispatch table. At the end of a bytecode handler,QuickJS reads the opcode of the next bytecode instruction and hands control overto the next corresponding bytecode handler. QuickJS continuously loads bytecodeinstructions and executes the corresponding bytecode handlers without altering thecontrol flow until a function completes execution and returns.Figure 3.1: QuickJS interpretation pipeline.During interpretation, QuickJS reflects three types of secret-dependent be-20havior of the running application, 1) bytecode instruction access, 2) operand ac-cess, and 3) bytecode handler invocation. These three secret-dependent behaviorspresent three different sources of leakage, each with varying exploitability and con-straints.Bytecode Instruction Access First, access to the bytecode instructions reveals thebytecode control flow. By inspecting bytecode instructions, an attacker collectsthe execution trace of the running application. The execution trace of bytecodeinstructions reveals the control flow and enables the attacker to further deduce thepredicate values of conditional branches. However, this leakage is limited by thenature of cache side-channel attacks, which can observe only one cache line ata time. It becomes infeasible for an attacker to determine the control flow whenthe different execution paths of a conditional branch do not exclusively occupyseparate cache lines. Since bytecode instructions are highly abstract and compact,with the majority being five or fewer bytes, an if-else statement may occupy onlyone cache line and prevent leakage.Operand Access Another source of leakage arises from the data access to vari-ables in the language runtime. For two bytecode instructions with the same opcodebut different operands, the runtime uses the same bytecode handler for interpre-tation, but the handler accesses different memory locations to fetch different vari-ables, thus leaking the operands in the bytecode instruction. However, QuickJSallocates variables dynamically on the heap, and the memory location of variablesmay change over multiple function invocations. The attacker might be unable topredict the address of the target variable to cause a leakage.Bytecode Handler Invocation Invocation of the bytecode handler introduces anew source of leakage. Since the bytecode handlers are compiled into machinecode that spans one or more cache lines, the attacker can easily monitor individualbytecode handlers and collect a trace of the bytecode handler’s invocation. Theinvocation of a bytecode handler can correlate with the execution of bytecode in-structions with the corresponding opcode and further reveal the detailed control21flow. In theory, monitoring all bytecode handlers simultaneously would allow theattacker to track every bytecode instruction executed by QuickJS and reconstructthe control flow precisely. Monitoring a large number of cache lines is challenging,as it significantly reduces the time resolution at which the attacker can observe thevictim’s execution. Additionally, monitoring an extra bytecode handler requiresadditional memory accesses, further increasing the noise in the attacker’s observa-tions. Thus, the attacker attempts to monitor as few bytecode handlers as possible.However, monitoring a limited number of bytecode handlers implies that the at-tacker is blind to what QuickJS executes in between any pair of consecutive byte-code handler invocations, making it difficult to reconstruct the concrete executionof the application.To address the above challenge, the attacker can leverage the Fingerprint ofthe secret-dependent computation. Let BC denote the complete set of bytecodeopcodes intrinsic to the language runtime, C denote the representation of a compu-tation process at the bytecode level, indicated as C= {(opi,operandsi) | opi ∈BC},and Input denote the secret input that determines the control flow of C. The finger-print of a computation C on a bytecode set BC for a given input Input is an orderedsequence describing a concrete control flow of C. Each element of the finger-print sequence consists of a bytecode opcode and a time difference, as denoted byF(C,BC, Input) = {(opi, tdi) | opi ∈ BC}. The time difference represents the dif-ference between the invocation times of the corresponding bytecode handlers foropi−1 and opi during the runtime system’s actual execution. Specially, td0 denotesthe time difference between the invocation of op0’s handler and the starting timeof C. The fingerprint inherently reflects how the input Input influences the controlflow C, and consequently, even without directly observing Input, the attacker caninfer Input from F(C,BC, ).Since monitoring every opcode is impractical, the attacker selects a sub-set BCM ⊆ BC to monitor the execution of C, first uses F(C,BCM, ) to in-fer F(C,BC, ) and eventually infers the secret Input. For any monitoring setBCM, the attacker should find the corresponding monitoring set of cache lines,CLM = {rc(opi) | opi ∈ BCM}, where rc(op) is the representative cache line forthe bytecode handler of op. The attacker then monitors CLM over a time win-dow T = [Tstart,Tend] and collects the invocation trace of BCM during T , denoted22as T (CLM,T ) = {(rc(opi), tsi) | opi ∈ BCM, tsi ∈ [Tstart,Tend]}ni=1. Here, tsi is theabsolute timestamp at which opi is executed. The attacker must carefully selecta minimal but sufficient monitoring set BCM such that F(C,BCM, ) satisfies thefollowing criteria:1. From F(C,BCM, ), the attacker can infer the complete fingerprintF(C,BC, ) of C.2. Given T (CLM,T ), the attacker can determine whether F(C,BCM, ) appearsas a subsequence. If it does, the attacker can extract F(C,BCM, ) fromT (CLM,T ).The attacker can derive a minimal monitoring set BCM that satisfies the cri-terion 1 through an analysis of the bytecode instructions of C. The combina-tion of opcodes and the time-frequency feature grants the uniqueness of a finger-print F(C,BCM, ) to fulfill the criteria 2. When the attacker finds the fingerprintF(C,BCM, ) of the target secret-dependent computation C and F(U,BCM, ) of anunrelated computation U undistinguishable, the attacker may expand the scope ofC to C′ and broaden BCM to BC′M, ensuring that F(C′,BC′M, ) remains distinctive.3.3.2 OpenPGP.js RSA AlgorithmWhen running in the QuickJS runtime, OpenPGP.js provides a pure JavaScript im-plementation of RSA using square-and-multiply exponentiation [Gor98].RSA The RSA algorithm (Rivest-Shamir-Adleman) [RSA78] is a widely usedpublic-key cryptosystem that enables secure data transmission and digital signa-tures. It is based on the mathematical properties of prime numbers and modulararithmetic. The RSA algorithm relies on two keys: a public key (N,e) used forencryption, and a private key (N,d) used for decryption. The RSA key satisfiesthe following conditions:• p and q are large prime numbers• N = pq• e is coprime to (p−1) and (q−1), typically 65537(216+1).23• d = e−1 mod (p−1)(q−1)The RSA signature of a message m is given byS = md mod N.Square-and-Multiply Exponentiation To reduce the timing leakage to side-channel attacks, the OpenPGP.js library adopts a ternary implementation [Ope24c](see Algorithm 1). The algorithm computes r =me % mod n using the square-and-multiply exponentiation. It represents the exponentiation e, part of the secret key,in binary format 2n−1en−1 + · · ·+ 20e0 and calculates a sequence of intermediatevalues xn−1, . . . ,x0 such that xi = m⌊e/2i⌋ mod m. At the i-th iteration of the loop,the algorithm takes the value of the least significant bit lsb of exp, which is equiv-alent to ei. The modular exponentiation algorithm multiplies ei into the result r iflsb = 1.Algorithm 1: modExp(m, e, n)Input: m (message to encrypt), e (exponentiation), n (modulus)Output: Compute modular exponentiation using square and multiply1 exp← e;2 x←m;3 x← x mod n;4 r ← 1;5 while exp > 0 do6 lsb← exp&1 // Extract least significant bit;7 exp← exp≫ 1 // Divide exp by 2 (right shift);8 rx← (r · x) mod n // Always compute multiplicationstep, to reduce timing leakage;9 r ← lsb ? rx : r // Update r only if lsb = 1;10 x← (x · x) mod n // Square x;11 return r;To achieve the conditional update, modExp uses a ternary operation at line9, which is translated into a conditional branch at the bytecode level. Figure 3.2shows bytecode instructions and the control flow graph of modExp on the left,24and the memory layout of the bytecode and corresponding handlers in QuickJSruntime on the right. Depending on the secret value lsb, the false branch jumps tothe basic block BB2 and loads r onto the stack, and the true branch jumps to thebasic block BB3 and loads rx onto the stack. r is further updated by the value atthe top of the stack in basic block BB4. Although the two branches have differentoperands and different numbers of goto8 instructions, the overall execution timedifference between the two branches is equivalent to the execution time of goto8,which is negligible. Consequently, the algorithm reduces timing leakage due to thesecret-dependent selection.Figure 3.2: QuickJS bytecode instructions of modExp while loop and thememory layout of QuickJS runtime system.However, the bytecode instructions contain differences that can be exploited25for leakage, as we describe in the next section.3.3.3 Leakage in OpenPGP.js within the Context of QuickJSFirst, in the false branch, BB2 requires an additional goto8 instruction tomerge the control flow while BB3 does not. Second, the operands to theget loc check instruction, which loads a local variable and pushes it ontothe stack, are different. The attacker may investigate three sources of leakage inQuickJS to transform these differences into leakage in OpenPGP.js.Inapplicable Leakage from Bytecode Instruction Access One potential leakage isfrom the QuickJS’ access to the bytecode instructions. However, the two executionpaths BB2 and BB3 only contain three bytecode instructions and 8 bytes in total.In most cases, these three bytecode instructions are packed into a single cache lineand access to the bytecode instructions of either branch leaves the same cache trace,making the source of leakage unexploitable.Inapplicable Leakage from Operand Access The attacker may exploit the operandaccess pattern in QuickJS to infer the secret lsb, by examining whether r or rxis accessed in each loop iteration. However, since the variables r and rx are dy-namic resources on the heap, every time QuickJS invokes modExp, r and rx arereallocated into dynamic memory locations. The attacker cannot use any informa-tion from static analysis or dynamic profiling to learn the address to r and rx in aspecific modExp run, and thus fails to exploit the operand access pattern.Leakage from Bytecode Handler Invocation The invocation of bytecode handlersprovides a different perspective. For each loop iteration, if lsb = 1, QuickJS fol-lows the false branch and executes an additional goto8 instruction, jumpingfrom BB2 to BB4. The time interval between goto8 executions in BB2 and BB4corresponds to the execution time of BB4, while the interval between goto8 inBB4 (from the previous iteration) and goto8 in BB2 (from the current iteration)corresponds to the execution time of BB1 and BB2. At the true branch, wherelsb = 0, QuickJS executes only the goto8 in BB4. The interval between goto826in BB4 across two consecutive loop iterations corresponds to the combined compu-tation time of BB1, BB3 and BB4. Figure 3.3 shows a sample trace of the goto8and sar handler’s invocation that the attacker may obtain The invocation of sarindicates the start of each loop iteration. From the trace, the attacker can easilydeduce whether the secret value of lsb in each loop iteration is 0 or 1 based on theintervals.0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0CPU Timestamp (×10⁶)Invocationsgoto8 sar0 1Figure 3.3: A snippet of bytecode handler invocation trace collected by in-strumenting QuickJS. Each dot represents one bytecode handler invoca-tion. The secret bits lsb extracted from the plot are 00101000.3.4 Identifying Cache Sets to MonitorWe now elaborate on how the attacker determines (1) the monitoring set BCM andthe fingerprint of the specific victim logic being targeted, and (2) the cache sets towhich the corresponding handlers are mapped at execution time. We explain thedetails in the context of the modExp function within the RSA algorithm.The attacker begins by identifying a minimal monitoring set that distinguishesthe fingerprint of the secret-dependent branch in modExp. Based on the analy-sis in Section 3.3.3, the attacker can choose BCM = {goto8} to obtain uniquefingerprints for the if statement IF on both true and false branches of IF inone loop iteration. To describe the fingerprint, we define TBBi as the executiontime of all instructions in the basic block BBi. Since both BB1 and BB4 containa mod instruction, whose execution time Tmod dominates the total execution time,we consider TBB1, TBB4 and Tmod to be equal. Additionally, our experiments showthat TBB2 and TBB3 are negligible compared to TBB1. Thus, the attacker identifies27the fingerprints of the secret-dependent branch as follows:F(IF,{goto8},True) = {(goto8,2×Tmod)} (3.1)F(IF,{goto8},False) = {(goto8,Tmod),(goto8,Tmod)} (3.2)Next, the attacker verifies whether the fingerprints uniquely identify the whileloop over the secret-dependent branch in modExp. This step is crucial for attack-ing the RSA algorithm, as the attacker must track the position of each bit, whichcorresponds to the loop iteration. The fingerprint of the while regarding the se-cret input e is simply a concatenation (defined as ∥ below) of the fingerprint ofsingle loop iteration:F(LOOP,{goto8},e) =|e|=n∥i=1F(IF,{goto8},cond),where cond := (ei == 0) ∈ {True,False}.(3.3)Although fingerprints based on goto8 are theoretically sufficient for identi-fying the while loop, relying solely on goto8 is not robust in practice. If theattacker misses or misidentifies a goto8 invocation, or if system interruptions in-troduce delays, the time interval may fluctuate, leading to a loss of track of loopiterations. To enhance robustness, the attacker must expand BCM and monitor ad-ditional bytecode handlers. For example, sar, which executes at the start of eachiteration, can serve as a reliable marker for loop iterations. The attacker may alsochoose to monitor mul and mod, but increasing the number of monitored handlersworsens time resolution, increases cache interference, and requires an empiricaltrade-off. For our actual attack, we choose BCM = {goto8,sar} as we found thatthe combination of these handlers provides a robust fingerprint for identifying themodExp computation of RSA and distinguishing the secret-dependent branching28within the computation. We identify the fingerprints as follows:F(IF,BCM,True) = {(sar,0),(goto8,2×Tmod)} (3.4)F(IF,BCM,False) = {(sar,0),(goto8,Tmod), (goto8,Tmod)} (3.5)F(LOOP,BCM,e) =|e|=n∥i=1F(IF,BCM,cond),where cond := (ei == 0) ∈ {True,False}. (3.6)Based on the monitoring set BCM, the attacker now wishes to monitor the cachesets to which the bytecode handlers for sar and goto8 get mapped at executiontime. This is not straightforward because the attacker does not know the virtualaddress to physical address mapping for the bytecode handlers in the victim’s pro-cess.To identify the cache sets for the target bytecode handlers, we leverage the factthat the modExp function exhibits a unique time-frequency pattern. Specifically,the mod instruction causes each loop iteration of the modular exponentiation tohave a stable execution time. Consequently, the time interval between the exe-cution of instructions (e.g., sar-sar and goto8-goto8) across two consecutive loopiterations is also stable. This unique timing pattern enables the attacker to dis-tinguish the fingerprint of modExp from other computations and random systeminterrupts.The attacker can first obtain the time-frequency feature of RSA modExp byinstrumenting QuickJS and profiling the execution frequency beforehand on thesame physical machine. For each opcode op ∈ BCM, the attacker monitors eachcache set, cs, collects the bytecode invocation trace T ({cs},T ), and decides if thecache set corresponds to the desired bytecode handler based on the time-frequencyfeature of F(modExp,{op}, ). The attacker may exploit the fact that virtual andphysical addresses share the lower 12 bits to filter the candidate cache sets tocheck [ZMFT24b].Similar to prior work [ZMFT24b], we use Welch’s method for Power SpectralDensity (PSD) [Wel67] to extract such time-frequency features. Specifically, wemap T ({cs},T ) to a discrete digital signal, where the sampling frequency corre-sponds to the consecutive detection interval of the attack primitives. The sampled29value at time t is 1 if T ({cs},T ) contains a detection at time t, and 0 otherwise.With the same approach, we can map Fingerprint(modExp,{op}, ) to digital sig-nals and obtain the PSD of it. Figure 3.4 shows the PSD spectrograms of a traceof goto8 bytecode handler’s cache set and unrelated cache set, respectively, dur-ing the modExp execution. The PSD estimates the power of a signal at differentfrequencies, and the peaks in the PSD spectrogram represent where the signal’senergy is concentrated. Based on the frequencies and amplitudes of the peaks, theattacker can determine if the cache access pattern in the cache set, T ({cs},T ), isconsistent with goto8’s access pattern, F(modExp,{goto8}, ), and identify thecache set that goto8’s handler maps to.0 8 16 24 32 40 48 56Frequency (KHz)0510PSDgoto80 8 16 24 32 40 48 56Frequency (KHz)0.050.1UnrelatedFigure 3.4: The left plot shows the PSD spectrogram of cache accesses withingoto8’s cache set during modExp’s execution. The right plot showsthe PSD of an unrelated cache set. The red scatters indicate the localpeaks.3.5 Recovering secrets from cache access tracesAfter figuring out the cache sets, the attacker can monitor the target cache setsusing Prime+Scope and collect cache access traces. To extract the fingerprint of thetarget computation from these traces, the attacker must distinguish which accessesare part of the fingerprint and which are caused by other computations or noise.3.5.1 Identifying the Invocation Trace From Cache Access TracesThe collected cache access trace Trace(BCM,T ) includes not only the bytecodeinvocations of modExp but also a sequence of other operations, such as message30generation, hash digest computation, and object to byte-stream conversion, in apractical encryption scenario. Each of these operations may involve the bytecodestargeted by the attacker, such as goto8, sar. The attacker must carefully extractF(LOOP,BCM, ) of the modExp function from this complex bytecode invocationtrace. Since the extraction of the secret key is highly sensitive to the position ofeach bit, an incorrect position, with even a one-bit misalignment can make therecovered secret key entirely incorrect, effectively degrading the attack to randomguesses. To address this, the attacker needs to precisely locate the starting andending time of the modExp loop and then extract the relevant fingerprint.1 1.2 1.4 1.6 1.8 2Time (s)05101520Frequency (KHz)051015start endFigure 3.5: STFT spectrogram of goto8’s invocations. The bright lines be-tween the start and end correspond to the fundamental and harmonicfrequencies during modExp. The dim lines indicate noise.We utilize short-time Fourier transformation (STFT) [Gab46], which leveragesthe time-frequency characteristics of the modExp bytecode invocations. STFTprovides an intuitive representation of whether the signal in a given time windowis concentrated around specific frequencies, as shown in Figure 3.5. By examiningcontinuous and stable frequency patterns, the attacker can identify the first and lasttime window corresponding to modExp loop, extract the invocations within thistime range from the trace to form the fingerprint, and use it for further analysis torecover the secret key.313.5.2 Sources of NoiseThe cache access trace also contains various sources of noise and error that im-pact the attacker’s ability to accurately deduce the original secret input. Generally,these sources of noise can be categorized into three types: (1) system and back-ground noise, (2) noise caused by speculative execution, and (3) detection blindspots [PTV21].System and Background Noise. The language runtime and victim application arenot the only active programs running on the processor. All other programs runningon the same physical machine—including kernel, daemon processes, and other userapplications—also access memory and cache. Such noise and interference causethe cache access traces detected by the attack primitives to include cache accessesunrelated to the language runtime or victim application. As a result, the cachetraces may not accurately reflect the execution of the victim application.Noise from Speculative Execution. Cache states can also change during specula-tive execution by the CPU. When the CPU mispredicts and discards all computa-tion results from transient execution, any modifications to the cache during spec-ulation remain unreverted. Speculative execution typically occurs when the CPUencounters instructions such as conditional branches, indirect jumps, indirect calls,or return statements. If the target address or jump condition is not yet resolvedbecause of slow operations or data dependencies in the pipeline, the CPU predictsa target address based on the Path History Register to avoid pipeline stalling.QuickJS utilizes a dispatch table to implement its control flow mechanism.This dispatch table directs control flow through the use of the goto keyword in C,which translates into an indirect jump in machine code. During this process, theinterpreter performs two memory accesses with data dependencies: one to fetchthe bytecode instruction and another to look up the dispatch table. Due to the slowand dependent memory accesses, the CPU, at the indirect jump stage, speculativelypredicts a bytecode handler and accesses its machine code instructions before it re-solves which bytecode handler should be executed next. The speculation breaksthe correlation from the cache hit to the victim’s execution as the indirect branch32predictor can mispredict and cache the instruction or data that the victim does notaccess. This uncertainty makes the attack inference chain significantly more chal-lenging, as the attacker lacks a clear mechanism to differentiate the actual executiontrace from noise introduced by speculative execution.For instance, as shown in Figure 3.2, if the lsb is 0, the interpreter, after com-pleting the execution of the get loc check rx instruction in the right branch, shouldlogically proceed to execute the dup handler based on the control flow. How-ever, the CPU, based on prior indirection history, might speculatively execute thegoto8 handler instead. In such a scenario, the attacker observes cache accessesrelated to the goto8 bytecode handler’s instructions. However, they cannot dis-tinguish whether these accesses result from the actual control flow or speculativeexecution. Moreover, during the entire execution of the branch where lsb = f alse,there are no other distinct instruction cache or data cache patterns available to helpdetermine whether this branch was executed. The attacker has no means to si-multaneously observe both branches to verify if an incorrect speculative executionoccurred.Blind Spots Another key challenge is that the Prime+Scope technique, which ourattack relies on, cannot guarantee accurate detection of all cache accesses in thevictim. Specifically, during the preparation phase, the attacker evicts the targetcache line from the cache hierarchy. This phase can take hundreds to thousandsof CPU cycles, during which the attacker has a blind spot and cannot observe anyaccesses to this cache line made by the victim application during this time.3.5.3 Countermeasures to NoiseWhile we cannot prevent noise from occurring in the collected trace, our key in-sight is that noise represents a statistically bounded error. By framing the secretrecovering process as a series of decision problems, these bounded errors can bemitigated through repeated experiments.Mitigating System and Background Noise via Multiple Channels. We first needto determine whether a cache access detected in a specific cache set actually corre-33sponds to the execution of a bytecode handler. This can be verified by increasingthe number of monitored cache sets to enable repeated experimentation.Consider a single iteration of the loop in Figure 3.2. In basic block BB1, in-structions such as sar and mod are executed once. Depending on the branch condi-tion, an additional goto8 instruction may be executed, followed by the execution ofmod and goto8 instructions in BB4. During this process, the execution time of modis significantly longer than other instructions. As a result, from a time perspective,the sar and mod instructions in BB1 and the preceding iteration’s goto8 in BB1will occur in a tightly grouped time window, while goto8 in BB2, along with themod in BB4 occur in a subsequent similarly tight time window.By simultaneously monitoring the cache sets corresponding to goto8, sar,mul, and mod, we can verify whether a cache access genuinely reflects the exe-cution of these bytecode handlers, as opposed to being caused by system or back-ground noise. We assume that noise occurs randomly with a certain probabilityor at a fixed frequency unrelated to the loop execution in the modular exponenti-ation process. Thus, if we detect an access in the sar cache channel, we shouldalso observe corresponding accesses in the mul, mod, or goto8 sets. If mul-tiple cache sets simultaneously detect an access, it is highly likely to correspondto a bytecode handler execution. The probability of noise randomly causing si-multaneous detections across multiple cache sets is extremely low, allowing us todistinguish actual bytecode handler executions from noise. In our noiseless ex-perimental environment, monitoring goto8 and sar is sufficient. However, in anoisier environment, monitoring mul and mod might be necessary.Mitigating Speculation Noise via Repeated Runs. In the context of speculative ex-ecution, the decision problem focuses on determining whether an observed instruc-tion cache access for a bytecode handler corresponds to an actual execution in thecontrol flow. While it is theoretically possible to distinguish speculation-inducedaccesses by analyzing the behavior of indirect branch predictors, our experimentalresults did not reveal any deterministic patterns. The explanation for this observa-tion is deferred to Chapter 4. Instead, our empirical experiments with the modExpfunction revealed that, for a fixed set of parameters (m,e,n), the indirect branchpredictor does not consistently make the same predictions across multiple runs.34For each bit of the secret exponent e, speculative execution of the goto8 handlerappears to follow a probabilistic distribution. We validated this experimentallyand demonstrated that this probabilistic behavior can be exploited by attackers toreconstruct the full secret key e.Specifically, for a fixed secret key (e,n) of length N, we randomly generateda message m for each run and used cache attack primitives to collect the byte-code handler’s execution trace during the execution of modExp(m,e,n). Using ascript based on the methodology described in Section 3.3.3, we identified N loopiterations in the execution trace and detected whether the goto8 handler had anyadditional speculative access in each iteration. We use pei to denote the presence ofan additional goto8 in the ith loop iteration, which computes based on the ith bit,ei of the secret key e. Specifically, if ei = 1, then pei = 1; otherwise, pei = ei = 0.We repeat the experiment M times, extract {pei}Ni=1 from each run, and record thenumber of times pei = 1 at each index i across the M runs, denoted as sumM(pei).To simplify analysis, we normalized sumM(pei) by dividing it by M, defining thismetric as the Predicted Positive Rate (PPR), where PPRi =sumM(pei)M . A higherPPRi value indicates greater confidence that the corresponding bit ei is 1, while alower PPRi value suggests greater confidence that ei is 0.Figure 3.6: Distribution of the Predicted Positive Rate of N=4096 bits secretkey in M=4096 runs.We calculate the PPR for a secret key e of length N = 4096 in M = 4096 runs,and the distribution of the PPR is shown in Figure 3.6. The blue cluster represents35the PPRi of bits whose actual bit value ei is 0, while the orange cluster representsthe PPRi of bits whose actual bit value ei is 1. For ei = 0, the PPRi cluster has awide distribution but is below 1. For ei = 1, the PPRi cluster is concentrated near1. The distribution aligns with our analysis, as the speculation noise introducesadditional accesses to the goto8 handler, which falsely leads to a prediction ofpei = 1, thereby increasing the PPRi with actual bit value ei = 0. Furthermore, thetwo clusters of ei = 0 and ei = 1 exhibit a clear separation, enabling the attacker todistinguish actual control flow execution and mispredicted speculative execution.The attacker only needs to determine an optimal threshold, above which PPRi isclassified as 1 and below which it is classified as 0, to accurately infer ei, therebyultimately eliminating the impact of speculation noise.Mitigating Blind Spots via Repeated Runs. The blind spots primarily affect theattack accuracy by causing the attacker to miss some legitimate bytecode handlerinvocations, but it rarely results in false positives where cache accesses are inferredwithout actual access. The impact of the blind spots is notable in the ei = 1 clusterin Figure 3.6, where the distribution is slightly skewed to the left, indicating occa-sional missed detections. Nevertheless, the overall influence of blind spots on thePredicted Positive Rate is minimal with repeated runs.36Chapter 4EvaluationWe now assess our attack on the RSA algorithm implemented in OpenPGP.js run-ning on the QuickJS runtime. Our evaluation answers the following key questions:1. What is the attack accuracy of a single attack run?2. How many runs are required to recover the secret key with high accuracy?We use an Intel(R) Ice-Lake Xeon(R) Silver 4309Y Scalable Processor witheight 2.8 GHz cores. The server runs Linux kernel 6.6. We disable hyperthreading,DVFS, and ASLR in our experiments for ease of debugging, although this is not afundamental requirement for a real attack.We use QuickJS at commit id 3b45d15, OpenPGP.js v5.11.2. The attackerprocess runs on one physical core, and the victim and its runtime system run on asecond physical core.In Section 4.1, we evaluate the attack accuracy on the OpenPGP.js RSA imple-mentation. Then, in Section 4.2, we determine the required number of attack runsto a full recovery of the secret encryption key.4.1 Attack AccuracyRecall from Algorithm 1 and Figure 3.2, the RSA encryption implementationbranches on the value of the least significant bit (lsb) of the encryption key e ineach loop iteration.37We first measure the accuracy of the attack in inferring RSA keys of 4096 bits.Consider a key instance with P 1s and N 0s. Note that P+N always equals thesize of the key. We define the accuracy of an attack run in recovering the key asAcc = (T P+T N)/(P+N). Here T P indicates the number of 1 bits in the key thatwere correctly predicted as 1s in the attack run. Similarly, T N indicates the numberof 0 bits in the key that were correctly predicted as 0s in the attack run.We select 100 randomly generated 4096-bit RSA keys. For each key input inthe victim application, we run the attack 128 times and compute the accuracy ofeach attack run using the above formula. In Figure 4.1, we plot the average andstderr of the individual accuracy of 128 single attack runs for each of the 100 keyson the x-axis. The average accuracy among (100×128) measurements is 75.87%.The results indicate no significant variance in accuracy across different keys of thesame length.Figure 4.1: Attack accuracy across different 4096-bit keys.4.2 Required Runs for Secret Key RecoveryEven though the attack accuracy in a single run is only around 75% from Section4.1, an attacker could improve the accuracy by observing repeated runs of the RSAencryption algorithm in the victim application. For this, we leverage the idea ofPPR thresholds as discussed in Section 3.5. Similar to the previous experiment, weperform 128 attack runs each for 100 different keys. However, we now computethe accuracy achieved for each key after observations from 128 attack runs and38with a specific value of PPRi threshold.Note that in practice, the attacker does not know the ground truth values ofthe secret keys. It can only guess the keys with a certain confidence. The PPRthreshold sets the attacker’s confidence for each bit of a key. We choose the PPRthreshold as a pair of lower bound and upper bound (lb,ub). We determine ei = 0if PPRi < lb and ei = 1 if PPRi > ub with high confidence; otherwise, the corre-sponding bit remains uncertain.We evaluate the attack accuracy on varying numbers of runs with varyingthreshold pairs. Figure 4.2 shows the attack accuracy with increasing numbersof runs with a fixed threshold pair (90%, 90%). Table 4.1 shows the average, min-imum, and maximum accuracy achievable for different threshold pairs with 128runs. As shown in the figure and table, the attacker can readily determine an ap-propriate threshold pair (lb,ub) to achieve 99% accuracy with 32 runs and nearly100% accuracy within 128 runs.Figure 4.2: Attack accuracy with increasing number of runs. The thresholdis set to (90%, 90%) and the x-axis is presented on a logarithmic scale.Furthermore, we determine the number of runs required to achieve 100% accu-racy with different PPR threshold pairs, as shown in Table 4.2. The results indicatethat selecting an appropriate threshold pair for full recovery is challenging. Formany threshold pairs, achieving 100% accuracy even after 10,000 runs is not fea-sible. Moreover, while the attacker can achieve high accuracy with a few runs,a significantly larger number of runs are required to resolve a small number ofuncertain or incorrectly inferred bits.39Threshold Pair (%) Avg (%) Min (%) Max (%)(80, 80) 97.02 94.16 98.56(90, 90) 99.65 98.88 99.95(90, 95) 99.63 98.83 99.95(95, 95) 99.93 99.02 100.0(90, 96) 99.53 96.16 99.95(95, 96) 99.83 96.29 100.0(98, 98) 98.42 82.75 100.0Table 4.1: Attack accuracy metrics for different threshold pairs.Threshold Pair (%) Key length Avg (%) Median(%) Stderr(%)(95, 95) 2048 >10000 >10000 NA(96, 96) 2048 >10000 >10000 NA(97, 97) 2048 285.0 224.0 223.0(96, 97) 2048 >10000 >10000 NA(98, 98) 2048 176.8 160.0 72.77(95, 95) 4096 >10000 >10000 NA(96, 96) 4096 540.5 240.0 758.1(97, 97) 4096 259.5 224.0 123.6(96, 97) 4096 567.0 320.0 609.9(98, 98) 4096 600.5 544.0 311.2Table 4.2: Number of runs required for full key recovery of different keylengths and threshold pairs.We then analyze the number of uncertain bits across different keys after vari-ous numbers of attack runs. Based on the analysis in 3.5.3 and experiment resultsabove, the attacker can set a conservative lower bound, such as 96%, while ini-tially setting the upper bound equal to the lower bound and forming the thresholdpair. All PPRi values within this range are considered uncertain, and the attackerwill brute force the possible values of ei for these uncertain bits. If the attackerfails to find a valid key, they may increase the upper bound incrementally, or de-crease the lower bound when the upper bound is near 1. This process is repeateduntil all secret bits ei are certain with high confidence. We track how the numberof uncertain bits changes as the number of runs increases. Figure 4.3 shows theaverage number of uncertain bits left on the y-axis and the number of attack runs40on the x-axis, with the shaded region indicating the stderr. As seen from the fig-ure, the number of uncertain bits reduces to an average of 7.8 after 256 runs. Thissmall number of uncertain bits can be easily brute forced, significantly reducingthe number of runs needed to recover the complete key. If applicable, the attackermay leverage domain knowledge in cryptography to reconstruct the RSA key frompartial bits [HS09, Per05], though this approach is beyond the scope of this thesis.Figure 4.3: Number of uncertain bits the attacker shall enumerate to achievea complete and accurate key recovery.4.3 Limitations4.3.1 Limitations of the EvaluationSo far, we have primarily tested our attack in local environments. When attempt-ing to deploy and run the attack in a cloud setting, we encountered significantchallenges due to the system and background noise, which were much higher thanthose observed in the local test environment. The huge amount of noise diminishedthe time-frequency characteristics of periodic bytecode handler accesses, makingthem harder to distinguish. This introduced several difficulties for our attack. Onechallenge is that, in the absence of memory sharing, it becomes difficult to directly41identify the cache set corresponding to a specific bytecode handler using methodslike Welch’s power spectral density. Additionally, we could not easily isolate andextract the cache accesses corresponding to the encryption function from a seriesof cache accesses.Even in such noisy cloud environments, we observe the potential for usingmultiple channels to mitigate system and background noise with human inspec-tion. However, due to time constraints and the engineering challenges involvedin automating the inference script in the cloud environment, we were unable tocomplete a reliable automated inference script to verify whether repeated experi-ments in the cloud could effectively reduce noise at scale. We leave this to futureevaluation work.4.3.2 Noise due to PredictionPrior work [LLT24, YTN+23] has conducted significant reverse engineering on in-direct branch predictors (IBP), their components, and prediction algorithms. Thesestudies reveal that the IBP maintains a fixed-length Path History Register (PHR).At each indirect branch, the IBP uses the current source address and PHR to querythe Branch Target Buffer (BTB) and its own ITTAGE branch history table. It iden-tifies the longest suffix match in the table relative to the current PHR and uses it asthe predicted target address. After resolving each actual branch, the PHR left-shiftstwo bits, and a hash function computed from the source and target addresses of thebranch is used to update the last bits of the PHR. Since the last two bits of the up-dated PHR depend solely on the most recent branch’s source and target addresses,the PHR eventually converges to a consistent value after a sufficient number ofconsecutive indirect branches, regardless of its initial state.Given this assumption, for a QuickJS dispatch table operating over the byte-code instruction control flow of a function, such as modExp, with identical inputdata, the predicted indirect branch target should be a consistent address after suf-ficient branches in every run. However, this hypothesis conflicts with our experi-mental observations. Specifically, during iterations where ei = 0, the probabilisticexecution of the goto8 handler predicted by the IBP contradicts the expected de-terministic behavior.42Due to limited access to prior artifacts, we could not fully replicate the reverseengineering of IBP behavior on our Ice Lake architecture. The length of the PHRand its update function remain unclear. Prior work indicates that the PHR lengthis 29×2 bits for Skylake and Gracemont architectures and 194×2 bits for Rap-tor (Golden) Cove. Based on these findings, we hypothesize that Ice Lake’s PHRlength likely falls within this range. Analyzing the modExp function’s bytecode in-structions reveals that each loop iteration executes either 46 instructions if lsb=1or 45 instructions if lsb=0. This suggests that the IBP might retain history forthe last 0 to 5 iterations’ branch results. However, when we group the predictedpositive rates (PPRi) by the current bit ei and several preceding bits, we find no sig-nificant distinction between distributions, such as those for {ek}ii−4 = 00000 and{ek}ii−4 = 11110 shown in Figure 4.4. This indicates that the IBP’s predictionsare seemingly unrelated to the outcomes of prior indirect branches in the languageruntime.We currently lack an explanation for this probabilistic prediction behavior. Wesuspect that additional, undocumented details about the IBP’s prediction policyremain undiscovered. Further reverse engineering is required to fully understandthese mechanisms.Figure 4.4: The distributions of PPRi for {ek}ii−4 corresponding to {00000}and {11110}.43Chapter 5Conclusion5.1 ConclusionWe demonstrate that the potential attack surface of an application running in a lan-guage runtime is more extensive than previously recognized. We show the attackercan infer secret-dependent control flow at the bytecode level within the languageruntime by targeting the bytecode handler, posing security risks for widely usedlanguage runtimes for interpreted programming languages.Additionally, we systematically studied the impact of various types of noise onattack accuracy in cache side channels, including system and background noise,speculation-induced noise, and blind spots. Those factors have been largely over-looked in prior research. Through experimental analysis, we demonstrated thatthese noise sources can be effectively mitigated by leveraging multiple cache chan-nels and combining results from repeated experiments.Our research highlights the need for comprehensive countermeasures that ad-dress cache side-channel vulnerabilities across all levels of execution, from sourcecode to runtime environments. Given the widespread reliance on language run-times in cloud computing, our work not only expands the scope of cache side-channel research but also serves as a call to action for researchers and developersto prioritize the security of interpreted language and their runtime environments.445.2 Future Work5.2.1 Other Runtime Systems and ApplicationsWhile we have shown our attack on QuickJS, we believe it can be generalized toother language runtimes. We plan to evaluate additional language runtimes, such asCPython. For CPython, we observe that its built-in handlers execute different codepaths based on bytecode operands. This implies that even if CPython’s source codeand bytecode lack secret-dependent control flow, leakage sources may still exist.We also plan to explore other applications, including image-processing li-braries and spell checkers. Expanding cache side-channel attacks to other appli-cations presents two main challenges. The first is that continuous detection viacache side channels often requires thousands of CPU cycles to achieve high ac-curacy. This time interval is relatively short. For a simple computation function,a few thousand cycles might be enough to complete an entire function, while theattacker can only perform one or two observations during this time. As a result,the information the attacker can extract is minimal. The second limitation is thatthe attacker must target secret-dependent computations with specific instructionflows or access patterns. Without such unique patterns, the attacker cannot easilydistinguish secret-related computations from the ordinary, secret-independent com-putations that may be running alongside them. Previous attacks demonstrated thatimage processing programs and spell checkers exhibit secret-dependent behavior,leaking pixel data of processed images or text input for spell-checking. These ap-plications are potential targets for further analysis and evaluation. Other vulnerableapplications require more analysis of the execution speed, special access pattern,and potential source of leakages, to be discovered.5.2.2 Mitigation StrategiesWe have demonstrated that applications running on language runtimes are vulner-able to cache side-channel attacks, exposing secret-dependent control flow at thebytecode level. This highlights the need for effective mitigation strategies.45Hardware Isolation. Cache side-channel attacks fundamentally rely on the sharednature of the hardware resource—the cache. If the cache were no longer shared be-tween different users, the potential for interference would be eliminated, leavingattackers with no means to infer victim information from the cache. Many studieshave proposed hardware partitioning techniques to achieve isolation, ensuring thatattackers and victims do not share cache resources [LGY+16, VFH+24]. How-ever, in scenarios such as cloud platforms, these techniques often impose signif-icant overhead on the entire system, not just on individual users. Adopting thepartitioning mechanisms can also impact scalability and flexibility in the Cloud.Additionally, it remains uncertain whether Intel has a hardware partitioning tech-nique to eliminate the shared nature of the snoop filter.Cache Randomization. Cache randomization has recently been revived as apromising defense against conflict-based cache side-channel attacks. Variousmitigation techniques have proposed different randomization strategies to in-crease the difficulty for attackers to interfere with and observe the victim’scache [LL14, SQ21, WUG+19, SLX+21, Qur18, Qur19]. However, to date, thereis no widely available implementation of cache randomization in hardware. More-over, many of the randomization algorithms have been shown to be not entirely ef-fective, as they remain vulnerable to eviction-based attacks [PGGV21, CBSM23].Constant-time Execution. Typically, the principle for mitigating cache side-channel vulnerabilities is constant-time execution, ensuring that the program’s be-havior remains independent of secret inputs. Following this principle will eliminatesecret-dependent control flow, secret-dependent data access, and variable-time in-struction usage.Implementing constant-time algorithms cannot be achieved solely at the sourcecode level and it often requires specialized compiler support. At the source codelayer, developers usually manually modify the C/Cpp code [CSJ+19, BDQG21] orrewrite it using domain-specific languages (DSLs) [ZBPB17, ABB+17], to elimi-nate secret-dependent behaviors and provide type annotations required by the com-piler. The compiler then addresses any remaining secret-dependent behaviors at the46intermediate representation level. Furthermore, compilers must ensure that no newsecret-dependent behaviors are introduced during optimization or code generation.Finally, the resulting binary must be thoroughly verified to confirm that it preservesthe constant-time property [DBR20, ZBPB17, ABB+17].The same challenges apply to applications running on language runtimes.Source-level mitigations may not guarantee the preservation of constant-time prop-erties after bytecode and machine code generation [BRB20]. One solution is fordevelopers to rewrite all confidential computations in lower-level languages likeC/C++ with extra type annotations or specialized DSLs and verify the resultingmachine code for constant-time properties. These verified binary components canthen be invoked via ABI calls. However, this approach has significant drawbacks: itundermines the language runtime’s goal of abstracting hardware details and makesthe application non-portable.To address cache side-channel leakage in language runtimes, the language run-time itself must take an active role in implementing mitigations. One solution isto provide verified, constant-time built-in functions within the language runtimefor application developers to use. This, however, may still require modificationsto the application source code. A more ambitious solution is to modify the lan-guage runtime to offer a constant-time execution mode. In this mode, the runtimewould ensure that generated bytecode instructions are entirely secret-independent.Additionally, the runtime’s bytecode handlers must not introduce secret-dependentcontrol flow or data access. If the language runtime includes JIT compilation,formal methods are required to ensure that secret-dependent behaviors are not in-troduced during machine code generation and optimization phases, which we leavefor future work.5.2.3 Speculative Execution AttacksTransient attacks [KHF+19] exploit speculative execution, a performance opti-mization technique in modern processors where instructions are executed out-of-order based on predictions. While speculative execution itself cannot directly ac-cess secret memory in cross-core attack scenarios, recent studies reveal that cacheside-channel attacks can leverage speculative execution to increase the speed of47the attacks, achieving higher time resolution [KKC+23, HRY24]. Some advancedattacks even exploit hardware prefetchers to break constant-time cryptographic im-plementations [CWS+24]. However, it remains an unresolved problem for suchattacks to overcome address space separation to identify target cache sets whenmemory sharing is unavailable.48Bibliography[ABB+17] Jose´ Bacelar Almeida, Manuel Barbosa, Gilles Barthe, Arthur Blot,Benjamin Gre´goire, Vincent Laporte, Tiago Oliveira, Hugo Pacheco,Benedikt Schmidt, and Pierre-Yves Strub. Jasmin: High-Assuranceand High-Speed Cryptography. ACM CCS, 2017. 46, 47[AEW09] Andrea Arcangeli, Izik Eidus, and Chris Wright. Increasing memorydensity by using ksm. Ottawa Linux Symposium, 2009. 11[AWS24a] AWS. The ec2 approach to preventing side-channels - the securitydesign of the aws nitro system, 2024. 11, 15, 18[AWS24b] AWS Labs. LLRT (Low Latency Runtime), 2024. 17[BDQG21] Pietro Borrello, Daniele Cono D’Elia, Leonardo Querzoni, andCristiano Giuffrida. Constantine: Automatic Side-Channel ResistanceUsing Efficient Control and Data Flow Linearization. ACM CCS,2021. 46[BG24] Fabrice Bellard and Charlie Gordon. QuickJS Javascript Engine,2024. 5, 17[BM06] Joseph Bonneau and Ilya Mironov. Cache-collision timing attacksagainst aes. CHES, 2006. 2[BMME20] Samira Briongos, Pedro Malagon, Jose M. Moya, and ThomasEisenbarth. RELOAD+REFRESH: Abusing cache replacementpolicies to perform stealthy cache attacks. USENIX Security, 2020. 1[BRB20] Tegan Brennan, Nicola´s Rosner, and Tevfik Bultan. Jit leaks:Inducing timing side channels through just-in-time compilation. IEEES&P, 2020. 16, 47[Bro24] Broadcom. Security considerations and disallowing inter-virtualmachine transparent page sharing, 2024. 1149[BSB20] Tegan Brennan, Seemanta Saha, and Tevfik Bultan. Jvm fuzzing forjit-induced side-channel detection, 2020. 16[CBSM23] Anirban Chakraborty, Sarani Bhattacharya, Sayandeep Saha, andDebdeep Mukhopadhyay. Are randomized caches truly random?formal analysis of randomized-partitioned caches. IEEE HPCA,2023. 46[cK06] Onur cıic¸mez and C¸etin Kaya Koc¸. Trace-driven cache attacks on aes(short paper). ICICS, 2006. 10[CSJ+19] Sunjay Cauligi, Gary Soeller, Brian Johannesmeyer, Fraser Brown,Riad S. Wahby, John Renner, Benjamin Gre´goire, Gilles Barthe,Ranjit Jhala, and Deian Stefan. FaCT: A DSL for Timing-SensitiveComputation. ACM PLDI, 2019. 46[CWS+24] Boru Chen, Yingchen Wang, Pradyumna Shome, Christopher W.Fletcher, David Kohlbrenner, Riccardo Paccagnella, and DanielGenkin. Gofetch: Breaking constant-time cryptographicimplementations using data memory-dependent prefetchers. USENIXSecurity, 2024. 48[DBR20] Lesly-Ann Daniel, Se´bastien Bardin, and Tamara Rezk. Binsec/Rel:Efficient Relational Symbolic Execution for Constant-Time atBinary-Level. IEEE S&P, 2020. 47[DKPT17] Craig Disselkoen, David Kohlbrenner, Leo Porter, and Dean Tullsen.Prime+Abort: A Timer-Free High-Precision l3 cache attack usingintel TSX. USENIX Security, 2017. 1[FHN+07] Keir Fraser, Steven Hand, Rolf Neugebauer, Ian Pratt, AndrewWarfield, and Mark Williamson. Safe hardware access with the xenvirtual machine monitor, 2007. 11[Fou24] Python Software Foundation. The python programming language,2024. 14, 17[FWN+22] Chongzhou Fang, Han Wang, Najmeh Nazari, Behnam Omidi,Avesta Sasan, Khaled N. Khasawneh, Setareh Rafatirad, and HoumanHomayoun. Repttack: Exploiting cloud schedulers to guideco-location attacks. NDSS, 2022. 15[Gab46] Dennis Gabor. Theory of communication. Journal of the Institution ofElectrical Engineers - Part I: General, 1946. 5, 3150[GBK11] David Gullasch, Endre Bangerter, and Stephan Krenn. Cache games –bringing access-based cache attacks on aes to practice. IEEE S&P,2011. 10[GLV+08] Diwaker Gupta, Sangmin Lee, Michael Vrable, Stefan Savage,Alex C. Snoeren, George Varghese, Geoffrey M. Voelker, and AminVahdat. Difference engine: Harnessing memory redundancy in virtualmachines. USENIX OSDI, 2008. 11[GMWM16] Daniel Gruss, Cle´mentine Maurice, Klaus Wagner, and StefanMangard. Flush+flush: A fast and stealthy cache attack. DIMVA,2016. 1[Goo24] Google. V8 JavaScript engine, 2024. 14[Gor98] Daniel M. Gordon. A survey of fast exponentiation methods. Journalof Algorithms, 1998. 2, 23[GPTY18] Daniel Genkin, Lev Pachmanov, Eran Tromer, and Yuval Yarom.Drive-by key-extraction cache attacks from portable code. ACNS2018, 2018. 15[GSFS24] L. Gerlach, S. Schwarz, N. Faros, and M. Schwarz. Efficient andgeneric microarchitectural hash-function recovery. IEEE S&P(SP),2024. 9[GSM15] Daniel Gruss, Raphael Spreitzer, and Stefan Mangard. Cachetemplate attacks: Automating attacks on inclusive Last-Level caches.USENIX Security, 2015. 1, 10[HRY24] Gal Horowitz, Eyal Ronen, and Yuval Yarom. Spec-o-scope: Cacheprobing at cache speed. ACM CCS, 2024. 48[HS09] Nadia Heninger and Hovav Shacham. Reconstructing RSA privatekeys from random key bits. CRYPTO, 2009. 41[IES15] Gorka Irazoqui, Thomas Eisenbarth, and Berk Sunar. S$A: A SharedCache Attack That Works across Cores and Defies VM Sandboxing –and Its Application to AES. IEEE S&P, 2015. 1[Ind24] Fedor Indutny. Fast elliptic-curve cryptography in a plain javascriptimplementation, 2024. 15[Int23] Intel. Intel® 64 and ia-32 architectures optimization referencemanual, 2023. 8, 1351[Int24] Intel. Intel® 64 and ia-32 architectures software developer’s manual,2024. 9[KHF+19] Paul Kocher, Jann Horn, Anders Fogh, , Daniel Genkin, Daniel Gruss,Werner Haas, Mike Hamburg, Moritz Lipp, Stefan Mangard, ThomasPrescher, Michael Schwarz, and Yuval Yarom. Spectre attacks:Exploiting speculative execution. IEEE S&P, 2019. 47[KKC+23] Daniel Katzman, William Kosasih, Chitchanok Chuengsatiansup,Eyal Ronen, and Yuval Yarom. The gates of time: Improving cacheattacks with transient execution. USENIX Security, 2023. 48[Koc96] Paul C. Kocher. Timing Attacks on Implementations ofDiffie-Hellman, RSA, DSS, and Other Systems. CRYPTO, 1996. 10[LGY+16] Fangfei Liu, Qian Ge, Yuval Yarom, Frank Mckeen, Carlos Rozas,Gernot Heiser, and Ruby B. Lee. CATalyst: Defeating last-level cacheside channel attacks in cloud computing. IEEE HPCA, 2016. 46[LL14] Fangfei Liu and Ruby B. Lee. Random fill cache architecture.IEEE/ACM MICRO, 2014. 46[LLT24] Hosein Yavarzadeh Luyi Li and Dean Tullsen. Indirector:High-precision branch target injection attacks exploiting the indirectbranch predictor. USENIX Security, 2024. 42[LYBB14] Tim Lindholm, Frank Yellin, Gilad Bracha, and Alex Buckley. TheJava Virtual Machine Specification, Java SE 8 Edition.Addison-Wesley Professional, 2014. 14[LYG+15] Fangfei Liu, Yuval Yarom, Qian Ge, Gernot Heiser, and Ruby B. Lee.Last-level cache side-channel attacks are practical. IEEE S&P, 2015.1, 13[LZJZ21] Xiaoxuan Lou, Tianwei Zhang, Jun Jiang, and Yinqian Zhang. Asurvey of microarchitectural side-channel vulnerabilities, attacks, anddefenses in cryptography. ACM CSUR, 2021. 2[MSN+15] Cle´mentine Maurice, Nicolas Scouarnec, Christoph Neumann,Olivier Heen, and Aure´lien Francillon. Reverse engineering intellast-level cache complex addressing using performance counters.RAID, 2015. 952[NS07] Michael Neve and Jean-Pierre Seifert. Advances on access-drivencache attacks on aes. SAC, 2007. 10[OKSK15] Yossef Oren, Vasileios P. Kemerlis, Simha Sethumadhavan, andAngelos D. Keromytis. The spy in the sandbox: Practical cacheattacks in javascript and their implications. ACM CCS, 2015. 15[Ope24a] OpenJS Foundation. Node.js — run javascript everywhere, 2024. 17[Ope24b] OpenPGP.js. Openpgp javascript implementation, 2024. 5, 18[Ope24c] OpenPGP.js. openpgpjs/openpgpjs, 2024. 24[OST06] Dag Arne Osvik, Adi Shamir, and Eran Tromer. Cache attacks andcountermeasures: The case of aes. CT-RSA, 2006. 1, 10, 11, 12[Per05] Colin Percival. Cache missing for fun and profit, 2005. 1, 41[PGGV21] Antoon Purnal, Lukas Giner, Daniel Gruss, and Ingrid Verbauwhede.Systematic analysis of randomization-based protected cachearchitectures. IEEE S&P, 2021. 46[PTV21] Antoon Purnal, Furkan Turan, and Ingrid Verbauwhede.Prime+scope: Overcoming the observer effect for high-precisioncache contention attacks. ACM CCS, 2021. 1, 5, 9, 10, 12, 32[QJS+22] Qi Qin, JulianAndres JiYang, Fu Song, Taolue Chen, and Xinyu Xing.DeJITLeak: Eliminating JIT-Induced Timing Side-Channel Leaks.ACM ESEC/FSE, 2022. 16[Qur18] Moinuddin K. Qureshi. Ceaser: Mitigating conflict-based cacheattacks via encrypted-address and remapping. IEEE/ACM MICRO,2018. 46[Qur19] Moinuddin K. Qureshi. New attacks and defense forencrypted-address cache. ISCA, 2019. 46[RSA78] R. L. Rivest, A. Shamir, and L. Adleman. A method for obtainingdigital signatures and public-key cryptosystems. Commun. ACM,1978. 23[SAO+21] Anatoly Shusterman, Ayush Agarwal, Sioli O’Connell, DanielGenkin, Yossi Oren, and Yuval Yarom. Prime+Probe 1, JavaScript 0:Overcoming browser-based Side-Channel defenses. USENIXSecurity, 2021. 1553[Sco09] Michael L. Scott. Programming Language Pragmatics, Third Edition.Morgan Kaufmann Publishers Inc., 2009. 13[SKLG22] Martin Schwarzl, Erik Kraft, Moritz Lipp, and Daniel Gruss. Remotememory-deduplication attacks. NDSS, 2022. 11[SLX+21] Wei Song, Boya Li, Zihan Xue, Zhenzhen Li, Wenhao Wang, andPeng Liu. Randomized last-level caches are still vulnerable to cacheside-channel attacks! but we can fix it. IEEE S&P, 2021. 46[SQ21] Gururaj Saileshwar and Moinuddin Qureshi. MIRAGE: MitigatingConflict-Based cache attacks with a practical Fully-Associativedesign. USENIX Security, 2021. 46[TC323] TC39. Ecmascript® 2023 language specification, 2023. 15[TMH+18] Simon M. Tam, Harry Muljono, Min Huang, Sitaraman Iyer, KalapiRoyneogi, Nagmohan Satti, Rizwan Qureshi, Wei Chen, Tom Wang,Hubert Hsieh, Sujal Vora, and Eddie Wang. Skylake-sp: A 14nm28-core xeon® processor. IEEE ISSCC, 2018. 9[VFH+24] Stavros Volos, Ce´dric Fournet, Jana Hofmann, Boris Ko¨pf, andOleksii Oleksenko. Principled microarchitectural isolation on cloudcpus. ACM CCS, 2024. 46[Wal02] Carl A Waldspurger. Memory resource management in vmware esxserver. USENIX OSDI, 2002. 11[Wel67] P. Welch. The use of fast fourier transform for the estimation of powerspectra: A method based on time averaging over short, modifiedperiodograms. IEEE Transactions on Audio and Electroacoustics,1967. 5, 29[WUG+19] Mario Werner, Thomas Unterluggauer, Lukas Giner, MichaelSchwarz, Daniel Gruss, and Stefan Mangard. ScatterCache:Thwarting cache attacks via cache set randomization. USENIXSecurity, 2019. 46[YF14] Yuval Yarom and Katrina Falkner. FLUSH+RELOAD: A highresolution, low noise, l3 cache Side-Channel attack. USENIXSecurity, 2014. 1, 5, 13[YSG+19] Mengjia Yan, Read Sprabery, Bhargava Gopireddy, ChristopherFletcher, Roy Campbell, and Josep Torrellas. Attack directories, not54caches: Side channel attacks in a non-inclusive world. IEEE S&P,2019. 7, 9, 13[YTN+23] Hosein Yavarzadeh, Mohammadkazem Taram, Shravan Narayan,Deian Stefan, and Dean Tullsen. Half&half: Demystifying intel’sdirectional branch predictors for fast, secure partitioned execution.IEEE S&P, 2023. 42[ZBPB17] Jean-Karim Zinzindohoue´, Karthikeyan Bhargavan, JonathanProtzenko, and Benjamin Beurdouche. HACL*: A Verified ModernCryptographic Library. ACM CCS, 2017. 46, 47[ZMFT24a] Zirui Neil Zhao, Adam Morrison, Christopher W. Fletcher, and JosepTorrellas. Everywhere all at once: Co-location attacks on public cloudfaas. ACM ASPLOS, 2024. 15[ZMFT24b] Zirui Neil Zhao, Adam Morrison, Christopher W. Fletcher, andJosep Torrellas. Last-level cache side-channel attacks are feasible inthe modern public cloud. ACM ASPLOS, 2024. 15, 2955
Thesis/Dissertation
eng
Computer Science
Vancouver : University of British Columbia Library
Attribution-NonCommercial-NoDerivatives 4.0 International
Graduate
Mehta, Aastha
Cache side-channel attacks on language runtimes
Text