A method of preventing return-oriented programming (ROP) attacks
By generating and adding PACs to the return address in a pipelined manner, the problems of high development cost, compatibility and coordination difficulties in the implementation of PAC functions in existing technologies are solved. This enables the improvement of software security and the prevention of ROP attacks without recompiling the program.
Patent Information
- Application Number
- CN202511001138.8
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2025-07-21
- Publication Date
- 2025-12-16
- Estimated Expiration
- 2045-07-21
AI Technical Summary
The Pointer Authentication Code (PAC) feature introduced in the existing ARMv8.3 version has problems such as high development costs, compatibility issues, difficulty in hardware updates, and difficulty in coordinating with manufacturers, which limits its progress in preventing Return-Oriented Programming (ROP) attacks.
By identifying the target instruction and pipeline level in a function call in pipelined mode, a Pointer Authentication Code (PAC) is generated and added to the return address. The stack pointer and key are obtained using the instruction bypass unit to generate a return address carrying the PAC, thus preventing ROP attacks.
Without recompiling the existing program, PAC protection is applied to the existing program through instruction bypass, which improves software security and prevents ROP attacks.
Smart Images

Figure CN120509012B_ABST
Abstract
Description
TECHNICAL FIELD
[0001] The present application relates to the technical field of computer instruction processing, and in particular to a method for preventing return-oriented programming (ROP) attack. BACKGROUND
[0002] With the rapid development of computer technology, software security problems are increasingly serious, especially malicious attacks on pointers, such as return-oriented programming (ROP) attacks, which pose a serious threat to system security.
[0003] At present, ARM Company introduces the function of pointer authentication code (PAC) in the ARMv8.3 version, which utilizes the characteristics that 64-bit architecture does not need to use the complete 64-bit address space, embeds authentication code in the unused bits to authenticate a pointer, and effectively prevents malicious attacks through the signature and signature verification mechanism.
[0004] However, in the process of introducing the PAC function, many problems are faced, such as the existing software written in high-level programming languages needs to be recompiled to adapt to the new PAC instruction set, which not only increases the development cost, but also may cause compatibility problems; secondly, for assembly language, the developer needs to manually add PAC related instructions, which increases the development difficulty and workload; thirdly, only the newer hardware implements the PAC function, and the existing hardware does not implement the PAC function, so it cannot benefit from it; in addition, the comprehensive implementation of the PAC function requires close cooperation of numerous manufacturers, from hardware manufacturers to software developers, each link needs to be updated and adapted accordingly, the coordination difficulty is large, and the promotion speed is limited. SUMMARY
[0005] The present application provides a method for preventing return-oriented programming (ROP) attack, which is used to generate PAC, add PAC to the return address, and then prevent ROP attack.
[0006] In a first aspect, embodiments of this application provide a method for preventing ROP attacks. The method includes: when processing instructions in a pipelined mode, if a first target instruction and a target pipeline level are identified in a function call, the target pipeline level is paused; the first target instruction is a first setting instruction in which the stack pointer points to the caller's stack frame before and after execution, or the first target instruction is a second setting instruction in which the stack pointer points to the callee's stack frame before and after execution; the "before and after execution" refers to before execution and / or after execution; the target pipeline level is a specified pipeline level in the pipeline; the return address of the function call, the stack pointer, and the key are obtained through an instruction bypass unit, and a PAC is generated based on the return address, the stack pointer, and the key; the PAC is added to a reserved bit in the return address to obtain a return address carrying the PAC; the return address carrying the PAC is used to prevent ROP attacks targeting the return address; after the instruction bypass unit has finished executing, the first target instruction is processed again through the target pipeline level in the pipeline.
[0007] Using the above method, when the preset first target instruction and target pipeline level are identified, the return address, stack pointer, and key are obtained to generate a PAC (Programming Access Controller). The PAC is then added to a reserved bit, resulting in a return address carrying the PAC. Because this return address carries the PAC, it cannot be used normally. Therefore, only after the PAC is removed and the signature verification is successful is it a valid address that can be used normally. In this way, through pipeline-level bypass of instructions, existing programs can be protected by PACs without recompiling them, thus preventing ROP (Return on Exploitation) attacks and improving software security.
[0008] In one possible implementation, processing of the instruction continues through the target pipeline stage in the pipeline, including: skipping instruction identification and directly continuing processing of the first target instruction from the target pipeline stage.
[0009] In one possible implementation, after obtaining the return address carrying the PAC, the method further includes: writing the return address carrying the PAC to the top of the stack or the return address register.
[0010] In a possible implementation, the identifying the instruction as the first target instruction is performed in the following manner: (1) if a stack grows from top to bottom, determining the instruction as the first target instruction if the instruction satisfies either of the following two conditions: (a) the operation code in the instruction is an immediate number addition operation code, the source register is a stack pointer register, the destination register is the stack pointer register, and the immediate number is a negative value; (b) the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is a positive value; (2) if a stack grows from bottom to top, determining the instruction as the first target instruction if the instruction satisfies either of the following two conditions: (a) the operation code in the instruction is an immediate number addition operation code, the source register is a stack pointer register, the destination register is the stack pointer register, and the immediate number is a positive value; (b) the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is a negative value; the stack growing from top to bottom is a stack with a stack bottom at a high address and a stack top at a low address; the stack growing from bottom to top is a stack with a stack bottom at a low address and a stack top at a high address; the high address is a memory address with a larger address value; and the low address is a memory address with a smaller address value.
[0011] In a possible implementation, the first setting instruction is an instruction in which a stack pointer points to a caller stack frame before execution and points to a callee stack frame after execution; the target pipeline stage is any pipeline stage in the pipeline that is no later than a write-back stage; the write-back stage includes the write-back stage; and the instruction bypass unit obtains the return address of the function call and the stack pointer in the following manner: reading the return address from a stack top or a return address register; and reading the stack pointer stored in a stack pointer register.
[0012] In a possible implementation, the second setting instruction is an instruction in which a stack pointer points to a caller stack frame before execution and points to a callee stack frame after execution; the target pipeline stage is a write-back stage; and the instruction bypass unit obtains the return address of the function call and the stack pointer in the following manner: reading the return address from a stack top or a return address register; and obtaining the stack pointer from an input of the target pipeline stage.
[0013] In a possible implementation, after the return address carrying the PAC is obtained, the method further includes: inputting the return address carrying the PAC as an instruction bypass result to the target pipeline stage.
[0014] In a possible implementation, the second setting instruction is an instruction for storing a return address on a stack; the target pipeline stage is any pipeline stage in the pipeline that is later than a decode stage but no later than a memory access stage; the stage later than the decode stage but no later than the memory access stage does not include the decode stage and includes the memory access stage.
[0015] obtaining, by the instruction bypass unit, the return address of the function call and the stack pointer, comprises: obtaining the return address from the input of the target pipeline stage; reading the stack pointer stored in the stack pointer register.
[0016] In a possible implementation, the first setting instruction is a jump instruction for the function call; the target pipeline is a memory access stage or a write back stage; and the obtaining, by the instruction bypass unit, of the return address of the function call and the stack pointer comprises: obtaining the return address from the input of the target pipeline stage; and reading the stack pointer stored in the stack pointer register.
[0017] In a possible implementation, the identifying of the instruction as the first target instruction comprises: (1) if a stack grows from top to bottom, determining that the instruction satisfies the following conditions as the first target instruction: the operation code in the instruction is a memory storage operation code, the source register is a return address register, the memory base address register is a stack pointer register, and the offset is a positive value; or (2) if a stack grows from bottom to top, determining that the instruction satisfies the following conditions as the first target instruction: the operation code in the instruction is a memory storage operation code, the source register is a return address register, the memory base address register is a stack pointer register, and the offset is a negative value.
[0018] The stack growing from top to bottom is a stack with a stack bottom at a high address and a stack top at a low address; the stack growing from bottom to top is a stack with a stack bottom at a low address and a stack top at a high address; the high address is a memory address with a larger address value; and the low address is a memory address with a smaller address value.
[0019] In a second aspect, the present application provides a method for preventing a return-oriented programming (ROP) attack, comprising: when processing instructions in a pipeline stage mode, if a second target instruction in a function call and a target pipeline stage are identified, pausing the target pipeline stage; the second target instruction is a third setting instruction for which a stack pointer before and after execution points to a caller stack frame, or the second target instruction is a fourth setting instruction for which a stack pointer before and after execution points to a callee stack frame; the before and after execution are before execution and / or after execution; the target pipeline stage is a specified pipeline stage in a pipeline; obtaining, by an instruction bypass unit, a return address carrying a PAC, the stack pointer, and a key, and generating a PAC to be verified based on the return address stripped of the PAC, the stack pointer, and the key; if the PAC is the same as the PAC to be verified, continuing to process the second target instruction through the target pipeline stage in the pipeline; and if the PAC is different from the PAC to be verified, triggering an exception, the exception indicating an ROP attack on a return address.
[0020] When the preset second target instruction and the target pipeline stage are identified by using the method, the return address carrying the PAC, the stack pointer, and the key are obtained, the PAC to be verified is generated, and if the PAC to be verified is the same as the carried PAC, it is determined that the return address carrying the PAC is not attacked. In this way, by using the pipeline stage bypass mode of the instruction, the existing program can be protected by the PAC without recompiling the existing program, the ROP attack is prevented, and the security of the software is improved.
[0021] In a possible implementation, the processing of the second target instruction is continued through the target pipeline stage in the pipeline, including: skipping instruction identification and directly continuing to process the second target instruction from the target pipeline stage.
[0022] In a possible implementation, the method further includes: if the PAC is the same as the PAC to be verified, writing the return address without the PAC into the top of the stack or a return address register.
[0023] In a possible implementation, the instruction is identified as the second target instruction by: (1) if a stack grows from top to bottom, determining that the instruction is the second target instruction if the instruction satisfies any one of the following two conditions: (a) the operation code in the instruction is an immediate number addition operation code, the source register is a stack pointer register, the destination register is the stack pointer register, and the immediate number is positive; (b) the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is negative; (2) if a stack grows from bottom to top, determining that the instruction is the second target instruction if the instruction satisfies any one of the following two conditions: (a) the operation code in the instruction is an immediate number addition operation code, the source register is a stack pointer register, the destination register is the stack pointer register, and the immediate number is negative; (b) the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is positive; the stack growing from top to bottom is a stack with a stack bottom at a high address and a stack top at a low address; the stack growing from bottom to top is a stack with a stack bottom at a low address and a stack top at a high address; the high address is a memory address with a larger address value; and the low address is a memory address with a smaller address value.
[0024] In a possible implementation, the third set instruction is an instruction for executing a caller stack frame pointed to by a stack pointer before execution and a callee stack frame pointed to by the stack pointer after execution; the target pipeline stage is a write-back stage; and the instruction bypass unit obtains the return address carrying the PAC and the stack pointer by: reading the return address carrying the PAC from the top of the stack or a return address register; and obtaining the stack pointer from the input of the target pipeline stage.
[0025] In a possible implementation, the fourth setting instruction is an instruction for setting the execution-before stack pointer to point to a caller stack frame and the execution-after stack pointer to point to a callee stack frame; the target pipeline stage is any pipeline stage in the pipeline that is no later than the write-back stage; the write-back stage comprises the write-back stage; and the instruction bypass unit obtains the return address carrying the PAC and the stack pointer by reading the return address carrying the PAC from a top-of-stack register or a return address register and reading the stack pointer stored in a stack pointer register.
[0026] In a possible implementation, the method further comprises: if the PAC is the same as the PAC to be verified, inputting the return address stripped of the PAC as an instruction bypass result to the target pipeline stage.
[0027] In a possible implementation, the fourth setting instruction is an instruction for loading a return address stored on a stack; the target pipeline stage is the write-back stage; and the instruction bypass unit obtains the return address carrying the PAC and the stack pointer by obtaining the return address carrying the PAC from an input of the target pipeline stage and reading the stack pointer stored in a stack pointer register.
[0028] In a possible implementation, the third setting instruction is a jump instruction for function return; the target pipeline stage is any pipeline stage in the pipeline that is later than the decode stage but no later than the write-back stage; the pipeline stage later than the decode stage but no later than the write-back stage does not comprise the decode stage and comprises the write-back stage; and the instruction bypass unit obtains the return address carrying the PAC and the stack pointer by obtaining the return address carrying the PAC from an input of the target pipeline stage and reading the stack pointer stored in a stack pointer register.
[0029] In a possible implementation, the instruction is identified as the second target instruction by: (1) if a stack grows from top to bottom, determining that an instruction meeting the following conditions is the second target instruction: an operation code in the instruction is a memory load operation code, a target register is a return address register, a memory base address register is a stack pointer register, and an offset is a positive value; or (2) if a stack grows from bottom to top, determining that an instruction meeting the following conditions is the second target instruction: an operation code in the instruction is a memory load operation code, a target register is a return address register, a memory base address register is a stack pointer register, and an offset is a negative value; the stack growing from top to bottom is a stack with a stack bottom at a high address and a stack top at a low address; the stack growing from bottom to top is a stack with a stack bottom at a low address and a stack top at a high address; the high address is a memory address with a larger address value; and the low address is a memory address with a smaller address value.
[0030] In a third aspect, the present application provides a device for preventing a return-oriented programming (ROP) attack, the device comprising a memory for storing a computer program or instructions; and a processor for invoking the computer program or instructions stored in the memory to execute the method in any possible implementation of the first aspect or the second aspect. BRIEF DESCRIPTION OF DRAWINGS
[0031] In order to more clearly illustrate the technical solutions in the embodiments of the present application, the drawings needed in the embodiment description will be briefly introduced. Obviously, the drawings in the following description are only some embodiments of the present application, and other drawings can be obtained by those skilled in the art without creative labor.
[0032] Figure 1 A flowchart of a method for preventing a ROP attack provided by an embodiment of the present application;
[0033] Figure 2 A flowchart of a method for preventing a ROP attack provided by an embodiment of the present application;
[0034] Figure 3 A flowchart of a PAC signature and verification process provided by an embodiment of the present application;
[0035] Figure 4 A flowchart of another PAC signature and verification process provided by an embodiment of the present application;
[0036] Figure 5 A flowchart of another PAC signature and verification process provided by an embodiment of the present application;
[0037] Figure 6 A structural diagram of a device 6000 for preventing a ROP attack provided by an embodiment of the present application. DETAILED DESCRIPTION
[0038] In order to make the purposes, technical solutions and advantages of the present application clearer, the present application will be further described in detail below with reference to the drawings. Obviously, the described embodiments are only some of the embodiments of the present application, but not all the embodiments. Based on the embodiments in the present application, all other embodiments obtained by those skilled in the art without creative labor are within the scope of protection of the present application.
[0039] The present application provides a method for preventing a ROP attack, which is used to prevent a ROP attack by generating a PAC and adding the PAC to a return address, thereby improving the security of software.
[0040] In order to facilitate understanding, some terms involved in the present application will be explained first.
[0041] Stack: is a region in the virtual memory, in the process of function call, used to store the state of the function and the local variables or temporary variables inside the function, the stack is last in first out, the address of the top of the stack is called stack pointer. Generally speaking, the stack is grown from top to bottom, in other words, the address of the bottom of the stack is larger than the address of the top of the stack (i.e. the stack pointer), in the case of the stack growing from top to bottom, the address of the bottom of the stack is the starting address of the stack, the address of the top of the frame is the stack pointer, and each time a new element is pushed into the stack, it is always pushed into the top of the stack and the stack pointer points to a lower address. The stack in the present application can also grow from bottom to top, and the present application does not limit the growth mode of the stack.
[0042] Stack frame: in the process of function call, a new stack frame is generated each time the function is called, and the current stack frame is released each time the function returns. As can be seen, the stack frame is a block of stack area associated with a certain call of a function, and the size of the stack frame required by a given function is determined. For the same function, when it is called multiple times, the stack frame occupied may not be located at the same address. If a function appears multiple times on the call chain at a certain time, the function must occupy different stack frames when it is called several times. For example: there are functions A, B and C, and the following call chain is generated: A -> B -> C -> B -> B -> C, assuming that the stack grows from top to bottom, from top to bottom there are: the stack frame of function A, the stack frame of the first call of function B, the stack frame of the first call of function C, the stack frame of the second call of function B, the stack frame of the third call of function B, and the stack frame of the second call of function C. At a certain place in the stack frame, the address to be returned after the current function is executed is stored.
[0043] Stack pointer and stack pointer register: the stack pointer represents the address of the top of the stack, which is equivalent to the address of the top of the current stack frame. The stack pointer register is a register that stores the stack pointer. By reading the stack pointer register, we can know the address of the current top of the stack; by writing the stack pointer register, we can update the address of the top of the stack after pushing data into the stack or popping data out of the stack. In particular, with the occurrence of function calls, the value of the stack pointer also changes due to the establishment and release of stack frames during function calls. The stack pointer register of some instruction set architectures such as Instruction Set Architecture (ISA) is automatically managed, in other words, special instructions are provided to move the stack pointer at the same time as pushing data into the stack or popping data out of the stack; the stack pointer register of some other instruction set architectures is manually managed, in other words, the value of the stack pointer register needs to be updated after or before pushing data into the stack or popping data out of the stack by using another instruction, in this case, the usual method is to update the value of the stack pointer register after or before pushing or popping a batch of data, rather than updating it once after or before pushing or popping one data.
[0044] ROP: a very important attack technique in the field of computer security, which uses existing code fragments in the program to achieve the function that the attacker wants by skillfully combining these code fragments. Attackers can construct ROP chains to execute arbitrary code, such as opening backdoors, stealing data, etc. ROP can bypass some security protection mechanisms, such as writable XOR executable, stack non-executable, etc.
[0045] PAC: takes advantage of the feature that the full 64-bit address space does not need to be used under 64-bit architecture, and embeds authentication code in the unused bits to authenticate a pointer and verify its authentication before using the pointer later to prevent the use of some malicious attack techniques and achieve the effect of improving software security. The calculation of PAC uses a specific algorithm that takes three parameters as input: the pointer, which refers to the original pointer that has not yet embedded PAC, the context, and the key, and produces an output: PAC, which is the pointer authentication code.
[0046] The PAC is calculated by the above algorithm and embedded into the corresponding pointer. A pointer containing PAC cannot be used directly, so there is also a new instruction for verifying the PAC and restoring the pointer. Since the above algorithm is reproducible, it is only necessary to first strip the PAC from the pointer containing the PAC, and then use the above algorithm to calculate the PAC based on the pointer after stripping the PAC, the context and the key. Whether the PACs calculated twice are equal can be compared. If they are equal, the PAC verification passes, and the pointer is modified to the form of stripping the PAC, so that the pointer can be used directly subsequently and becomes a legal pointer; if they are not equal, the PAC verification fails, and the pointer will remain illegal, or if it is not originally in the illegal form, such as a pointer without PAC, this step will convert it into an illegal form, and subsequent use of it will cause an exception.
[0047] Figure 1 A flowchart of a method for preventing ROP attacks provided by an embodiment of the present application, which can be executed by a CPU that processes instructions in a pipeline mode. The method is used to add a PAC to the reserved bits of a return address to obtain a return address carrying a PAC, as shown in Figure 1 The flowchart includes the following steps:
[0048] Step 101: When the CPU processes instructions in a pipeline stage mode, if the first target instruction and the target pipeline stage in the function call are identified, the target pipeline stage is paused.
[0049] Step 102: The CPU obtains the return address, the stack pointer and the key of the function call through the instruction bypass unit, and generates a PAC based on the return address, the stack pointer and the key. The PAC is added to the reserved bits of the return address to obtain a return address carrying a PAC.
[0050] Step 103: After the execution of the instruction bypass unit, the CPU continues to process the first target instruction through the target pipeline stage in the pipeline.
[0051] Specifically, the first target instruction is a first setting instruction of the pre-execution and post-execution stack pointers pointing to the caller stack frame, or the first target instruction is a second setting instruction of the pre-execution and post-execution stack pointers pointing to the callee stack frame, the pre-execution and post-execution are pre-execution and / or post-execution, and the target pipeline stage is a specified pipeline stage in the pipeline. After the first target instruction and the target pipeline stage are identified, the instruction bypass unit obtains a return address, a stack pointer, and a key of the function call, generates a PAC based on the return address, the stack pointer, and the key, and adds the PAC to a reserved bit of the return address to obtain a return address carrying the PAC, which is used to prevent ROP attack on the return address. After the instruction bypass unit is executed, the first target instruction is processed through the target pipeline stage in the pipeline.
[0052] In the embodiments of the present application, the return address of the function call is a pointer in the PAC algorithm. For the A-type instruction set architecture, the A-type instruction set architecture generally belongs to the complex instruction set computer (CISC) architecture, and the jump instruction for the function call inserts the return address into the top of the stack. At this time, the data stored in the top of the stack is the return address. There is also a jump instruction for function return that directly reads the return address from the top of the stack and jumps to the address, that is, the function returns. In the A-type instruction set architecture, there is no return address register as mentioned below. The jump instruction for the function call is also an instruction for updating the stack pointer register (i.e., the pre-execution stack pointer points to the caller stack frame, and the post-execution stack pointer points to the callee stack frame), and is also an instruction for loading the return address stored on the stack. The jump instruction for the function return is also an instruction for updating the stack pointer register (i.e., the pre-execution stack pointer points to the callee stack frame, and the post-execution stack pointer points to the caller stack frame), and is also an instruction for loading the return address stored on the stack. In the following, these instructions are described separately, but in the A-type instruction set architecture, the instruction bypass behavior of the jump instruction for the function call, the instruction for updating the stack pointer register (i.e., the pre-execution stack pointer points to the caller stack frame, and the post-execution stack pointer points to the callee stack frame; or the pre-execution stack pointer points to the callee stack frame, and the post-execution stack pointer points to the caller stack frame), and the instruction for loading the return address stored on the stack (or the instruction for loading the return address stored on the stack) should be understood together, and similarly, the instruction bypass behavior of the jump instruction for the function return that is also an instruction for updating the stack pointer register should be understood together.
[0053] In a class B instruction set architecture, which is typically a reduced instruction set computer (RISC) architecture, an instruction for a function call writes the return address into a specific register, called the return address register. The prologue of a non-leaf function has an instruction to save the data in the specific register into the top of the stack. The epilogue of a non-leaf function has an instruction to restore the return address from the top of the stack into a register. Then, there is an instruction to use the address in the register for a jump, which is for a function return. Although it is possible to restore the return address into another register, typically, according to the calling convention, the function epilogue restores the return address into the return address register. The jump instruction for a function call in a class B instruction set architecture is not an instruction to update the stack pointer register; similarly, the jump instruction for a function return in a class B instruction set architecture is not an instruction to update the stack pointer register.
[0054] In the embodiments of the present application, different types of pointers are allowed to use different keys to enhance security. For the same type of pointer, there are also multiple different keys to choose from. At the same time, the user state cannot access the value of the key to ensure security. Only the kernel state and higher privileged states can access the currently effective key through special instructions. The control register can be defined to store the currently effective key, which makes the key accessible and modifiable by the kernel space. Generally, the kernel randomly generates a new key when starting a new program, and backs up / restores them when context switching. Randomly generating a key can prevent replay attacks.
[0055] Different keys are generated in the instruction bypass unit for different address space identifiers (ASIDs). Generally, when the kernel is switching processes, it will simultaneously operate the control register of the CPU to modify the current ASID. Therefore, generating different keys for different ASIDs can achieve key isolation between processes. However, the value range of ASID is limited. In typical practice, the maximum is only 1024 or a few thousand. In many use cases, the number of running processes does not exceed the value range of ASID, and the key isolation between processes is sufficient at this time. However, when the number of running processes exceeds the value range of ASID, some processes will be forced to share ASIDs, resulting in insufficient key isolation between processes. Therefore, in order to enhance security in this case and implement sufficient key isolation, the next implementation is implemented.
[0056] A pair of instructions are designed and added to the match, both of which are originally undefined or reserved. Since they are originally undefined or reserved, there will be no such instructions in the existing program. Executing such instructions will cause a bypass, and then the instruction bypass unit first verifies the privilege state of the CPU, and if it is in the user state, an exception is triggered and it does not continue; if it is in the kernel state or higher privilege state, it continues. Then parse the instructions, one of which is used to read the current configured key and write it to the register or memory address specified by the instruction; the other instruction is used to read the key from the register or memory address specified by the instruction and configure it as the current key. Thus, the kernel can back up the key of the previous process with the former instruction before process switching, and configure the key of the next process to be executed with the latter instruction, and if a process is started for the first time, the kernel generates a unique key in some way and configures it using the latter instruction.
[0057] For PAC, optionally, the following restriction can be implemented, that is, all binary bits cannot be all 1 or all 0. In other words, it is actually also a restriction that the PAC algorithm will not output all 1 or all 0. This can ensure that a pointer with PAC, if not signed by PAC, will always be an illegal address in the view of the Memory Management Unit (MMU), so it cannot be directly used, or will cause an exception when used.
[0058] It should also be noted that in many programming languages, there is the concept of function call. Each function call involves a caller and a callee, and the function call involves the passing of parameters and return values, so a common convention is needed to specify how to pass them, which is the calling convention. The calling convention creates a function prologue and a function epilogue. The function prologue is a sequence of instructions at the beginning of the function, and the function epilogue is a sequence of instructions at the end of the function. According to the above explanations, it can be determined that the value of the stack pointer changes during function calls, but as long as the program is executing normally, it is always guaranteed that the value of the stack pointer is the same at the time of entering a function due to a function call, i.e. the function prologue, and at the time of completing a function call and returning from the function, i.e. the function epilogue.
[0059] Taking MIPS64 as an example, MIPS is a type of B-class instruction set. Taking MIPS64 and a stack growing from top to bottom as an example, a typical function prologue and function epilogue are described in assembly language as follows, where the lines starting with / / are explanations of the instructions:
[0060] / / 31 The return address is stored in the register, which is written by the caller of the function when calling the function.
[0061] / / prolog
[0062] / / update the stack pointer register (sp) to point to the bottom of the stack frame sp), subtracting the stack frame size (FRAME_SIZE) from its value, i.e. pushing the stack top down.
[0063] / / The stack frame size is large enough to hold the registers to be saved, and also large enough to hold the local variables used by the function, not shown here.
[0064] daddiu sp, sp,-FRAME_SIZE
[0065] / / push the return address stored in register 31 onto the bottom of the current stack frame 31
[0066] sd 31,FRAME_SIZE-8( sp)
[0067] / / There can be other instructions to save other registers, not shown here.
[0068] <... function body...>
[0069] / / epilog
[0070] / / pop the return address from the bottom of the current stack frame into register 31 31
[0071] / / ld rt,offset( base) will load the values from the address range from offset( base) (inclusive) to offset+8( base) (exclusive) into register rt.
[0072] ld 31,FRAME_SIZE-8( sp)
[0073] / / update the stack pointer register (sp) to point to the top of the stack frame sp), adding the stack frame size (FRAME_SIZE) to its value, i.e. pushing the stack top back up to its original position,
[0074] / / in effect, restoring the value of the stack pointer register.
[0075] daddiu sp, sp,FRAME_SIZE
[0076] / / jump to 31 the address stored in the register continues execution.
[0077] jr 31
[0078] nop
[0079] According to the above code, there are the following occasions where the value of the stack pointer register is the same, before the first daddiu instruction, that is, before the function prologue, and after the second daddiu instruction, at this time the value of the stack pointer register is the old value, that is, it points to the top of the caller's stack frame. Between the first daddiu instruction and the second daddiu instruction, at this time the value of the stack pointer register is the new value, that is, it points to the top of the stack frame of the function being called, that is, the callee.
[0080] Therefore, there are two cases of determining the context corresponding to the stack pointer according to the old value of the stack pointer register and determining the context corresponding to the stack pointer according to the new value of the stack pointer register when signing the PAC.
[0081] (I) Determining the context corresponding to the stack pointer according to the old value of the stack pointer register
[0082] There are two suitable occasions for determining the context corresponding to the stack pointer using the old value of the stack pointer register. The first suitable occasion is the first daddiu instruction in the above code, which is used to update the stack pointer register by subtracting the size of the stack frame of the called function from the value of the stack pointer register. Before the execution of this instruction, the stack pointer points to the top of the caller's stack frame (equivalent to the value in the stack pointer register being the old value), and after the execution of this instruction, the stack pointer points to the top of the stack frame of the called function (equivalent to the value in the stack pointer register being the new value). The second suitable occasion is not embodied in the above assembly code. Since MIPS has a series of instructions jal / jalr / bal etc. dedicated to function calls, these instructions all write the return address into 31 register (i.e. the return address register of the MIPS architecture) at the same time as the jump, so the jal / jalr / bal etc. instructions are the second suitable occasion. Both of these instructions are the first target instruction.
[0083] For the first suitable timing, the first set instruction is an instruction where the stack pointer points to the caller's stack frame before execution (equivalent to the value in the stack pointer register being the old value), and the stack pointer points to the callee's stack frame after execution (equivalent to the value in the stack pointer register being the new value). The target pipeline stage is any pipeline stage no later than the write-back stage. "No later than the write-back stage" means that a write-back stage can be included. The return address and stack pointer of the function call are obtained through the instruction bypass unit, including reading the return address from the top of the stack or the return address register, and reading the stack pointer stored in the stack pointer register.
[0084] Specifically, the first setting instruction is the first daddiu instruction in the above code. When the first setting instruction is detected, the instruction bypass unit has the following pipeline-level bypass mode.
[0085] (1) The first suitable time for pipeline-level bypass method
[0086] For pipeline-level bypass, the bypassed pipeline stage must be any pipeline stage no later than the write-back stage. The write-back stage is the stage that writes to the register; otherwise, only the register can be retrieved. The new value of the sp register is available. A bypass write-back is also possible because it occurs before the write-back process is complete. The sp register still contains the old values; the instruction bypass unit only completes the operation on the sp register. The PAC signature of the return address on register 31 is obtained at this time. The value of the sp register is still the old value; use it and then rewrite it. Register 31 sets the bypassed pipeline stage to the current pipeline stage, and sets the instruction bypass result to the input of the current pipeline stage. This maintains the current pipeline stage's input unchanged, causing the `daddiu` instruction to skip one instruction match, thus allowing the instruction to be executed normally. Ultimately, the instruction completes the process through normal execution. Rewriting the sp register.
[0087] Specifically, one or more pipeline stages are matched, and these pipeline stages are no later than the write-back stage. These are the pipeline stages that need to be bypassed in the matching items. This is to ensure that the value of the stack pointer register has not been updated and the old value can still be retrieved. The value of the stack pointer register is read as context. For Class A instruction set architectures, the return address is read from the top of the stack; for Class B instruction set architectures, the return address is read from the return address register. Combined with the current key, the PAC signature is completed to generate the PAC. The PAC is embedded in the reserved bits of the return address. Then, for Class A instruction set architectures, the return address with the PAC is written to the top of the stack; for Class B instruction set architectures, the return address with the PAC is written to the return address register.
[0088] In a possible implementation, if a stack is used to grow from top to bottom, the instruction is identified as the first target instruction in the following manner: if the operation code in the instruction is an immediate number addition operation code, the source register is a stack pointer register, the destination register is the stack pointer register, and the immediate number is negative, then the instruction is the first target instruction; or if the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is positive, then the instruction is the first target instruction.
[0089] Since the names of instructions with the same purpose are different in different instruction set architectures, the specific name of the operation code is not limited in the present application. In the embodiments of the present application, the MIPS64 instruction set architecture is used, and the stack grows from top to bottom, and the operation code is an immediate number addition operation code. Therefore, in the MIPS64 instruction set architecture, the operation code in the instruction is DADDIU (an immediate number addition operation code), and the immediate number is negative.
[0090] Specifically, since the daddiu instruction itself can also be used as a general operation purpose, which is not the purpose we want to match, we only want to match the case where it is used to decrement the sp register (i.e., the stack pointer register). Therefore, when using the mask matching, the operation code needs to be matched as DADDIU, the source register domain needs to be matched as sp, and the destination register domain needs to be matched as sp. However, the immediate number cannot be matched, because the value filled therein is the stack frame size, which is not the same for different functions. The matching item is shown in Table 1:
[0091] Table 1
[0092]
[0093] In Table 1, 1 indicates that the binary bit is 1, 0 indicates that the binary bit is 0, and x indicates that the binary bit can be any value. As can be seen from Table 1, the binary bits with the mask of 1 participate in matching, and the binary bits with the mask of 0 do not participate in matching. This also applies to subsequent tables, and will not be described in detail.
[0094] Since in the prologue of a function, either no stack frame is allocated, or once a stack frame is allocated, the stack top is always pushed down (since the stack used in this example grows from top to bottom), when further matching is needed, we want to match only the case where the stack top is pushed down, that is, the immediate number is negative. In the case of a self-decrement by sp, the immediate number must be filled in as a negative number. It is noted that according to the instruction definition of daddiu, the filled-in immediate number is actually a signed number, that is, the most significant bit can be used to determine the sign of the immediate number, when it is 1, the immediate number must be negative, otherwise it must be non-negative. The matching item is shown in Table 2 as an example:
[0095] Table 2
[0096]
[0097] In a possible implementation, if the AArch64 (also called ARM64 or Arm A64) instruction set architecture is used, and the stack is grown from top to bottom, and the operation code is an immediate number subtraction operation code, the operation code in the instruction is SUB (and is an immediate number subtraction operation code), and the immediate number is a positive value. Exemplarily, if the matching item in this example is described in the assembly language of AArch64, it is SUB SP, SP, #, where SUB indicates that the matching operation code is an immediate number subtraction operation code, SP is the stack pointer register of AArch64, the first SP indicates that the matching destination register is the stack pointer register, the second SP indicates that the matching source register is the stack pointer register, and # indicates that the matching positive immediate number is.
[0098] In a possible implementation, if a stack that grows from bottom to top is used, the instruction that satisfies any one of the following two conditions is determined as the first target instruction:
[0099] (a) the operation code in the instruction is an immediate number addition operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is a positive value; (b) the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is a negative value. The stack that grows from bottom to top is a stack with the stack bottom at a low address and the stack top at a high address, where the high address is a memory address with a larger address value, and the low address is a memory address with a smaller address value. The specific matching method is not described in detail here.
[0100] For the second suitable opportunity, the first set instruction is a jump instruction for function calling, and the target pipeline is the memory stage or the write-back stage. The return address of the function calling and the stack pointer are obtained by the instruction bypass unit, including obtaining the return address from the input of the target pipeline stage, and reading the stack pointer stored in the stack pointer register.
[0101] The jump instruction used for function calls can be described as follows: write the return address to the top of the stack (for Class A instruction set architecture) or to the return address register (for Class B instruction set architecture), and then jump to the target address.
[0102] Specifically, the first setting instruction can be an instruction such as jal / jalr / bal. When the first setting instruction is detected, the instruction bypass unit has the following pipeline-level bypass mode.
[0103] (2) The second suitable time for pipeline-level bypass method
[0104] For pipeline-level bypass, the instruction bypass unit obtains the input to the target pipeline level, completes the PAC signature, and at this point obtains... The value of the sp register remains the old value, which is used, and the signed return address is used as the bypass result, setting the bypassed pipeline stage to the current pipeline stage. This causes the jump instruction used for the function call to temporarily skip one instruction match, allowing the instruction to enter the current pipeline stage. However, the input of the current pipeline stage has now been rewritten with a PAC-signed return address containing the PAC. This ensures that for Class A instruction set architectures, the return address with the PAC is written to the top of the stack, or for Class B instruction set architectures, the return address with the PAC is written to the return address register.
[0105] Specifically, for Class A instruction set architectures, the matching stage is the memory access stage (the stage where memory access is performed). For Class B instruction set architectures, the matching stage is the write-back stage (the stage where registers are written). These are the pipeline stages that need to be bypassed in the matching criteria. This is to obtain the return address directly from the input of the pipeline stage. The value of the stack pointer register is read as the context, the return address is obtained from the input of the current pipeline stage, and combined with the current key, a PAC signature is completed to generate the PAC. The PAC is embedded in the return address, and the return address containing the PAC is used as the instruction bypass result.
[0106] When using mask matching for these types of instructions, only the opcode needs to be matched, because these instructions will always write the return address. 31, regardless of the values filled in other fields. The opcodes for these instructions vary; some use a single opcode, while others use multiple opcode levels. Sufficient opcode levels should be matched until the instruction type can be determined. Details will not be elaborated further.
[0107] (ii) Determine the context corresponding to the stack pointer based on the new value of the stack pointer register.
[0108] There are two suitable opportunities for determining the context corresponding to the stack pointer using the new value of the stack pointer register, the first suitable opportunity is the first daddiu instruction in the above code, which is used to update the stack pointer register, subtracting the stack frame size of the callee from the value of the stack pointer register, before the execution of the instruction, the stack pointer points to the top of the stack frame of the caller (equivalent to the value in the stack pointer register being the old value), after the execution of the instruction, the stack pointer points to the top of the stack frame of the callee (equivalent to the value in the stack pointer register being the new value). The second suitable opportunity is the sd instruction in the above assembly code, which is used to back up the value of the 31 register to the stack. Both of the instructions are the first target instruction. 31 register to the stack. Both of the instructions are the first target instruction.
[0109] For the first suitable opportunity, the second setting instruction is the instruction that makes the stack pointer point to the stack frame of the caller before execution (equivalent to the value in the stack pointer register being the old value) and makes the stack pointer point to the stack frame of the callee after execution (equivalent to the value in the stack pointer register being the new value), the target pipeline stage is the write-back stage, and the return address and the stack pointer of the function call are obtained by the instruction bypass unit, including reading the return address from the top of the stack or the return address register, and obtaining the stack pointer from the input of the target pipeline stage.
[0110] Specifically, the second setting instruction is the first daddiu instruction in the above code, and when the second setting instruction is identified, the instruction bypass unit has the following pipeline stage bypass mode.
[0111] (1) Pipeline stage bypass mode under the first suitable opportunity
[0112] For pipeline stage bypass, the write-back stage can be bypassed, that is, the stage of writing to the register, and the instruction bypass unit only completes the PAC signature of the return address on the 31 register at this time, and the input of the write-back stage obtained at this time is the new value of the sp register, which is used and overwrites the 31 register. sp register, and the bypassed pipeline stage is the current pipeline stage. This makes the instruction temporarily skip the instruction matching once, so that the instruction is normally executed, and finally the overwriting of the sp register is completed through normal execution.
[0113] Specifically, for the A-type instruction set architecture, the return address is read from the top of the stack, and for the B-type instruction set architecture, the return address is read from the return address register, and the PAC signature is completed by using the current key to generate the PAC. The PAC is embedded in the reserved bits of the return address, and then for the A-type instruction set architecture, the return address with the PAC is written to the top of the stack, and for the B-type instruction set architecture, the return address with the PAC is written to the return address register.
[0114] As to how to match the first daddiu instruction, the foregoing has been described and will not be repeated here.
[0115] For the second suitable timing, the second setting instruction is an instruction for storing the return address onto the stack, specifically an instruction for backing up the return address stored in the return address register onto the stack, the target pipeline stage is any pipeline stage later than the decode stage but not later than the memory stage in the pipeline, later than the decode stage but not later than the memory stage, not including the decode stage, including the memory stage. The return address of the function call and the stack pointer are obtained by the instruction bypass unit, including: obtaining the return address from the input of the target pipeline stage, reading the stack pointer stored in the stack pointer register.
[0116] Specifically, the second setting instruction can be the sd instruction in the above-mentioned assembly code, when the instruction bypass unit reaches the second setting instruction, the instruction bypass unit has the following pipeline stage bypass mode.
[0117] (2) Pipeline stage bypass mode under the second suitable timing
[0118] For pipeline stage bypass, the next stage of the decode stage is bypassed, to be precise, the next stage of the pipeline stage for fetching the register value, the instruction bypass unit obtains the input of the pipeline stage, that is, the value in the 31 register, that is, the return address, reads the value of the stack pointer register as the context, uses the current key, completes the PAC signature to generate the PAC, and embeds the PAC into the return address. At this time, the value obtained in the sp register is a new value, which is used, and the signed return address is used as the bypass result, the bypassed pipeline stage is set to the current pipeline stage, so that this instruction temporarily skips the instruction matching once, so that the instruction can enter the current pipeline stage, but the input of the current pipeline stage has been rewritten as the return address with the PAC after the PAC signature, so that the return address with the PAC can be written to the specified position on the stack by the current pipeline stage or the subsequent pipeline stage. The memory stage, that is, the stage for accessing memory, can also be bypassed, the instruction bypass unit obtains the input of the pipeline stage, that is, the return address to be written into the memory, reads the value of the stack pointer register as the context, uses the current key, completes the PAC signature to generate the PAC, and embeds the PAC into the return address. At this time, the value obtained in the sp register is a new value, which is used, and the signed return address is used as the bypass result, the bypassed pipeline stage is set to the current pipeline stage, so that this instruction temporarily skips the instruction matching once, so that the instruction can enter the current pipeline stage, but the input of the current pipeline stage has been rewritten as the return address with the PAC after the PAC signature, so that the return address with the PAC can be written to the specified position on the stack by the current pipeline stage or the subsequent pipeline stage.
[0119] The memory stage, that is, the stage for accessing memory, can also be bypassed, the instruction bypass unit obtains the input of the pipeline stage, that is, the return address to be written into the memory, reads the value of the stack pointer register as the context, uses the current key, completes the PAC signature to generate the PAC, and embeds the PAC into the return address. At this time, the value obtained in the sp register is a new value, which is used, and the signed return address is used as the bypass result, the bypassed pipeline stage is set to the current pipeline stage, so that this instruction temporarily skips the instruction matching once, so that the instruction can enter the current pipeline stage, but the input of the current pipeline stage has been rewritten as the return address with the PAC after the PAC signature, so that the return address with the PAC can be written to the specified position on the stack by the current pipeline stage or the subsequent pipeline stage. If the value of the sp register is already the new value, the value is used, the bypassed return address with the signature is used as the bypass result, the bypassed pipeline stage is set to the current pipeline stage, so that the instruction is temporarily skipped once in the instruction matching, so that the instruction can enter the current pipeline stage, but at this time the input of the current pipeline stage has been rewritten as the PAC signatured return address with PAC, so that the return address with PAC can be written to the specified location on the stack by the current pipeline stage, i.e. the memory stage.
[0120] If a stack growing from top to bottom is used, the instruction is identified as the first target instruction in the following manner: the opcode in the instruction is a memory storage opcode, the source register is a return address register, the memory base register is a stack pointer register, and the offset is a positive value. The stack growing from top to bottom is a stack with the bottom at a high address and the top at a low address. The high address is a memory address with a larger address value, and the low address is a memory address with a smaller address value.
[0121] Specifically, since the names of instructions with the same purpose are different in different instruction set architectures, the specific name of the opcode is not limited in the present application. In the embodiments of the present application, the MIPS64 instruction set architecture is used, and the stack is taken as an example of growing from top to bottom. Therefore, in the MIPS64 instruction set architecture, the opcode in the instruction is SD (belonging to a memory storage opcode), and the offset is a positive value.
[0122] Specifically, when the mask is used to match the instruction, the sd instruction is a memory access instruction using a base register plus an immediate offset to address, which reads the data stored in the source register and writes it to the memory address determined by the addressing mode. If the data is to be written to the stack, the base register should be sp. In this case, the matching item not only matches the instruction as sd, but also matches the source register used by the instruction as 31, and matches the base register used by the instruction as sp. The matching item is shown in Table 3:
[0123] Table 3
[0124]
[0125] Further, considering that when accessing data in the stack, the data should be in the stack rather than outside the stack, and the memory address range occupied by the stack can be represented from the bottom of the stack to the top of the stack, and considering that the address stored in the sp register points to the top of the stack, since the stack growing from top to bottom is used in the present example, the target address of a legal memory access to the stack must be higher than the address of the top of the stack. Therefore, when the When sp is used as the base register, the offset must be a positive integer to make the target memory address in the stack rather than outside the stack. Since the offset of the above instruction is a signed integer, to make the offset a positive integer, the highest bit of the offset must be 0. Therefore, a preferred match is shown in Table 4:
[0126] Table 4
[0127]
[0128] In a possible implementation, if a stack grows from bottom to top, the instruction is identified as the first target instruction, the opcode in the instruction is a memory storage opcode, the source register is a return address register, the memory base register is a stack pointer register, and the offset is negative. The stack growing from bottom to top is a stack with the bottom at a low address and the top at a high address; the high address is a memory address with a larger address value; and the low address is a memory address with a smaller address value. Specifically, taking the MIPS64 instruction set architecture and taking the stack growing from bottom to top as an example, in the MIPS64 instruction set architecture, the opcode in the instruction is SD (belonging to the memory storage opcode), and the offset is negative. The matching example is similar to Table 4, except that the binary number representing the sign of the immediate number in the 15th bit is 0.
[0129] Figure 2 A flowchart of a method for preventing ROP attacks provided by an embodiment of the present application, which can be executed by a CPU processing instructions in a pipeline mode, is used to determine whether a PAC to be verified is the same as a PAC carried by a return address. As shown in FIG. 2, the flowchart includes the following steps. Figure 2
[0130] In step 201, when processing instructions in a pipeline stage mode, the CPU stops a target pipeline stage if a second target instruction in a function call and the target pipeline stage are identified.
[0131] In step 202, the CPU acquires a return address carrying a PAC, a stack pointer, and a key through an instruction bypass unit, and generates a PAC to be verified based on the return address stripped of the PAC, the stack pointer, and the key.
[0132] In step 203, if the PAC is the same as the PAC to be verified, the second target instruction is processed through the target pipeline stage in the pipeline; or if the PAC is different from the PAC to be verified, an exception is triggered.
[0133] Specifically, the second target instruction is a third setting instruction for the execution-before and execution-after stack pointers to point to the caller stack frame, or the second target instruction is a fourth setting instruction for the execution-before and execution-after stack pointers to point to the callee stack frame. The execution-before and execution-after are the execution-before and / or the execution-after, and the target pipeline stage is a specified pipeline stage in the pipeline. After the second target instruction and the target pipeline stage are identified, the instruction bypass unit obtains the return address carrying the PAC, the stack pointer, and the key, and generates a PAC to be verified based on the return address carrying the PAC, the stack pointer, and the key. If the PAC is the same as the PAC to be verified, the second target instruction is processed through the target pipeline stage in the pipeline; if the PAC is different from the PAC to be verified, an exception is triggered, and the exception indicates an ROP attack on the return address.
[0134] When the PAC is verified, there are two cases of determining the context corresponding to the stack pointer according to the old value of the stack pointer register and determining the context corresponding to the stack pointer according to the new value of the stack pointer register.
[0135] (1) Determining the context corresponding to the stack pointer according to the old value of the stack pointer register
[0136] There are two suitable opportunities to determine the context corresponding to the stack pointer using the old value of the stack pointer register. The first suitable opportunity is the second daddiu instruction in the above code, that is, the instruction for restoring the stack pointer register. Only the value of the restored stack pointer register needs to be used as the context in the bypass to execute the verification and modify the target address of the jump accordingly. The second suitable opportunity is the jr instruction in the above code, that is, the instruction for actually using the stack pointer register. At this time, only the value of the restored stack pointer register needs to be used as the context in the bypass to execute the verification and modify the target address of the jump accordingly. 31 register value. The second suitable opportunity is the jr instruction in the above code, that is, the instruction for actually using the stack pointer register. At this time, only the value of the restored stack pointer register needs to be used as the context in the bypass to execute the verification and modify the target address of the jump accordingly. 31 register value. The second suitable opportunity is the jr instruction in the above code, that is, the instruction for actually using the stack pointer register. At this time, only the value of the restored stack pointer register needs to be used as the context in the bypass to execute the verification and modify the target address of the jump accordingly.
[0137] For the first suitable opportunity, the third setting instruction is an instruction for the execution-before stack pointer to point to the callee stack frame (equivalent to the value in the stack pointer register being a new value) and the execution-after stack pointer to point to the caller stack frame (equivalent to the value in the stack pointer register being an old value), and the target pipeline stage is the write-back stage. The return address carrying the PAC, the stack pointer, and the key are obtained by the instruction bypass unit, including: reading the return address carrying the PAC from the top of the stack or the return address register; and obtaining the stack pointer from the input of the target pipeline stage.
[0138] Specifically, the third setting instruction is the second daddiu instruction in the above code. When the third setting instruction is identified, the instruction bypass unit has the following pipeline stage bypass mode.
[0139] (1) Pipeline stage bypass mode under the first suitable opportunity
[0140] For pipeline-level bypass, a bypass write-back stage can be selected, i.e., the stage for writing to registers. The instruction bypass unit only completes the write-back of the register. The PAC checksum of the return address on register 31, at which point the write-back input is obtained. The old value of the sp register after restoration is used and rewritten. Register 31 sets the bypassed pipeline stage to the current pipeline stage (write-back stage), and sets the instruction bypass result to the input of the current pipeline stage, thus maintaining the current pipeline stage's input unchanged. This causes the instruction to temporarily skip one instruction match, allowing it to complete the execution normally. Rewriting the sp register.
[0141] Specifically, for Class A instruction set architectures, the return address with the PAC is read from the top of the stack; for Class B instruction set architectures, the return address with the PAC is read from the return address register. The PAC is stripped from the return address to obtain the original return address. The updated stack pointer register value is obtained from the current pipeline stage input as context, and combined with the current key, a new PAC is generated using the original return address. This is compared with the previously stripped PAC. If they match, for Class A instruction set architectures, the original return address is written to the top of the stack; for Class B instruction set architectures, the original return address is written to the return address register. Otherwise, the original return address with the PAC is maintained, or an invalid address is written. Optionally, if the comparison is inconsistent, an exception can be raised directly without proceeding to the next step.
[0142] In one possible implementation, if a top-to-bottom growing stack is used, the instruction is identified as the second target instruction in the following ways: if the opcode in the instruction is an immediate addition opcode, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate value is positive, then the instruction is the second target instruction; or, if the opcode in the instruction is an immediate subtraction opcode, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate value is negative, then the instruction is the second target instruction. The top-to-bottom growing stack has its bottom at a high address and its top at a low address, where the high address is a memory address with a larger memory value, and the low address is a memory address with a smaller memory value.
[0143] This application uses the MIPS64 instruction set architecture, and takes the stack as growing from top to bottom and the opcode as an immediate addition opcode as an example. Therefore, in the MIPS64 instruction set architecture, the opcode in the instruction is DADDIU (which is an immediate addition opcode), and the immediate value is positive.
[0144] Specifically, since in the tail of the function, either the stack frame is not released, or once the stack frame is released, the stack top is always pushed up (since the stack used in this example grows from top to bottom), here we want to match only the case of pushing the stack top up, that is, the case of self-incrementing the sp, at this time, the above immediate number must be filled in a positive number. According to the instruction definition of daddiu, the most significant bit can be used to determine the sign of the immediate number, and the most significant bit of the immediate number must be 0, and an example of the matching item is shown in Table 5:
[0145] Table 5
[0146]
[0147] In a possible implementation, if a stack growing from bottom to top is used, the instruction satisfying any one of the following two conditions is determined as the second target instruction: (a) the operation code in the instruction is an immediate number addition operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is a negative value; (b) the operation code in the instruction is an immediate number subtraction operation code, the source register is the stack pointer register, the destination register is the stack pointer register, and the immediate number is a positive value. The stack growing from bottom to top is a stack with the stack bottom at a low address and the stack top at a high address; the high address is a memory address with a larger address value, and the low address is a memory address with a smaller address value. The specific matching method is not described in detail here.
[0148] For the second suitable opportunity, the third set instruction is a jump instruction for function return, and the target pipeline stage is a memory stage or a write-back stage, and the instruction bypass unit acquires the return address carrying the PAC and the stack pointer, including: acquiring the return address carrying the PAC from the input of the target pipeline stage, and reading the stack pointer stored in the stack pointer register.
[0149] Specifically, the third set instruction can be a jr instruction, and when the third set instruction is identified, the instruction bypass unit has the following pipeline stage bypass mode.
[0150] (2) Pipeline stage bypass mode under the second suitable opportunity
[0151] For pipeline stage bypass, for B-type instruction set architecture, the matched pipeline stage that needs to be bypassed is any pipeline stage between decode stage (inclusive) to write back stage (inclusive). This is to get the return address with PAC directly from the input of the pipeline stage. The PAC in the return address is stripped off to get the original return address. The value of the stack pointer register is read as the context, and the original return address is used to generate the PAC again using the current key, and the PAC verification is completed. Compared with the PAC stripped off before, if the comparison is consistent, the verification is passed, and the return address with the PAC stripped off is used as the bypass result after the verification is passed. If the verification is not passed, an exception can be triggered, and optionally, the return address can be maintained as it is or changed to an illegal address. The pipeline stage after bypassing is the current pipeline stage, i.e., the target pipeline stage in the match. This causes the bypass result to be used for jumping, that is, the address after PAC verification is used to perform jumping.
[0152] For A-type instruction set architecture, since the jump instruction for function return of this type of instruction set architecture is to get the return address from the stack directly and use it, only the next stage of the memory stage needs to be bypassed, and the return address with PAC can be directly obtained from the input of the pipeline stage. The remaining procedures are the same. It is worth noting that, in general, the next stage of the memory stage belongs to any pipeline stage between the decode stage (inclusive) to the write back stage (inclusive).
[0153] The jr instruction is an instruction that reads the address stored in the source register and jumps to the address. In this case, the match item needs to match both the instruction as jr and the source register used by the instruction as 31. In addition, it is noted that the jr instruction uses a two-level opcode, so the opcode of two levels must be matched to determine that the instruction is jr. An example of the match item is shown in Table 6:
[0154] Table 6
[0155]
[0156] (2) Determine the context corresponding to the stack pointer according to the new value of the stack pointer register
[0157] There are two suitable opportunities to determine the context corresponding to the stack pointer using the new value of the stack pointer register. The first suitable opportunity is the second daddiu instruction described above, that is, the instruction for restoring the stack pointer register. Only the current value of the stack pointer register (the value before the instruction is executed) needs to be used in the bypass as the context to perform verification and modify the 31 register value accordingly. The second suitable opportunity is the ld instruction in the above code, that is, the instruction for popping the return address from the bottom of the current stack frame to the 31 register, at this time, only need to use the current value of the stack pointer register in bypass as the context to execute the signature verification and use the signature verification return address written to 31 accordingly.
[0158] For the first suitable opportunity, the fourth setting instruction is the instruction that the pre-execution stack pointer points to the callee stack frame (equivalent to the value in the stack pointer register is the new value) and the post-execution stack pointer points to the caller stack frame (equivalent to the value in the stack pointer register is the old value), the target pipeline stage is no later than the write-back stage, the instruction bypass unit obtains the return address carrying PAC and the stack pointer, including, reading the return address carrying PAC from the top of the stack or the return address register, obtaining the stack pointer from the input of the target pipeline stage.
[0159] Specifically, the fourth setting instruction is the second daddiu instruction in the above code, when the second setting instruction is identified, the instruction bypass unit has the following pipeline stage bypass mode.
[0160] (1) The pipeline stage bypass mode under the first suitable opportunity
[0161] For pipeline stage bypass, the bypassed pipeline stage must be no later than the write-back stage, i.e., the stage of writing to the register, otherwise only the old value of the sp register can be obtained, and the write-back stage can be bypassed, because before the write-back stage is executed, the sp register is still the new value. The instruction bypass unit only completes the PAC signature verification of the return address on the 31 register, at this time, the value of the sp register obtained is still the new value, which is used and the 31 register is rewritten, the bypassed pipeline stage is set to the current pipeline stage, so that this instruction is temporarily skipped once the instruction matching is performed, so that the instruction is normally executed, and finally the rewriting of the sp register is completed.
[0162] Specifically, for the A-type instruction set architecture, the return address with PAC is read from the top of the stack, and for the B-type instruction set architecture, the return address with PAC is read from the return address register. The PAC in the return address is stripped, thus obtaining the original return address. The stack pointer register value is taken from the input of the current pipeline stage as the context, where the value of the stack pointer register has not been updated and is still the new value, and the current key is used to regenerate the PAC again using the return address after stripping the PAC, and compared with the PAC obtained by stripping before. If the comparison is consistent, the original return address is written to the top of the stack for the A-type instruction set architecture, and the original return address is written to the return address register for the B-type instruction set architecture. Otherwise, the return address with PAC is maintained or an illegal address is written, and optionally, an exception can be directly triggered when the comparison is inconsistent without entering the next step.
[0163] As to how to match the second daddiu instruction, the foregoing has been described and will not be repeated here.
[0164] For the second suitable opportunity, the fourth setting instruction is an instruction for restoring the return address stored on the stack to the return address register, and the target pipeline stage is the write-back stage. The PAC-carrying return address and the stack pointer are obtained by the instruction bypass unit, including obtaining the PAC-carrying return address from the input of the target pipeline stage and reading the stack pointer stored in the stack pointer register.
[0165] Specifically, the fourth setting instruction can be the ld instruction in the above-mentioned assembly code, and when the fourth setting instruction is reached, the instruction bypass unit has the following pipeline stage bypass mode.
[0166] (2) Pipeline stage bypass mode under the second suitable opportunity
[0167] For pipeline stage bypass, the write-back stage, i.e., the stage of writing to the register, can be bypassed. The instruction bypass unit completes the PAC verification of the return address, and the value of the sp register obtained at this time is still the new value and is used. The input of the write-back stage obtained at this time is the data on the target memory address, i.e., the return address with the PAC signature, and is used. The bypassed pipeline stage is the current pipeline stage, i.e., the write-back stage. This makes the instruction temporarily skip the instruction matching once, so that the instruction can enter the write-back stage, but the input of the write-back stage has been rewritten as the return address after PAC verification, so that the return address after PAC verification is written to the 31 register by the write-back stage.
[0168] Specifically, the return address with PAC is fetched from the input of the write-back pipeline stage, and the PAC in the return address is stripped to obtain the original return address. The value of the stack pointer register is read as the context, and the original return address is used to generate the PAC again using the current key. If the comparison is consistent with the PAC stripped from the previous PAC, the original return address is taken as the instruction bypass result; otherwise, the original input of the current pipeline stage is maintained as the instruction bypass result or an illegal address is used as the instruction bypass result. Alternatively, an exception can be directly triggered without entering the next step when the comparison is inconsistent.
[0169] If a stack growing from top to bottom is used, the instruction is identified as the second target instruction in the following manner: if the operation code in the instruction is a memory load operation code, the target register is a return address register, the memory base address register is a stack pointer register, and the offset is a positive value, the instruction is the second target instruction.
[0170] The embodiment of the present application uses the MIPS64 instruction set architecture, and takes the stack growing from top to bottom as an example. Therefore, in the MIPS64 instruction set architecture, the operation code in the instruction is LD (belonging to a memory load operation code), and the offset is a positive value.
[0171] Specifically, when using mask matching for such instructions, the ld instruction is a memory access instruction using a base register plus an immediate offset to address, which reads data from a determined memory address and writes it into a target register. If data is to be read from the stack, the base register should be sp. In this case, the matching item should match that the instruction is ld, that the target register used by the instruction is 31, and that the base register used by the instruction is sp. An example of the matching item is shown in Table 7.
[0172] Table 7
[0173]
[0174] Further, considering that when data in the stack is accessed, the data should be in the stack rather than outside the stack, and the memory address range occupied by the stack can be represented from the bottom of the stack to the top of the stack, and considering that the address stored in the sp register points to the top of the stack, since the stack growing from top to bottom is used in this example, the target address of a legal memory access to the stack must be higher than the address of the top of the stack. Therefore, when the When sp is used as a base register, the offset must be a positive integer to make the target memory address in the stack rather than out of the stack. Since the offset of the above instruction is a signed integer, to make the offset a positive integer, the highest bit must be 0. Therefore, a preferred match is shown in Table 8:
[0175] Table 8
[0176]
[0177] In a possible implementation, if a stack grows from bottom to top, the instruction satisfying the following condition is determined as the second target instruction: the operation code in the instruction is a memory load operation code, the target register is a return address register, the memory base register is a stack pointer register, and the offset is negative. The stack growing from bottom to top is a stack with the bottom at a low address and the top at a high address; the high address is a memory address with a larger address value; and the low address is a memory address with a smaller address value. Specifically, taking the MIPS64 instruction set architecture and taking the stack growing from bottom to top as an example, in the MIPS64 instruction set architecture, the operation code in the instruction is LD (belonging to the memory load operation code), and the offset is negative. The matching example is similar to Table 8, except that the binary number representing the sign of the immediate number on the 15th bit is 1.
[0178] Therefore, as described above, the PAC signature can be signed in the reserved bits of the pointer, Figure 3 A PAC signature and signature verification process schematic diagram provided by an embodiment of the present application. In order to implement PAC, we must define which bit field of the pointer is to be used to embed PAC, and also need to pay attention to not causing additional information loss in this process, that is, in this process, the valid bits of the pointer cannot be used, and the high / low address identifier cannot be lost, or at least the lost information can be recovered.
[0179] The existing pointer actually has one face and two sides of the reserved bits and the high / low address identifier, because there are usually the following two applicable regulations at the same time: the highest bit is 1 for the high address (kernel space address), and the lowest bit is 0 for the low address (user space address). Each bit between the highest bit and the highest significant bit is a reserved bit. All reserved bits must be synchronized with the highest bit to be the same binary value, otherwise it is an illegal pointer, that is, an illegal memory address or an unstandard memory address. In other words, the highest bit and the reserved bit must be all 1 or all 0, otherwise it is not a legal address.
[0180] Therefore, as long as a pointer is legal, any reserved bit of the pointer is related to the high / low address in addition to the highest bit. Therefore, the highest bit and the reserved bit can be collectively referred to as the reserved bit and the high / low address identifier.
[0181] Based on this, the embodiment of the present application provides a redefinition method of a pointer bit field, which can embed PAC while maintaining any original effective information without loss. That is, the use of the original effective bit is not changed, and the reserved bit and the high / low address identifier are re-allocated.
[0182] In a possible implementation, at least one bit is used as the high / low address identifier, and the remaining bits are used to embed PAC without limitation on the position and length. Figure 4 Another PAC signature and verification flowchart provided by the embodiment of the present application is shown in FIG. 6. As can be seen from FIG. 6, the highest bit can be used as the high / low address identifier, and the remaining reserved bits are all used to embed PAC. Figure 4
[0183] Figure 5 Another PAC signature and verification flowchart provided by the embodiment of the present application is shown in FIG. 6. As can be seen from FIG. 6, the highest bit can be used as the high / low address identifier, and the remaining reserved bits are all used to embed PAC.
[0184] Figure 6 A structure diagram of a device 6000 for preventing ROP attack provided by the embodiment of the present application is shown in FIG. 7. As shown in FIG. 7, the device 6000 includes at least one processor 601 and a memory 602 connected with the at least one processor 601. In the embodiment of the present application, the specific connection medium between the processor 601 and the memory 602 is not limited, and the connection between the processor 601 and the memory 602 through a bus is taken as an example. Figure 6 Figure 6 The bus can be divided into an address bus, a data bus, a control bus, etc.
[0185] In the embodiment of the present application, the memory 602 stores instructions executable by the at least one processor 601, and the at least one processor 601 can implement the steps of the method for preventing ROP attack by executing the instructions stored in the memory 602.
[0186] The processor 601 is the control center of the computer device, can connect various parts of the computer device by using various interfaces and lines, and perform resource setting by running or executing instructions stored in the memory 602 and calling data stored in the memory 602. Optionally, the processor 601 can include one or more processing units, and the processor 601 can integrate an application processor and a modem processor, where the application processor mainly processes an operating system, a user interface, and an application program, and the modem processor mainly processes wireless communication. It can be understood that the above modem processor can also not be integrated into the processor 601. In some embodiments, the processor 601 and the memory 602 can be implemented on the same chip, and in some embodiments, they can also be respectively implemented on independent chips.
[0187] The processor 601 can be a general-purpose processor, for example, a central processing unit (CPU), a digital signal processor, an application specific integrated circuit (ASIC), a field programmable gate array or other programmable logic device, a discrete gate or transistor logic device, a discrete hardware component, and can implement or execute the methods, steps, and logic block diagrams disclosed in the embodiments of the present application. The general-purpose processor can be a microprocessor or any conventional processor. The steps of the method disclosed in combination with the embodiments of the present application can be directly embodied as hardware processor execution or executed by a combination of hardware and software modules in the processor.
[0188] The memory 602, as a non-volatile computer readable storage medium, can be used to store non-volatile software programs, non-volatile computer executable programs and modules. The memory 602 can include at least one type of storage medium, for example, can include flash memory, hard disk, multimedia card, card type memory, random access memory (RAM), static random access memory (SRAM), programmable read-only memory (PROM), read-only memory (ROM), electrically erasable programmable read-only memory (EEPROM), magnetic storage, magnetic disk, optical disk, etc. The memory 602 is any other medium capable of carrying or storing desired program codes in the form of instructions or data structures and capable of being accessed by a computer, but is not limited thereto. The memory 602 in the embodiments of the present application can also be a circuit or any other device capable of realizing a storage function, used for storing program instructions and / or data.
[0189] Those skilled in the art should understand that the embodiments of the present application can be provided as a method, a system, or a computer program product. Therefore, the present application can take the form of an entirely hardware embodiment, an entirely software embodiment, or an embodiment combining software and hardware aspects. Moreover, the present application can take the form of a computer program product implemented on one or more computer-usable storage media (including, but not limited to, disk storage, CD-ROMs, optical storage, etc.) containing computer-usable program code.
[0190] The present application is described with reference to flowcharts and / or block diagrams of the method, device (system) and computer program product according to the present application. It should be understood that each flow and / or block in the flowcharts and / or block diagrams, as well as a combination of flows and / or blocks in the flowcharts and / or block diagrams, can be implemented by computer program instructions. These computer program instructions can be provided to a processor of a general-purpose computer, a special-purpose computer, an embedded processor, or other programmable data processing apparatus to produce a machine, so that the instructions executed by the processor of the computer or other programmable data processing apparatus produce a device that implements the functions specified in the flowcharts and / or block diagrams. Figure 1 The functions specified in a flow or multiple flows and / or blocks Figure 1 The functions specified in a flow or multiple flows and / or blocks
[0191] These computer program instructions can also be stored in a computer readable memory that can direct a computer or other programmable data processing apparatus to function in a particular manner, such that the instructions stored in the computer readable memory produce an article of manufacture including instructions which implement the flow Figure 1 The flow or flows and / or blocks Figure 1 The flow or flows and / or blocks
[0192] These computer program instructions can also be loaded onto a computer or other programmable data processing apparatus to cause a series of operational steps to be performed on the computer or other programmable apparatus to produce a computer implemented process such that the instructions that execute on the computer or other programmable apparatus provide steps for implementing the flow Figure 1 The flow or flows and / or blocks Figure 1 The flow or flows and / or blocks
[0193] Obviously, numerous modifications and variations of the present application are possible in light of the above teachings. It is therefore to be understood that within the scope of the appended claims and their equivalents, the application can be practiced otherwise than as specifically described.
Claims
1. A method for preventing Return-Oriented Programming (ROP) attacks, characterized in that, The method includes: When processing instructions in a pipelined manner, if a first target instruction and a target pipeline level are identified in a function call, the target pipeline level is paused. The first target instruction is a first setting instruction in which the stack pointer points to the caller's stack frame before and after execution, or the first target instruction is a second setting instruction in which the stack pointer points to the callee's stack frame before and after execution. Before and after execution refers to before execution and / or after execution. The target pipeline level is a specified pipeline level in the pipeline. The return address of the function call, the stack pointer, and the key are obtained through the instruction bypass unit. Based on the return address, the stack pointer, and the key, a pointer authentication code (PAC) is generated. The PAC is added to the reserved bits of the return address to obtain a return address carrying the PAC. The return address carrying the PAC is used to prevent ROP attacks targeting the return address. After the instruction bypass unit has finished executing, the first target instruction continues to be processed through the target pipeline stage in the pipeline.
2. The method according to claim 1, characterized in that, The first setting instruction is an instruction in which the stack pointer points to the caller's stack frame before execution and the stack pointer points to the callee's stack frame after execution; The target pipeline stage is any pipeline stage in the pipeline that is no later than the write-back stage; The term "no later than the write-back level" includes the write-back level. Obtaining the return address of a function call and the stack pointer through an instruction bypass unit includes: Read the return address from the top of the stack or the return address register; Read the stack pointer stored in the stack pointer register.
3. The method according to claim 1, characterized in that, The second setting instruction is an instruction where the stack pointer points to the caller's stack frame before execution and the stack pointer points to the callee's stack frame after execution; The target pipeline stage is a write-back stage; Obtaining the return address of a function call and the stack pointer through an instruction bypass unit includes: Read the return address from the top of the stack or the return address register; Obtain the stack pointer from the input of the target pipeline stage.
4. The method according to claim 1, characterized in that, The second setting instruction is used to store the return address onto the stack; The target pipeline stage is any pipeline stage that is later than the decoding stage but not later than the memory access stage; the stage that is later than the decoding stage but not later than the memory access stage does not include the decoding stage or includes the memory access stage. Obtaining the return address of a function call and the stack pointer through an instruction bypass unit includes: Obtain the return address from the input of the target pipeline stage; Read the stack pointer stored in the stack pointer register.
5. The method according to claim 1, characterized in that, The first setting instruction is a jump instruction used for function calls; The target pipeline is either a memory access stage or a write-back stage; Obtaining the return address of a function call and the stack pointer through an instruction bypass unit includes: Obtain the return address from the input of the target pipeline stage; Read the stack pointer stored in the stack pointer register.
6. A method for preventing Return-Oriented Programming (ROP) attacks, characterized in that, The method includes: When processing instructions in a pipelined manner, if a second target instruction and a target pipeline level are identified in a function call, the target pipeline level is paused; the second target instruction is a third setting instruction that sets the stack pointer to the caller's stack frame before and after execution, or the second target instruction is a fourth setting instruction that sets the stack pointer to the callee's stack frame before and after execution; "before and after execution" refers to before execution and / or after execution; the target pipeline level is a specified pipeline level in the pipeline. The return address carrying the pointer authentication code (PAC), the stack pointer, and the key are obtained through the instruction bypass unit, and a PAC to be verified is generated based on the return address of the stripped PAC, the stack pointer, and the key. If the PAC is the same as the PAC to be verified, then the second target instruction is processed through the target pipeline stage in the pipeline. If the PAC is different from the PAC to be verified, an exception is raised, which indicates a ROP attack targeting the return address.
7. The method according to claim 6, characterized in that, The third setting instruction is an instruction where the stack pointer points to the callee's stack frame before execution and the stack pointer points to the caller's stack frame after execution; The target pipeline stage is a write-back stage; The return address carrying the PAC is obtained through the instruction bypass unit; the stack pointer includes: Read the return address carrying the PAC from the top of the stack or the return address register; Obtain the stack pointer from the input of the target pipeline stage.
8. The method according to claim 6, characterized in that, The fourth setting instruction is an instruction where the stack pointer points to the callee's stack frame before execution and the stack pointer points to the caller's stack frame after execution. The target pipeline stage is any pipeline stage in the pipeline that is no later than the write-back stage; The term "no later than the write-back level" includes the write-back level. Obtaining the return address carrying the PAC and the stack pointer through the instruction bypass unit includes: Read the return address carrying the PAC from the top of the stack or the return address register; Read the stack pointer stored in the stack pointer register.
9. The method according to claim 6, characterized in that, The fourth setting instruction is an instruction used to load the return address stored on the stack; The target pipeline stage is a write-back stage; Obtaining the return address carrying the PAC and the stack pointer through the instruction bypass unit includes: Obtain the return address carrying the PAC from the input of the target pipeline stage; Read the stack pointer stored in the stack pointer register.
10. The method according to claim 6, characterized in that, The third setting instruction is a jump instruction used for function return; The target pipeline stage is any pipeline stage that is later than the decoding stage but not later than the write-back stage; the stage that is later than the decoding stage but not later than the write-back stage does not include the decoding stage but includes the write-back stage; Obtaining the return address carrying the PAC and the stack pointer through the instruction bypass unit includes: Obtain the return address carrying the PAC from the input of the target pipeline stage; Read the stack pointer stored in the stack pointer register.
Citation Information
Patent Citations
Stack buffer overflow attack defense method based on LBR
CN109858253A
Return Oriented Programming (ROP) Attack Protection
US20160171211A1