Checking the validity of stack pointer switching.
The stack pointer switching validity check and output capping operations secure stack pointer switches, addressing vulnerabilities in GCS data structures and optimizing thread switching, thereby enhancing security and efficiency in processor architectures.
Patent Information
- Authority / Receiving Office
- JP · JP
- Patent Type
- Applications
- Current Assignee / Owner
- ARM LTD
- Filing Date
- 2023-09-20
- Publication Date
- 2026-04-20
AI Technical Summary
Existing systems lack efficient and secure methods for switching stack pointers without incurring high performance overhead or compromising security, particularly in scenarios involving guarded control stacks (GCS) that are vulnerable to attacks like return-oriented programming (ROP).
Implement a stack pointer switching validity check operation that verifies the input data value against a stack cap value condition, ensuring it corresponds to a valid page address, independent of sub-page address bits, and optionally performs an output stack capping operation to secure the stack pointer switch.
This approach enhances security by preventing unauthorized stack pointer switches, reducing the risk of ROP attacks and ensuring secure access to GCS data structures, while optimizing processor architecture for efficient thread switching and supporting multiple stack record types.
Smart Images

Figure 2026512618000001_ABST
Abstract
Description
Technical Field
[0001] This technology relates to the field of data processing.
[0002] Using a stack pointer, access to a stack data structure in memory can be managed. The stack data structure is a data structure in which access to entries on the stack is managed according to the Last In First Out (LIFO) method. The stack pointer provides an address that can be related to determine the address of an item on the stack. When an item is pushed onto the stack and popped from the stack, the stack pointer is updated to track the position representing the "top" of the stack.
[0003] At least some examples include a memory access circuit that performs stack access to a stack data structure based on a stack pointer, and a stack pointer switching validity check operation associated with switching the output stack pointer value of the stack pointer to the input stack pointer value, where the stack pointer switching validity check operation is based on the input stack pointer value. In response to a memory access request specifying an address determined by the memory access circuit, the input data value obtained by the memory access circuit is determined whether the input data value satisfies at least one stack cap value validity condition including the condition that a predetermined portion of the input data value corresponds to a page address of a page indicating an address space including an address determined based on the input stack pointer value. A processing circuit that performs a stack pointer switching validity check operation including verifying whether it is satisfied, and the processing circuit determines whether the input data value satisfies at least one stack cap value validity condition regardless of whether a further portion of the input data value other than the predetermined portion corresponds to a sub-page address bit of an address determined based on the input stack pointer value. The processing circuit is configured to trigger an error processing response in response to determining that the input data value does not satisfy at least one stack cap value validity condition. An apparatus is provided.
[0004] At least some examples provide a stack pointer switching validity check operation associated with switching the stack pointer from an output stack pointer value to an input stack pointer value, the method comprising performing a stack pointer switching validity check operation which includes verifying whether an input data value obtained by a memory access circuit in response to a memory access request specifying an address determined based on the input stack pointer value satisfies at least one stack cap value validity condition, which includes the condition that a given portion of the input data value corresponds to a given page address indicating a page in the address space containing the address determined based on the input stack pointer value, the determination of whether the input data value satisfies at least one stack cap value validity condition is independent of whether further portions of the input data value other than the given portion correspond to subpage address bits of the address determined based on the input stack pointer value, and the method includes triggering an error handling response in response to determining that the input data value does not satisfy at least one stack cap value validity condition.
[0005] At least some examples include a computer program that, when executed by a host data processing device, includes instructions that control the host data processing device to provide an instruction execution environment for executing target code, wherein the computer program includes memory access program logic that performs stack access to a stack data structure based on a stack pointer, and a stack pointer switching validity check operation associated with switching the stack pointer from an output stack pointer value to an input stack pointer value, wherein the stack pointer switching validity check operation determines that an input data value obtained by the memory access program logic in response to a request specifying an address determined based on the input stack pointer value is determined based on the input stack pointer value, and a predetermined portion of the input data value is determined based on the input stack pointer value. The computer program provides a computer program comprising: a processing program logic that performs a stack pointer switching validity check operation, which includes verifying whether at least one stack cap value validity condition is met, which includes the condition that it corresponds to a given page address indicating a page in the address space containing the given address, wherein the processing program logic is configured to determine whether an input data value satisfies at least one stack cap value validity condition, regardless of whether any further portion of the input data value other than a given portion corresponds to a subpage address bit of an address determined based on the input stack pointer value, and the processing program logic is configured to trigger an error handling response in response to determining that the input data value does not satisfy at least one stack cap value validity condition. [Brief explanation of the drawing]
[0006] Further aspects, features, and advantages of this technology will become apparent from the following example description, which should be read in conjunction with the attached drawings. [Figure 1] An example of a data processing device is shown. [Figure 2] An example of a function call is shown below. [Figure 3]Examples of Guarded Control Stack (GCS) push and pop operations are shown. [Figure 4] This demonstrates the access permission checks for GCS load / store operations. [Figure 5] This demonstrates access permission checks for non-GCS load / store operations. [Figure 6] This indicates an authorization check for instruction fetching or branch operations. [Figure 7] This demonstrates how to control stack switching to switch the stack pointer from an output stack pointer value to an input stack pointer value. [Figure 8] This shows the processing of the first stack pointer switching instruction. [Figure 9] This shows the processing of the second stack pointer switching instruction. [Figure 10] This diagram shows how to switch the stack pointer. [Figure 11] An example of GCS encoding is shown. [Figure 12] This figure shows an example of a simulation.
[0007] The device includes memory access circuitry that performs stack access to stack data structures based on a stack pointer. Different parts of the software may be associated with different stack structures in memory, and therefore, when switching between those parts of the software, it may be desirable to switch the corresponding stack pointer from the output stack pointer value associated with the output software to the input stack pointer value associated with the input software. However, for some stacks, it may be important that the stack pointer cannot be switched to an arbitrary location that is not intended to be an input stack structure. For example, some stacks may be associated with certain security measures when pushing items onto the stack and popping items from the stack. If the stack pointer could be switched to an arbitrary software-choice address, these security measures could be bypassed, and future stack accesses could potentially access data that is not protected by these security measures.
[0008] Therefore, it may be desirable to provide a technique for monitoring stack pointer switches. One technique might be to trap updates to the stack pointer in a more privileged execution state so that the more privileged software can examine the input stack pointer value and determine whether the update is permitted. However, it may be desirable to support fast software thread switching without requiring calls to the kernel or other more privileged software. Such thread switching may occur frequently, and therefore the performance overhead of calling the kernel for each stack pointer switch may be considered too high.
[0009] In the example described below, the processing circuit supports the execution of a stack pointer switching validity check operation associated with switching the stack pointer from an output stack pointer value to an input stack pointer value. The stack pointer switching validity check operation includes verifying whether an input data value obtained by the memory access circuit in response to a memory access request specifying an address determined based on the input stack pointer value satisfies at least one stack cap value validity condition. The at least one stack cap value validity condition includes the condition that a given portion of the input data value corresponds to a given page address indicating a page in the address space containing the address determined based on the input stack pointer value. The processing circuit determines whether the input data value satisfies at least one stack cap value validity condition, regardless of whether further portions of the input data value other than the given portion correspond to subpage address bits of the address determined based on the input stack pointer value. An error handling response is triggered in response to the determination that the input data value does not satisfy at least one stack cap value validity condition.
[0010] Therefore, the input data value is retrieved by the memory access circuit from a location having a memory address determined based on the input stack pointer value. For example, if the input stack pointer value represents a previously established stack structure, the input data value can be retrieved from a location that should represent the top of the stack. To pass the validity check, the input data value is required to specify, in a given portion, a given page address that points to a page in the address space containing the address of the location providing the input data value itself. Therefore, the software must ensure that an inactive stack has a stack cap value that specifies the page address of the page in the address space that stores its value at a location associated with the input stack pointer used to refer to the stack later. This provides a security measure to eliminate some erroneous behaviors that provide an incorrect value for the input stack pointer value (which does not correspond to the intended stack structure that is to be switched), as it is relatively unlikely that a location represented by an incorrect input stack pointer value would accidentally contain a data value that specifies the page address of that location itself.
[0011] One might consider further enhancing security by requiring that valid input data values specify a particular address of the location where that value is provided, including a subpage address bit that distinguishes different addresses within the same page. This further enhances security because pointers to the exact same address where the pointer itself is stored are extremely rare, and therefore the probability of accidentally passing the stack pointer switch validity check when specifying any other random address as the input stack pointer value is extremely low.
[0012] However, the inventors have recognized that, in practice, for security reasons, it may be sufficient to indicate the page address within the stack cap value used to identify a stack structure that can be effectively switched. By determining whether at least one stack cap value validity condition is met by the input data value, regardless of whether any part of the input data value corresponds to the subpage address bits of the address determined from the input stack pointer value, this frees up bits of the data word that provide the stack cap value for other purposes. This may be particularly useful as in some use cases it may be desirable to support several different stack record types that can be allocated on the stack. If it is required that the subpage address bits are meaningful when checking the validity of the stack cap value, then most of the bits of the data word are required to specify the address within the stack cap value, leaving very few bits available to encode the stack record type, with the exception of a few lower bits of the address that may not need to be explicitly specified if data / instruction address alignment constraints are given. In contrast, by requiring a valid stack cap value to specify the page address where the stack cap value is stored, but not requiring the subpage address bits to be specified, more bits are freed up for encoding the stack record type, which could be very useful for supporting future extensions to the processor architecture.
[0013] A given page address may be a virtual page address that points to a page in the virtual address space containing a virtual address determined based on the input stack pointer value. By requiring that it be valid when the stack pointer is switched, the input data value (obtained by the memory access circuit based on the input stack pointer value) provides the virtual page address of the location where that input data value is stored, which also provides a sanity check that the input stack is being accessed using the same virtual-physical address translation mapping that was used when the stack was previously accessed, which can help detect an attack based on an attacker defining an aliasing virtual-physical address translation mapping that maps different virtual addresses to the physical addresses of the locations where the stack is stored.
[0014] The processing circuit can support performing an output stack capping operation associated with switching the stack pointer from the output stack pointer value to the input stack pointer value in order to push a valid stack cap value to a location having an address selected based on the output stack pointer value, where the valid stack cap value specifies a page address that indicates a page in the address space containing the address selected based on the output stack pointer value, in a given portion of the valid stack cap value. The output stack capping operation is complementary to the stack pointer switching validity check operation in that it sets a valid stack cap value on the output stack, and this stack cap value is expected to pass the stack pointer switching validity check operation when the stack is later switched back as the input stack in a subsequent stack switching operation.
[0015] It is not mandatory for the output stack capping operation to be conditional on an input data value that satisfies at least one stack cap value validity condition in the stack pointer switching validity check operation. Even if the input stack pointer is incorrect and the input data value loaded based on the input stack pointer value fails the check in the stack pointer switching validity check operation, it may still be safe to cap the output stack with a valid stack cap value. In any case, as described below, in some implementations, the output stack capping operation can be triggered by a different instruction for the stack pointer switching validity check operation, and therefore the circuit logic that implements the function of the instruction for triggering the output stack capping operation can be defined independently of any validity check, and the output stack capping operation can be easily performed. Even if an error is detected in response to the instruction that triggers the stack pointer switching validity check operation, this does not necessarily mean that the instruction for triggering the output stack capping operation will stop executing (the timing of the response to an error identified in the stack pointer switching validity check operation can vary, and it may not be necessary for faults to be notified immediately, as will be further described below).
[0016] The page address specified in the effective stack cap value for output stack capping operation may be a virtual page address that points to a page in the virtual address space containing the virtual address selected based on the output stack pointer value.
[0017] The technique described above can be used in any use case where a stack data structure is used by processing circuits to maintain thread-specific data, in which case different stack data structures can be assigned to different software threads, such that it is desirable to switch the stack pointer from the output stack pointer to the input stack pointer to change which stack is active when switching threads. This technique may be particularly useful in use cases where the data on the stack is sensitive, or requires some kind of security measures to control the use of the data on the stack, and as a result there is a risk that switching to an arbitrary address in memory that does not represent the stack protected by those security measures when switching the stack pointer could lead to erroneous results that could damage the software code being executed.
[0018] However, one particular scenario in which this technique may be useful is when the stack pointer is a guarded control stack (GCS) pointer that controls access to a guarded control stack (GCS) data structure that protects the return address for returning from an exception or function call. Such a GCS data structure can be used as a defense against return-oriented programming (ROP) attacks. ROP attacks are a common form of attack that aims to cause an incorrect control flow by altering the return address used for function or exception returns (typically by altering the return address while it is stored in memory during a nested sequence of function calls or exceptions). The protected GCS data structure may be established in a region of memory that has at least one defense that restricts the ability to write data to the GCS data structure, providing some additional protection over the normal region of memory and reducing the likelihood that an attacker could modify the return state stored in the GCS data structure by an instruction that is not expected to write to the GCS data structure. Protected return state information from GCS data structures can be used to directly control exception / function returns, or it can be compared with exception / function return information obtained by software from other sources (e.g., a separate software-managed stack structure in memory) to check whether that exception / function return information can be used safely before triggering the corresponding exception / function return. However, while certain security measures may be available to prevent erroneous updates to GCS data structures, these measures can be easily circumvented if an attacker switches the stack pointer used to access the GCS data structure to an input stack pointer value pointing to a memory region controlled by the attacker. As a result, these measures may be rendered ineffective if the victim software subsequently attempts to access the GCS data structure and returns an erroneous return state.Also, some attacks may be based on switching the input stack pointer to the correct GCS data structure but to an incorrect position on that GCS data structure, such as a position that does not represent the current "top" of the stack. This can pose a risk that subsequent exception / function returns will behave incorrectly because the subsequent exception / function returns use the return state intended for a different exception / function return.
[0019] Therefore, the stack pointer switch validity check operation can be particularly useful in architectures that support the use of GCS data structures because it allows a sanity check of whether the input GCS data structure is safe to use without requiring each stack pointer switch to be trapped at a higher privilege level. Also, a more efficient encoding of stack cap values using page addresses instead of full addresses is useful because it frees up multiple stack record encodings for other purposes. Since the GCS data structure can be used to protect data from tampering by attackers, providing encoding space for additional types of stack records can be useful to enable other types of information (not just function / exception return state information) to be protected using the GCS data structure.
[0020] In order to protect the GCS data structure from tampering, several security measures can be supported in the instruction set architecture used by the processing circuit. The apparatus can have a memory management circuit for determining whether access to a target address is permitted based on memory attribute data associated with the target address, where the memory attribute data specifies whether a target memory address space region including the target address is a GCS region for storing the GCS data structure, and write access to the GCS region is restricted to a dedicated class of GCS access instructions. Thus, the GCS data structure can be allocated to a dedicated type of memory region (handled by the memory management circuit as a different type of memory from the normal memory used for general-purpose data or program code). By restricting the class of instructions that can write to such a GCS region of memory, the attack surface available for an attacker to utilize when attempting to modify the return state stored on the GCS data structure is reduced.
[0021] In response to determining that the target memory address space region is a GCS region, the memory management circuit can reject a non-GCS store operation to the target address triggered by a store instruction other than the dedicated class of GCS access instructions. By restricting the ability to write to the GCS region to store operations of a predetermined GCS access type, other more general store instructions cannot tamper with the contents of the GCS data structure, and greater security assurance is provided for the protected return state information stored in the GCS data structure. This reduces the attack target area available for an attacker to exploit when attempting to initiate a ROP attack.
[0022] Similarly, the memory management circuit may, in response to determining that the target memory address space region is not a GCS region, reject a GCS load / store operation to a target address triggered by one of the dedicated classes of GCS access instructions. Thus, access to a memory region not designated as a memory region for GCS data structures may be rejected if the access is triggered by an instruction of the GCS access type. This prevents the misuse of GCS access type instructions to access memory regions not intended to store GCS data structures and provides assurance that it is a GCS read to a memory region that could not be modified by a non-GCS access instruction, thus protecting against ROP attacks. Loading input data values for a stack pointer switching validity check operation may be considered a GCS load operation, failing if the address is identified by the memory attribute data as corresponding to a memory region type other than a GCS region type.
[0023] In some cases, memory management circuits may also refuse to fetch or branch to a target address when memory attribute data specifies that the target memory address space region is a GCS region. Therefore, data stored in a GCS region cannot be treated as an executable instruction (although it can be treated as an address pointer pointing to another location in memory that stores an executable instruction). Given this characteristic of GCS regions, it can be very useful to set a valid stack cap value (expected to be on the input stack in the region allocated as a GCS region type when a stack switching operation is performed) to specify the page address of the same page that contains the address of the location that stores the stack cap value itself. This reduces the risk of inaccurate control flow caused by misinterpreting the stack cap value as an exception return address or function return address when accessing GCS data structures in a GCS memory region, a risk that could occur if an attacker compromises control flow in victim code so that a function return or exception return is triggered when the stack cap value is at the top of the stack. Even if an attacker causes an incorrect access to the stack such that the stack cap value is returned as a protected return address for an exception return or function return, the fault is identified by the corresponding return operation (when attempting to fetch an instruction from the address represented by the stack cap value misinterpreted as a return address, either directly or later during the stack access or return operation) because the stack cap value points to its own page, which is expected to be a page allocated as a GCS area type.
[0024] The conditions for the input data value specifying the page address do not have to be the only conditions that the input data value must pass in order to satisfy the check in the stack pointer switching validity check operation. Other conditions may also apply.
[0025] For example, in some implementations, at least one stack cap value validity condition may also include the condition that the least significant portion of an input data value has a bit pattern that cannot be specified by the least significant portion of any valid instruction address. More specifically, at least one stack cap value validity condition may include the condition that the least significant portion has a specific bit pattern used to indicate a valid stack cap value, which cannot be specified by the least significant portion of any valid instruction address.
[0026] For example, this particular bit pattern can have at least one bit with a bit value of 1. For some processor architectures, instruction coding can have a certain number of bits, and there may be a requirement that any instruction is stored at an address aligned to an address boundary in multiples of the instruction size. For example, an instruction may have 32-bit coding and therefore be required to be stored at an address aligned to a 4-byte address boundary (for architectures with different instruction sizes, the address boundaries may have different granularity). An attempt to perform an instruction fetch or branch to an unaligned address may result in a fault being reported. Therefore, encoding the stack cap value such that its least significant bit has a non-zero bit pattern that cannot be specified by the least significant part of any valid instruction address (because if treated as an instruction address, that pattern would result in a value that is an unaligned instruction address) provides another means of detecting erroneous attempts to use the stack cap value as a return address to perform an exception return or function return, thus improving security.
[0027] Therefore, a “stack cap value” assigned to an inactive stack (which is expected to be verified when switching back to that stack) can be considered to “capp” (or “seal” the stack) in the sense that having the stack cap value at the top of the stack prevents the use of the stack to control the return operation until the cap is removed.
[0028] The input stack pointer value may be defined independently of the output stack pointer value, and as a result, switching from the output stack pointer value to the input stack pointer value can represent a switch to an entirely different stack structure, rather than simply an increment or decrement of the current stack pointer that occurs when pushing an entry onto the stack or popping an entry from the stack.
[0029] The processing circuit may perform a stack pointer switch validity check operation in response to a first stack pointer switch instruction that specifies an operand indicating an input stack pointer value. Therefore, the input stack pointer value can be defined as an operand optionally specified in the first stack pointer switch instruction (for example, by specifying the input stack pointer value in a general-purpose register specified by the first stack pointer switch instruction).
[0030] The device may have a stack pointer register for storing the stack pointer. The output stack pointer value for stack pointer switching may be the current value specified for the stack pointer register when the first stack pointer switching instruction is executed.
[0031] In response to the first stack pointer toggle instruction, if the stack pointer toggle validity check operation is successful (i.e., the input data value obtained based on the input stack pointer value satisfies at least one stack cap value validity condition and any other checks (which depend on the specific implementation) are satisfied), the processing circuit may update the stack pointer register from the output stack pointer value to the input stack pointer value.
[0032] In some cases, the first stack pointer toggle instruction may be the only mechanism available to software running in the lowest privileged execution state of the processing circuit (typically user-level software) to cause a stack pointer toggle. Software running in the lowest privileged execution state may not have direct write access to the stack pointer register (software may be able to write directly to the stack pointer register even when running in a more privileged execution state). This improves security by limiting the ability of user-level software to cause a stack pointer toggle. Since software must use the first stack pointer toggle instruction to cause a stack pointer toggle, this forces a stack pointer toggle validity check operation to be performed. For example, an attempt by software to execute a system register instruction requesting an update to the stack pointer register may be rejected if the current privilege level is lower than a certain threshold privilege level.
[0033] In some implementations, the first stack pointer toggle instruction may also trigger the output stack capping operation described above. Thus, in response to the first stack pointer toggle instruction, the current value specified for the stack pointer register at the time of execution of the first stack pointer toggle instruction is used as the output stack pointer value, an effective stack cap value is formed specifying the (virtual) page address corresponding to the output stack pointer value, and it is written to the address corresponding to the output stack pointer value.
[0034] However, in practice, performing both a stack pointer switching validity check and an output stack capping operation in the same instruction may require translating between two different target addresses: the load address of the input data value loaded based on the input stack pointer value, and the storage address of the valid stack cap value stored based on the output stack pointer value. Some circuit implementations may not be able to handle two different address translations in response to the same instruction, and therefore, instruction set architectures that require both the stack pointer switching validity check and the output stack capping operation to be performed in a single instruction (although this is possible) can present significant design challenges for microarchitecture circuit designers.
[0035] Therefore, to simplify circuit design implementation, it may be useful to define two separate architectural instructions for performing stack switching: a first stack pointer switching instruction that triggers a stack pointer switching validity check operation and, if the validity check operation is successful, updates the stack pointer register to switch the stack pointer to the input stack pointer value, and a second stack pointer switching instruction that performs an output stack capping operation.
[0036] However, in the two-instruction method, the output stack pointer value (which is replaced in the stack pointer register in response to the first stack pointer toggle instruction) must be "stored" between the processing of the first stack pointer toggle instruction and the processing of the second stack pointer toggle instruction. From an architectural standpoint, consuming an architectural register to hold the output stack pointer value may be undesirable as it can increase register pressure, and exposing the output stack pointer value to software that runs after the stack pointer toggle may also be undesirable, which can be a risk if the architectural register is allocated to store the output stack pointer value for use as an operand for the second stack pointer toggle instruction.
[0037] Therefore, the instruction set architecture can define that the first stack pointer toggle instruction architecturally (temporarily) writes the output stack pointer value to the input stack so that the output stack pointer value is held by being written to the memory address space. This does not exclude some microarchitecture implementations that can use microarchitecture mechanisms such as register renaming or store buffering to provide the second stack pointer toggle instruction with access to the output stack pointer value nominally overwritten in memory by the first stack pointer toggle instruction, which is faster than if the second stack pointer toggle instruction had to actually access memory (for example, buffering in the processing circuit hardware can be used, since it is often expected that the output stack pointer will be needed by the second instruction relatively soon after it is stored by the first instruction). Nevertheless, such microarchitecture circuit mechanisms are optional, and from an architectural (software visible) point of view, the instructions can be processed as if the first stack pointer toggle instruction wrote the output stack pointer value to memory and the second stack pointer toggle instruction read it from memory.
[0038] Therefore, in response to the first stack pointer switching instruction, the processing circuit may push a progress token value specifying the output stack pointer value to a location having an address selected based on the input stack pointer value. This temporarily makes the output stack pointer value accessible within the architecturally visible memory address space, and as a result, it becomes permissible to overwrite the output stack pointer value in the stack pointer register and switch the stack pointer to the input stack pointer value, even if the output stack is not yet capped.
[0039] With respect to a load operation for loading an input data value to be verified in a stack pointer switching validity check operation, and a store operation for pushing a token value in progress to a location having an address selected based on the input stack pointer value, the processing circuit may perform the load and store operations atomically. Thus, a mechanism is provided to prevent intervening access to the address selected based on the input stack pointer value between the load and store being performed, or, if such intervening access is possible, to detect it and correct such lack of atomicity (for example, by triggering a pipeline flush and re-executing the first stack pointer switching instruction). Any known atomic access mechanism used to enforce atomicity between load and store can be used.
[0040] In response to the second stack pointer toggle instruction, the processing circuit can verify whether a given data value obtained by the memory access circuit in response to a memory access request specifying an address determined based on the current stack pointer in the stack pointer register is a validly formed ongoing token value. In response to verification that the given data value is a validly formed ongoing token value, the processing circuit triggers a write of the valid stack cap value to a location having the address determined based on the given stack pointer value specified by the portion of the given data value, specifying a page address indicating a page in the address space containing the address determined based on the given stack pointer value, within a predetermined portion of the valid stack cap value. In some examples, the address determined based on the given stack pointer value may be an address offset from the given stack pointer value by an amount corresponding to the size of a single stack entry. If the second stack pointer toggle instruction is executed after the first stack pointer toggle instruction, it is expected that the given data value obtained (at the time of the second stack pointer toggle instruction) based on the current stack pointer should be an ongoing token value previously written to the input stack data structure by the first stack pointer toggle instruction. However, it will be understood that the hardware circuit logic of the processing circuit has no way of knowing whether the second stack pointer toggle instruction actually follows the first stack pointer toggle instruction, and the hardware circuit logic simply implements "black box" circuit logic that implements the function of the second stack pointer toggle instruction based on its defined operands, independently of other instructions that the software has chosen to execute before that instruction. Therefore, there is no circuit in hardware that forces the operands of the second stack pointer toggle instruction to correspond to operands previously used for the first stack pointer toggle instruction.
[0041] Therefore, the second stack pointer toggle instruction checks that a given data value obtained based on the current stack pointer in the stack pointer register corresponds to a validly formed ongoing token value. If it is valid, it uses the given stack pointer value provided by that ongoing token value (expected, but not guaranteed, to be the address of the output stack structure previously toggled by the previous first stack pointer toggle instruction) to access the corresponding stack structure and push a valid stack cap value into that structure. Here again, the valid stack cap value is formed such that, in a given portion, it specifies a page address that points to a page in the address space containing the address indicated by the given stack pointer value. This ensures that when the software later wants to toggle the corresponding stack back as the input stack for a stack pointer toggle operation, it will pass a subsequent check performed for the stack pointer toggle validity operation.
[0042] In response to a second stack pointer toggle instruction, when a given data value is verified to be a validly formed ongoing token value, the processing circuit is configured to update the current stack pointer in the stack pointer register to indicate the removal of the entry providing the given data value from the corresponding stack data structure. For example, the update to indicate the removal of an entry may be of the same type as the update to the current stack pointer performed when an entry is popped from the stack (e.g., either an increment or a decrement, depending on the direction in which the stack grows / collapses during push / pop). This update means that the ongoing token value will no longer be accessed during subsequent pop accesses to the stack. Since the update to the stack pointer means that it will not be accessed by subsequent accesses based on the stack pointer, it is not necessary to actually remove the ongoing token value from memory. The ongoing token value may be overwritten later if there is a subsequent push operation that pushes a new entry onto the stack anyway.
[0043] In response to a second stack pointer toggle instruction, the processing circuit can verify that a given data value is a validly formed ongoing token value if the least significant portion of the given data value has a bit pattern that cannot be specified by the least significant portion of any valid instruction address and cannot be specified by any value that satisfies at least one stack cap value validity condition. It may also be useful for the ongoing token value to have a least significant portion corresponding to an unaligned instruction address, so that any attempt to use the ongoing token value as a return address will result in the misalignment fault described above. It may also be desirable to have different encodings for the least significant portions of valid stack cap values and valid ongoing token values to prevent an attacker from circumventing the protection using incorrect control flow (for example, this allows for the detection of errors where only one of the first / second stack pointer toggle instructions is executed, rather than both being executed together).
[0044] In response to a second stack pointer switching instruction, the processing circuit may trigger an error handling response if it determines that a given data value is not a validly formed ongoing token value.
[0045] For both the error handling response performed when an input data value does not satisfy at least one stack cap value validity condition for a stack pointer toggle validity check operation, and the error handling response performed in response to a second stack pointer toggle instruction when a given data value is not a validly formed ongoing token value, the error handling response can be implemented in several ways. For example, the error handling response may include at least one of notifying a fault, setting an error reporting instruction, and setting the stack pointer to an invalid value. In some implementations, the error handling response can directly halt processing (e.g., notifying a fault or exception as soon as an error is detected). Other examples may use more indirect means of notifying a fault so that the fault itself does not occur until later. For example, by setting the stack pointer to an invalid value that cannot be a valid memory address, subsequent attempts to access memory based on an invalid stack pointer may trigger a fault. This may be easier to implement in hardware than directly triggering a fault based on the checks of the first / second stack pointer toggle instructions. For example, a reserved portion of the address space with upper address bits that have values other than all zeros or all ones may be reserved so that it cannot be specified as a valid address. Therefore, if an error handling response is required, the stack pointer can be set to an address within this reserved portion, causing subsequent memory access to fail and thus avoiding error handling. It will be understood that the specific error handling response performed may vary between different implementations of the general techniques described above. Also, in some cases, when a given data value is not a validly formed ongoing token value, the error handling response performed for a failed stack cap value validity check may differ from the error handling response performed for a second stack pointer toggling instruction.
[0046] The above-described technique may be implemented within a data processing device having hardware circuits provided for implementing the above-described memory access circuit and processing circuit.
[0047] However, the same technique may also be implemented in a computer program that runs on a host data processing unit and provides an instruction execution environment for the execution of target code. Such a computer program can control the host data processing unit to simulate an architectural environment provided on a hardware device that actually supports the target code according to a particular instruction set architecture, even if the host data processing unit itself does not support its architecture. The computer program may have memory access program logic and processing program logic that controls the host data processing unit to emulate the features described above, including support for stack pointer switching validity checks. The memory access program logic performs stack access based on the stack pointer. The processing program logic performs stack pointer switching validity checks, which include checking whether a given portion of the input data value loaded based on the input stack pointer value specifies a given page address (in the simulated address space, not the host address space of the host data processing unit) of a page containing an address derived from the input stack pointer value. Thus, if target code that requires a stack pointer switch from an output stack pointer value to an input stack pointer value is executed in an instruction execution environment provided by a simulation computer program running on the host data processing unit, the same functionality as described above can be achieved even if the host data processing unit itself does not hardware support the stack pointer switching validity checks.
[0048] Such simulation programs can be useful, for example, when program code written for a certain instruction set architecture is running on a host processor that supports a different instruction set architecture. Furthermore, running software in a simulation environment allows for testing of the software in parallel with ongoing development of hardware devices supporting the new architecture. Therefore, simulations can enable the start of software development for a new version of an instruction set architecture before dealing with hardware that supports the new architecture version. The simulation program may be stored in a storage medium, which may be a non-temporary storage medium.
[0049] Figure 1 schematically shows an example of a data processing unit 2. The data processing unit has a processing pipeline 4 which includes several pipeline stages. In this embodiment, the pipeline stages include a fetch stage 6 for fetching instructions from the instruction cache 8, a decode stage 10 for decode the fetched program instructions to generate microoperations (decoded instructions) to be processed by the remaining stages of the pipeline, an issue stage 12 for checking whether the operands required for a microoperation are available in the register file 14 and issuing a microoperation for execution when the operands required for a given microoperation are available, an execution stage 16 for executing a data processing operation corresponding to the microoperation by processing the operands read from the register file 14 to generate a result value, and a write-back stage 18 for writing the results of the processing back to the register file 14. This is merely one example of a possible pipeline architecture, and it will be understood that other systems may have additional stages or stages with different configurations. For example, an out-of-order processor may include a register rename stage for mapping architectural registers specified by program instructions or microoperations to physical register specifiers that identify physical registers in the register file 14. In some examples, a one-to-one relationship may exist between a program instruction decoded by the decoding stage 10 and the corresponding microoperation processed by the execution stage. Alternatively, there may be a one-to-many or many-to-one relationship between program instructions and microoperations; for example, a single program instruction may be split into two or more microoperations, or two or more program instructions may be merged so that they are processed as a single microoperation.
[0050] Execution stage 16 (example of processing circuit) includes several processing units for performing different classes of processing operations. For example, the execution unit may include a scalar arithmetic / logic unit (ALU) 20 for performing arithmetic or logical operations on scalar operands read from register 14, a floating-point unit 22 for performing operations on floating-point values, a branch unit 24 for evaluating the results of branch operations and adjusting the program counter representing the current execution point accordingly, and a load / store unit 26 for performing load / store operations to access data in memory systems 8, 30, 32, and 34. The load / store unit is an example of memory access circuitry. A memory management unit (MMU) 28 is provided, which is an example of memory management circuitry, for performing address translation between a virtual address specified by the load / store unit 26 based on the operand of a data access instruction and a physical address that identifies the storage location of the data in the memory system. The MMU has a translation lookaside buffer (TLB) 29 for caching address translation data from page tables stored in the memory system, where page table entries define address translation mappings and access permissions that govern, for example, whether a given process running on the pipeline can read, write, or execute instructions from a given memory region. The MMU 28 may have circuits for requesting memory access during a page table walk as the page table structure is traversed to locate the page table entry corresponding to the required address. A memory management unit is an example of memory management circuitry.
[0051] In this embodiment, the memory system includes a Level 1 data cache 30, a Level 1 instruction cache 8, a shared Level 2 cache 32, and main system memory 34. This is merely one example of a possible memory hierarchy, and it will be understood that other arrangements of caches can be provided. The specific types of processing units 20-26 shown in execution stage 16 are merely one embodiment, and other implementations may have different sets of processing units, or may include multiple instances of the same type of processing unit so that multiple microoperations of the same type can be processed in parallel. Figure 1 is merely a simplified representation of some components of a possible processor pipeline implementation, and it will be understood that the processor may include many other elements not shown for brevity. Figure 1 shows a single processor core with access to memory 34, but device 2 may have one or more further processor cores that share access to memory 34, with each core having its own caches 8, 30, and 32.
[0052] Figure 2 shows an example of calling a function (labeled fn1 for ease of reference) and returning from it. A function (also known as a procedure) is a set of instructions that can be called from another part of a program and, upon completion, returns control to the part of the program flow from which the function was called. Because the same function can be called from many different locations in a program, a function return address is stored when a function is called, and as a result, the function return can distinguish which address the program flow should return to.
[0053] For example, as shown in Figure 2, a linked branch instruction BLR may be executed at the point where a function is called (represented by address #add1), causing the function to branch the program flow to an instruction at the branch target address #add2, specified using the operands of the linked branch instruction. The linked branch instruction also causes the processing circuit to set the link register (a designated register used to track the function return address) to the address of the next instruction after the linked branch instruction (in this example, the function return address is #add1+4). After the branch has occurred, many instructions (e.g., LD, MUL, ADD, etc.) are executed within the function code, and when the function completes, a return branch instruction RET is executed, causing a branch to the instruction indicated by the return address stored in the link register.
[0054] If no other functions are called from within fn1, and no exception occurs before reaching the final return branch of fn1, the address of the link register should still be the same as the one set when fn1 was called.
[0055] However, the first function fn1, called by background code, often calls a further function (fn2) in a nested manner. In this case, the function call to fn2 overwrites the return address stored in the link register. Therefore, before calling that further function, the function code of the first function fn1 should include an instruction to save the return address from the link register to a data structure in memory (e.g., a stack structure operating in a last-in-first-out (LIFO) manner). After returning from fn2, the function code of fn1 should restore the return address to the link register before executing a return branch. The responsibility for saving and restoring function return states, such as the return address, usually rests with the software (there may not be an architecturally enforced hardware mechanism for saving the return address).
[0056] However, while the function return address is stored in memory, it can be vulnerable to an attacker modifying that data, for example, by using another thread running on a different processor core, or by interrupting the called function and executing other code that overwrites the return address stored in memory during that time. Alternatively, an attacker could execute several instructions aimed at modifying the address operand of an instruction that restores the return address from memory to a register, so that the data loaded from memory is not the same as the return address originally stored in memory before the nested function was called. If an attacker can cause the return branch to branch at a point in the program flow other than an instruction after the function call branch, the attacker may be able to cause the software to behave maliciously, potentially circumventing certain security protections or performing undesirable actions.
[0057] A function call is one example of an operation that generates return state information, which provides information about the state that the processing circuit will later restore. Another scenario in which return state information may be obtained is when an exception occurs, at which point a hardware-provided exception handling circuit or a software exception handler may obtain exception return state information, such as an exception return address indicating the address of the instruction to be executed after returning from exception handling, and / or stored processor state information indicating the mode or execution state that the processor should execute after returning from the exception. For example, stored processor state information may indicate at what exception level the exception occurred, as well as other information about the operating state of the processor at the time the exception occurred. Similar to function calls, exceptions can be nested, so the exception return state obtained for one exception may be stored in memory (either automatically in hardware or by a software exception handler) when another exception occurs, and may be vulnerable to tampering by an attacker while stored in memory. These types of attacks may be called return-oriented programming (ROP) attacks. It may be desirable to provide architectural countermeasures against such attacks.
[0058] Figure 3 illustrates a technique for protecting against ROP attacks using a protected data structure in memory called a "guarded control stack" (GCS)40. While the location of the GCS data structure in the memory address space may be selected by software, the hardware provides architectural features designed to protect the GCS data structure from tampering by a malicious attacker.
[0059] As shown in Figure 1, register 14 may contain a control register including one or more Guarded-Control-Stack-Pointer (GCSPR) registers 36 for storing a stack pointer that points to an address on a GCS data structure. In some examples, the GCS pointer registers may be a bank set of registers provided separately for at least two execution states (e.g., exception levels), allowing software operating in different execution states to reference different GCS structures in memory without requiring the shared stack pointer register to be reprogrammed after each execution state transition. In other examples, a single GCS pointer register may be used, and the software can update the stack pointer stored in the GCS pointer register during transitions between execution states.
[0060] As shown in Figure 3, the GCS data structure 40 is stored in a memory region designated as the GCS region of memory by a memory attribute that is directly or indirectly specified by an associated page table entry in a page table used by the memory management unit (MMU) 28 to control address translation and access permission checks. The GCS region attribute may be directly specified within the encoding of the corresponding page table entry in the memory region containing at least a portion of the GCS data structure, or it may be indirectly referenced within a register referenced by the page table entry.
[0061] When a memory region is identified as a GCS region, write access to that region is restricted to write requests triggered by the processing circuit 16 when executing a specific subset of GCS access instructions. Generic store instructions used by software for general store operations not intended to access GCS structures are not considered one of the restricted subsets of GCS access instructions. The MMU 28 may still allow GCS structures to be read using generic load instructions that cause read requests that are not GCS memory access requests. If a memory access request requests access to a GCS region, and the request is a write request, and the request is not a GCS memory access request triggered by one of the restricted subsets of GCS access instructions, the memory access request is rejected and a fault is reported. The subset of GCS access instructions may include at least GCS push instructions that cause return state information (such as a function return address from a link register, or an exception return address, or a saved processor state obtained when an exception occurs) to be pushed to a location on the GCS structure determined using the stack pointer indicated in the GCS pointer register 58. A GCS push instruction also advances the stack pointer by an amount dependent on the size of the stack frame pushed into the GCS (for example, by incrementing the stack pointer by the size of the stack frame if the GCS is managed as an ascending stack, or by decrementing the stack pointer by the size of the stack frame if the GCS is managed as a descending stack). A GCS access instruction may also include at least one form of a GCS pop instruction that pops protected return information from the GCS structure.In addition to returning the popped return information from the stack, the GCS pop instruction also adjusts the stack pointer in the opposite direction to the direction in which the stack pointer is adjusted for a GCS push instruction (for example, by decrementing the stack pointer by the size of the stack frame if the GCS is managed as an ascending stack, or by incrementing the stack pointer by the size of the stack frame if the GCS is managed as a descending stack). As described below, GCS access instructions may also include GCS stack pointer switching instructions GCSSS1 and GCSSS2, which allow special-purpose values to be written to the stack in the GCS memory area for the purpose of protecting the stack from improper switching of the stack pointer within GCSPR36.
[0062] GCS access instructions may not be able to access memory regions that are not designated as GCS region types by the page table attribute. Therefore, if an attempt is made to perform a GCS access (including GCS stack pointer toggle instructions GCSSS1 and GCSSS2) when the memory region targeted for access is not marked as a GCS region type, a fault may be reported. By prohibiting the use of GCS access instructions to access non-GCS regions, this prevents programmers from using GCS access instructions to reduce the attack surface available to attackers unless it is actually intended to be a GCS access. This also gives confidence that data accessed by a GCS pop instruction or verified by one of the GCS stack pointer toggle instructions GCSSS1 or GCSSS2 cannot be modified by a non-GCS instruction.
[0063] The GCS structure is separate from any data structure used by software to maintain return state information stored in memory and to handle nested function calls or exceptions. Therefore, the GCS structure is not intended to eliminate the need for the software itself to track the storage and restoration of return state information when function calls or exceptions are nested (software-triggered storage of return state may continue in the same way as on processors that do not support the GCS protection architecture means considered above). Instead, the GCS structure provides a protected area of memory protected from tampering by compromised program code, which can be used to provide information for verifying return state information intended to be used by software to return from handling function calls or exceptions.
[0064] In some implementations, the GCS pop instruction, which pops protective return state information from the GCS structure, also causes the processing circuit 16 to compare the popped return state with the current return state information stored in registers (e.g., the link register for function returns, or the exception return address register for exception returns, and / or the stored processor state register), and may notify a fault if there is a mismatch between the return state information popped from the GCS structure 40 and the return state information that the software intends to use for function / exception returns. Thus, the software can be protected from tampering by including instances of the GCS push and GCS pop instructions within the program code executed around function calls / returns or exception entries / returns.
[0065] In other implementations, a separate instruction may be defined to verify whether the intended return state information is valid, in addition to the instruction that pops the return state information from the GCS structure 40.
[0066] Alternatively, a GCS pop instruction can pop a protected return state directly from the GCS into one or more registers used to specify a return state for an exception or function return (or can be combined with an exception / function return instruction to pop a protected return state and use that state to control an exception / function return), in which case, in such an implementation, the GCS-protected return state is used directly to control the exception / function return, so it is not necessary to perform the step of verifying whether the intended return state information provided by the software is valid. For example, for GCS protection of a function return address, the function return address can be popped directly into a link register to replace any software-managed function return address that the software may have placed in the link register based on its own managed stack structure.
[0067] Furthermore, other types of GCS access instructions can also be supported. Some instructions that have other functions in modes where GCS use is disabled may cause the processing circuit 16 to perform additional functions (such as additional GCS mode-specific security checks) when executed when GCS mode is enabled (the control state in the control register can control whether GCS mode is enabled or not).
[0068] In general, by providing architectural support for defining GCS memory region types for use with GCS structure 40, and by restricting write access to GCS region types to a limited subset of GCS access instructions (which may not allow access to memory regions other than GCS region types), this reduces the attack surface available to an attacker attempting to tamper with protected return state information stored on GCS structure 40.
[0069] Figure 4 is a flowchart illustrating the access permission check for a GCS load / store operation. A GCS load / store operation is a load / store operation triggered by one of the classes of GCS access instructions (for example, GCS access instructions include GCS push and pop instructions and GCS stack pointer switching instructions GCSSS1 and GCSSS2). In step 110, the processing circuit 16 determines the target address for the GCS load / store operation based on the GCS pointer in register 36. In step 112, the memory management unit 28 looks up the target address in its TLB 29 to obtain the memory attributes for the target address of the GCS load / store operation. In step 114, the MMU 28 determines whether the target address corresponds to a GCS memory area, which is a dedicated type of memory area used to store GCS data structures. If the target address does not correspond to a GCS memory area type, the GCS load / store operation is denied in step 116. When a fault is reported, the processing being performed may be interrupted and the cause of the fault may be handled by an exception handler. By suppressing GCS access to areas not marked as GCS memory region type, this prevents GCS load / store instructions from being exploited to access non-GCS memory, and means that the protected return state returned by a GCS load operation can be trusted because it cannot be tampered with by a non-GCS instruction.
[0070] If, in step 114, the target address is determined to correspond to a GCS memory region, then in step 118, the MMU28 determines whether any other access permission checks have passed. These checks may include read / write permission information indicating whether read and write requests are permitted for a memory region, or other attributes such as attributes defining a subset of the execution state of processor 2 that makes the region accessible. If any of the other access permission checks fail, the GCS load / store operation is again denied in step 116 and a fault is reported. The fault type information set by the processor when a fault occurs may differ depending on whether the cause of the fault was GCS access to a non-GCS memory region or another type of access permission violation. If all other access permission checks pass, the GCS load / store operation is permitted in step 120.
[0071] Figure 5 shows a similar access permission check performed for non-GCS load / store operations (loads / stores triggered by instructions outside the GCS access instruction class). Steps 130, 132, and 134 are the same as steps 110, 112, and 114 in Figure 4. Also, compared to Figure 4, in step 134 of Figure 5, the response to the check whether the target address corresponds to a GCS memory area is the reverse of that for non-GCS load / store operations compared to GCS load / store operations: if the target address corresponds to a GCS memory area, the non-GCS store operation is denied, and if the target address does not correspond to a GCS memory area, the GCS load / store operation is denied.
[0072] Therefore, if in step 134 it is determined that the target address corresponds to a GCS memory region, and in step 135 it is determined that the current load / store operation is a non-GCS store operation, then in step 136 the non-GCS load / store operation is denied and a fault is reported. A non-GCS load operation may potentially be possible, even if it targets a GCS memory region, subject to the results of any other access permission checks performed in step 138. If any of the other access permission checks fail, then again the non-GCS load / store operation is denied in step 136. Otherwise, if the target address does not correspond to a GCS memory region (N in step 134), or if the non-GCS operation is a load operation (N in step 135), and any of the other access permission checks (not related to GCS access checks) in step 138 pass, then in step 140 the non-GCS load / store operation is permitted.
[0073] Figure 6 is a flowchart illustrating the authorization check for a fetch or branch operation. In step 150, the fetch stage 6 requests to fetch an instruction associated with the target address, or a branch to an instruction at the target address is detected (the branch may be detected based on the execution of a branch instruction by the branch unit 24 of the execution stage 16, or based on the prediction of a future branch made by the branch predictor associated with the fetch stage 6). In response to the instruction fetch or branch, in step 152, the MMU 28 looks up the target address in its TLB 29 to identify the memory attribute data corresponding to the target address (if there is a TLB miss, a page table walk to memory is performed) and determines whether the target address is in an area identified as a GCS area by the memory attribute data. If the target address is in a GCS area, in step 154, the instruction fetch or branch is rejected and a fault is reported. This prevents data stored on the GCS structure from being treated as an executable instruction that could risk unpredictable results.
[0074] If the target address is not in the GCS area, in principle, the instruction loaded from that address can be executed according to any other permission checks performed in step 156. For example, these checks may include a page table-based check of the execution permission data indicated in the memory attribute data for the target address. If these other permission checks pass, the instruction fetch or branch may be permitted in step 158. If the other permission checks fail, the fetch or branch is again denied in step 154 and a fault is reported.
[0075] Therefore, the GCS memory area is limited to providing data values (such as address pointers and other information), and it cannot provide executable instruction code, as any attempt to fetch an instruction from the GCS area or to branch to an instruction within the GCS area will trigger a fault.
[0076] The measures described above may be useful in protecting content on GCS data structures from tampering by attackers when handling function returns and exception returns within a specific process.
[0077] However, another possible risk to control flow may occur when the GCS pointer in register 36 is switched from an output stack pointer value associated with an output stack data structure to an input stack pointer value associated with an input stack data structure. Such a switch is common (and may be permitted) when switching between threads of execution using different GCS data structures, but it may be a means that an attacker might try to use to cause malicious processing by attempting to expose sensitive information accessible to a victim process that should not be accessible to the attacker. For example, if the input stack pointer value for a stack pointer switch is set to an address that does not correspond to the correct GCS data structure for the input thread, there is a risk of triggering improper control flow, especially if the address specified for the input stack pointer value happens to be an address in the GCS region of memory (e.g., an address pointing to a return state on a GCS structure associated with a different thread). Even if the input stack pointer value is an address in the correct GCS data structure for the input thread, the risk of error may still exist, as if the input stack pointer value is set to a position other than the current "top" of the stack, the valid return state of one exception / function return may be used as the return address of a different exception / function return, which may still result in inaccurate information.
[0078] Such errors in the input stack pointer value can occur accidentally due to a programming error or maliciously by an attacker who compromises the executed code to execute an instruction that, in turn, switches the value of the GCS pointer in register 36 to point to a wrong location, for example, a return address pre-filled by the attacker within a GCS data structure (within the GCS area, and therefore not caught by the check in Figure 4) designed to deceive the victim software process into branching into a wrong sequence of code.
[0079] One technique to mitigate such incorrect setting of the input stack pointer value might be to require each write to GCSPR36 to be trapped in a more privileged execution state so that a more privileged process, such as the operating system or hypervisor, can verify whether the new value of the stack pointer is safe before updating GCSPR36. However, this negatively impacts performance. Switching GCS pointers is very common when switching between application-level threads, and to ensure fast switching and therefore high performance, it may be desirable to allow such switching of GCS pointers to be done without invoking a more privileged process.
[0080] To mitigate the risks of the type of attack described above, it may also be undesirable to allow direct access to the GCS pointer register 36.
[0081] Therefore, several instructions can be provided to control the switching of the stack pointer value in the GCS pointer register 36, thereby enabling several sanity checks to detect improper setting of the input stack pointer value. These GCS pointer switching instructions are considered to be members of the GCS access class of instructions, and therefore, writes to the GCS area triggered by these instructions can pass the checks shown in Figures 4 and 5.
[0082] When switching between different threads, the software stack (tracked using a stack pointer separate from the GCS pointer) is switched by the software, and the current guarded control stack is also switched. To ensure that the software cannot switch to an arbitrary position on the input GCS, a stack cap value is added to the output GCS when switching from that GCS, and the cap value is verified when switching to that GCS as the input stack during a stack pointer switch.
[0083] The cap value is designed to be distinguishable from any procedure return value, meaning that when switching the stack, we can be confident that we are simply switching to the top of the input GCS. For example, the lower address bits of the cap value can be set to a non-zero bit pattern that cannot be specified by any valid instruction address, since instruction alignment requirements may require that all valid instruction addresses be aligned to address boundaries at the granularity of the instruction length (for example, in the case of 32-bit instruction coding, aligned address boundaries may be 4-byte intervals). This means that any valid procedure return value should have a 0 for its lower bits, and therefore the cap value is distinguishable by having at least one 1 for its lower bits.
[0084] The cap value also includes the address of the cap position to check when switching to GCS. This address provides the following: 1) Sanity check that you are returning to the intended GCS using the correct VA-PA mapping of the GCS by comparing the address of the cap with the value loaded from the cap. 2) Security checks when a cap is used (incorrectly) as part of a procedure return. If you try to branch to a value held in a cap, this is implicit because it is in the GCS area. * data * This is an address (and therefore the check shown in Figure 6 triggers a fault if there is an attempt to execute an instruction at that address), and when the processor attempts to execute from this location, it does not have permission to execute and takes an exception.
[0085] The address is still * data *Since it is a page (a GCS memory area set using memory attributes specified directly or indirectly by a page table entry defined at the page granularity of the memory address space), it can be seen that the security check in point 2 above is maintained if the address held in the cap is in the same memory page as the cap's location. This allows storing fewer bits of the address, as it guarantees that only bits [63:12] of the cap's location is in the same 4KB page as the cap's location. Therefore, an attempt to use the cap as a return address will still result in an allow fault.
[0086] Sanity check #1 is also partially preserved in that it ensures that you are switching to the same GCS as intended, albeit for a location within the same GCS (however, if you switch to a location that is not the top of the stack, it will return information other than a valid cap value, resulting in an invalid stack cap validity check and therefore an error handling response, so in either case it is still impossible to validly switch to a location within that GCS that was not the top of the stack when that GCS was previously switched out).
[0087] Therefore, the cap value only needs to specify the page address, and it is not necessary to specify the subpage address bits. When checking the validity of the cap value when switching to the input stack, the subpage address bits of the input stack pointer do not need to be checked to determine whether the cap value is valid.
[0088] This is useful because it allows the record format within GCS to have more reserved bits, enabling future extensions to the architecture. This is very useful because it is anticipated that GCS may be used to protect a wide range of other information besides function / exception return state information, and therefore it may be useful to have an encoding space for encoding other record types.
[0089] Figure 7 shows the steps performed when switching the stack pointer in GCSPR36 from an output stack pointer value to an input stack pointer value (where the input stack pointer value is independent of the output stack pointer value; that is, this is not simply an increment or decrement of the current stack pointer performed when pushing onto or popping from the stack, but an arbitrary switch of the stack pointer that specifies an address provided as an operand of the instruction that triggers the switch).
[0090] In step 200, the processing circuit 16 performs a stack pointer switching validity check operation. This involves issuing a memory access request to load an input data value from address X, which is determined based on the input stack pointer value. Often, address X can be the address indicated by the output stack pointer value itself. However, depending on how the position marking the "top" of the stack is represented for the stack pointer value in register 36, it is also possible to determine address X of the input data value by applying an offset to the address indicated by the input stack pointer value. The memory access request to load the input data value from address X is a GCS load access and therefore may fail if address X does not correspond to GCS memory.
[0091] If the software functions correctly, the input data value obtained from address X based on the input stack pointer value is expected to be the stack cap value that should have been previously placed in the input GCS structure when the GCS pointer switched from that GCS structure in a previous switch. However, since the processing circuit 16 does not (yet) know whether the input stack pointer value actually corresponds to a previously accessed GCS structure, the input data value may not correspond to a valid stack cap value.
[0092] Therefore, in step 200, the processing circuit 16 performs a stack pointer switching validity check operation to check whether the input data value satisfies at least one stack cap value validity condition. The at least one stack cap value validity condition includes at least that a given portion of the input data value corresponds to a given page address indicating a page in the address space containing address X, regardless of whether further portions of the input data value correspond to subpage address bits of address X. More specifically, it is required that a given portion of the input data value corresponds to a virtual page address corresponding to virtual address X, and as a result, this check can verify whether the mapping from virtual addresses to physical addresses used to access the stack based on the input stack pointer value is still the same as before the stack was accessed. By not considering subpage address bits of address X to verify the at least one stack cap value validity condition, this frees up a considerable amount of encoding space in the GCS stack record for other purposes, as will be explained in more detail below with respect to Figure 11. As shown in step 224 of Figure 8, which will be explained below, the at least one stack cap value validity condition may also impose other requirements on the encoding of the input data value.
[0093] In step 202, it is determined whether the input data value satisfies each of the at least one stack cap value validity conditions applied by the processing circuit 16. The at least one stack cap value validity condition that must be satisfied includes, at a minimum, that the input data value specifies a virtual page address for the location where the input data value is stored. One or more additional stack value validity conditions may also be applied (for example, the lower part of the input data value is a token bit pattern representing the stack cap value). If any of the stack cap value validity conditions are not satisfied, an error handling response is triggered in step 204. For example, this response may be to report a fault, set an error flag in the error reporting register, or set the stack pointer in GCSPR36 to an invalid address within the reserved address range that cannot be specified for any valid memory address (the MMU may trigger a fault if there is any attempt to perform a load / store operation or instruction fetch for an address within the reserved range).
[0094] If it is determined that the input data value satisfies each of the applicable stack cap value validity conditions, in step 206, the processing circuit 16 allows the stack pointer to be switched from the output stack pointer value to the input stack pointer value (thus the input stack pointer value is written to GCSPR36).
[0095] Furthermore, in step 208, the processing circuit 16 performs an output stack capping operation to push a valid stack cap value to the location having address Y selected based on the output stack pointer value. The valid stack cap value specifies a (virtual) page address that points to a page in the address space containing (virtual) address Y in a predetermined portion checked in step 200. This ensures that the output stack is sealed (to prevent a return from being triggered based on access to the top of the stack, since the stack cap value would cause a fault on an instruction fetch or a branch to that address), and that the corresponding stack pointer value has an appropriate cap value that will later allow a valid switch return to that stack when it is specified as the input stack pointer for a stack switch.
[0096] In some implementations, the output stack capping operation shown in Figure 7 may be performed in response to the same instruction that also triggers the stack pointer switching validity check operation.
[0097] However, Figures 8 and 9 show specific examples in which an output stack capping operation is performed in response to an instruction different from the instruction that triggers the stack pointer switch validity check operation. Separating these operations into separate instructions significantly simplifies the circuit implementation by avoiding the need for two different memory addresses to be translated by the MMU28 in the same instruction. Figure 8 shows the function of the first stack pointer switch instruction (GCSSS1) used in the GCSPR36 to perform the stack pointer switch validity check operation and perform the stack pointer switch. Figure 9 shows the function of the second stack pointer switch instruction (GCSSS2) used to perform the output stack capping operation.
[0098] As shown in step 220 of Figure 8, the operands of the first stack pointer toggle instruction are the output stack pointer value specified by GCSPR36 and the input stack pointer value specified by the general-purpose register Xn, where the register specifier of general-purpose register Xn is encoded within the instruction encoding of the first stack pointer toggle instruction. Therefore, the software can choose any general-purpose register to define the input stack pointer, and the previous instruction can set that input stack pointer in any software-specific way. Since GCSPR36 is an implicit operand of the operation, it does not need to be explicitly encoded in the encoding of the GCSSS1 instruction.
[0099] In response to the GCSSS1 instruction being decoded by the decode stage 10 and issued for execution by the issue stage 12 of pipeline 4, in step 222, the processing circuit 16 controls the memory access circuit (load / store unit 26) to issue a load memory access request requesting the loading of input data values from a position corresponding to an address determined based on the input stack pointer value (derived from register Xn). In one particular implementation, the address specified by the load memory access request is equal to the input stack pointer value, but in other examples, the load address can be derived by applying an offset to the input stack pointer value. Since this load memory access request is a GCS load operation because it was triggered by the GCSSS1 instruction, it undergoes the check shown in Figure 4. Assuming the load operation passes these checks, the input data value is returned, and in step 224, the processing circuit 16 checks whether (i) a given portion of the input data value corresponds to the page address portion of the virtual address used for loading in step 222, and (ii) the least significant portion of the input data value is a specific bit pattern that identifies a valid stack cap value that cannot be specified by the least significant portion of a valid instruction address. If either of these checks fails, the input data value is not a valid stack cap value, and in step 226, an error handling response is triggered (which may be one of the types of error handling responses described above for step 204 in Figure 7).
[0100] If the check in step 224 is passed (i.e., a given portion of the input data value corresponds to the page address portion of the virtual address used for loading in step 222, and the least significant portion of the input data value has a specific bit pattern that identifies a valid stack cap value), i.e., the input data value satisfies at least one stack cap value validity condition, then in step 228, the processing circuit 16 controls the memory access circuit 26 to issue a store memory access request to store the ongoing token value at a memory location having an address selected based on the input stack pointer. The ongoing token value has a least significant portion that specifies the output stack pointer value and has a least significant portion set to a different bit pattern that is different from the encoding of the least significant portion of a valid stack cap value and cannot be specified by the least significant portion of any valid instruction address. Since it is expected that it may be possible to simply overwrite the output stack pointer with the input stack pointer value in GCSPR36, it may not be expected that an instruction to switch the stack pointer would need to use the output stack pointer as an operand. However, by writing the output stack pointer to the input stack (after the input stack has been validated by performing the stack cap value validity check in step 224), this helps support implementations in which the stack pointer switching operation is split between two instructions, GCSSS1 and GCSSS2, because it allows the output stack pointer value to be preserved so that the second stack pointer switching instruction GCSSS2 is available, without the need for an architectural register to be consumed to hold the output stack pointer value after it has been overwritten in GCSPR36.
[0101] In step 230, if the check in step 224 is passed, GCSPR36 is updated to specify the input stack pointer value (and therefore the output stack pointer value is overwritten).
[0102] As shown in Figure 8, the load in step 222 and the store in step 228 are executed atomically, so the result seen by the software executing the GCSSS1 instruction and another thread accessing the same address determined based on the input stack pointer is consistent with the result that would occur if the load in step 222 and the store in step 228 were executed consecutively without any intervening writes to that address between the load in step 222 and the store in step 228. Several different techniques may exist that can be used to guarantee this atomicity. For example, a lock-based technique can be used to lock access to the relevant memory location, preventing other writes to that memory location from being permitted during the period between the load and the store. Alternatively, a conflicting write operation triggered by another thread (e.g., running on a different processor core) may still be permitted during the intervening period, but a mechanism may be provided to detect such conflicting write operations and, if such writes are detected, abort the processing performed by the stack pointer switching instruction (e.g., flush the pipeline and rewind to an earlier point in the execution within the thread containing the GCSSS1 instruction to allow the GCSSS1 instruction to be re-executed later). Atomic loading and storing helps improve security by reducing the possibility that a state checked by the GCSSS1 instruction may change before the check is complete, which could otherwise be a risk of errors.
[0103] Figure 9 shows the processing of the second stack pointer switching instruction (GCSSS2). As shown in step 250, the instruction's operand is the current value specified in GCSPR36. In the common use case where the GCSSS2 instruction follows a GCSSS1 instruction, it would be expected that the value in GCSPR36 should be the input stack pointer value specified based on the Xn operand of the GCSSS1 instruction. However, in practice, the processor hardware has no way of checking whether the GCSSS2 instruction actually follows a GCSSS1 instruction, and therefore the following pseudocode for GCSSS2 refers to the operand of the GCSSS2 instruction as the "input" stack pointer value, but more generally, it performs the operation on the current stack pointer stored in stack pointer register 36, regardless of whether this is actually the same value as the input stack pointer value of the preceding GCSSS1 instruction.
[0104] In response to the GCSSS2 instruction being decoded by the decode stage 10 and issued for execution by the issue stage 12 of pipeline 4, in step 252, the processing circuit 16 controls the memory access circuit 26 to issue a load memory access request requesting the loading of a given data value from a location corresponding to an address determined based on the current stack pointer obtained from GCSPR36. In one particular implementation, the address specified by the load memory access request is equal to the current stack pointer value from GCSPR36, but in other examples, the address of the load can be derived by applying an offset to the current stack pointer value. Since this load memory access request is a GCS load operation because it was triggered by the GCSSS2 instruction, it undergoes the checks shown in Figure 4. Assuming the load operation passes these checks, the given data value is returned, and in step 254, the processing circuit 16 checks whether the given data value is a validly formed ongoing token. For example, the processing circuit 16 determines that a given data value is a validly formed token in progress if the least significant bit portion of the given data value matches a specific bit pattern used to encode a token in progress. This bit pattern is different from the bit pattern in the least significant portion of a valid stack cap value and therefore cannot be specified by any value that satisfies at least one stack cap value validity condition. Also, this bit pattern cannot be specified by any valid instruction address (for example, because it is non-zero at lower bit positions with less significance than the bits representing the significance of the instruction alignment boundary). If the given data value is not a validly formed token in progress, an error handling response is triggered in step 256 (again, this can be one of the error handling response types described above).
[0105] If a given data value is a validly formed token in progress, in step 258, the processing circuit 16 controls the memory access circuit 26 to issue a store memory access request to write a valid stack cap value to a location having address Y determined based on a given stack pointer value specified in the portion of the given data value loaded in step 252. In some examples, address Y may be offset from a given stack pointer value by an amount corresponding to the size of one stack entry, reflecting that adding a valid stack cap value to the top of the stack means that the stack pointer of the corresponding stack is incremented / decremented from its previous value (represented by the given stack pointer value), as with any other stack push operation for pushing a new stack entry onto the stack. Thus, the store operation in step 258 is for address Y which is different from the address to which the given data value was loaded in step 252. If the GCSSS2 instruction follows the preceding GCSSS1 instruction, the store in step 258 is for the output stack structure based on the output stack pointer for the GCSSS1 instruction, while the load in step 252 is from the input stack structure. The effective stack cap value specifies the (virtual) page address of a page in the address space containing the virtual address Y, which is indicated by a given stack pointer value obtained from a given data value loaded in step 252, within a predetermined portion of the page address being checked in step 224 of Figure 8. This allows the stack cap value to be set on the output stack, and when the stack pointer is later switched to the output stack (which is currently acting as the input stack), the check performed in step 224 of Figure 8 for the GCSSS1 instruction to be passed on to the subsequent stack pointer switch.
[0106] Furthermore, in step 260 of Figure 9, the processing circuit updates the stack pointer in GCSPR36 in response to the GCSSS2 instruction to indicate the removal of the entry that provided the given data value from the stack. This update can be either an increment or decrement of the current stack pointer by an amount corresponding to the size of a single stack record. Whether an increment or decrement is applied depends on whether the stack is managed as a descending or ascending stack (both options are possible; in the case of a descending stack, the stack pointer is decremented on push and incremented on pop, and vice versa for an ascending stack).
[0107] The following is example pseudocode to represent the functions of the GCSSS1 and GCSSS2 instructions. Although this is shown as pseudocode, it should be understood that in a hardware processor, the corresponding functions would be implemented using hardware circuit logic gates.
[0108] [Table 1]
[0109] Of course, the valid stack cap value and the specific coding used for tokens in progress may differ from those shown in the pseudocode.
[0110] Figure 10 schematically illustrates an example of stack switching based on the operation described above. The top of Figure 10 shows the initial state where the output GCS pointer P1 in GCSPR36 currently points to the top of the output GCS, and the input GCS (associated with pointer P2) is previously capped by storing a valid stack cap value at the top of the stack.
[0111] As shown in the center of Figure 10, when the GCSSS1 instruction is executed with an operand indicating a pointer P2 to the input GCS, the page address portion P2 of the input stack pointer value matches a predetermined portion P2[63:12] of the value obtained from the position on the input GCS corresponding to the input stack pointer value, and the pointer switching validity check operation passes. Therefore, the input stack is marked with a progress token value indicating the output stack pointer P1[63:3], and GCSPR36 is updated to indicate the input stack pointer value P2.
[0112] As shown in the lower part of Figure 10, when the GCSSS2 instruction is executed, the ongoing token on the input GCS (accessed based on the current stack pointer value P2 in GCSPR36) is validated, and if the check passes, the output stack is capped by writing the effective stack cap value, which specifies the page address portion of the page containing the location where the effective stack cap value was written, to the location on the output stack addressed based on the output stack pointer P1[63:3] obtained from the ongoing cap token. Also, the current stack pointer in GCSPR36 is updated to represent the removal of the ongoing token from the input GCS (in this example, by adding 8, but other examples may use a decrement, or may have stack records of different sizes and therefore different increment / decrement sizes).
[0113] Figure 11 shows examples of different formats for GCS records that can be placed on the GCS stack. • Procedure (function) return address record 300 provides a 62-bit procedure return address. The lower two bits of 0b00 indicate that this is a procedure return record (since these bits are 0, the address is 4-byte aligned and therefore can be a valid instruction address for 32-bit instruction coding aligned to an address boundary). • Stack cap value record 302 provides a 52-bit page address with the value 0b000000000001 in the lower 12 bits. Since the lower bits are 0b01, this is an misaligned address when interpreted as an instruction address, and therefore triggers a misalignment fault. • Record 304 of the ongoing token provides a 61-bit stack pointer value (used to represent the output stack pointer during stack pointer switching as described above - this encoding requires that the output stack pointer be double-word aligned such that the 62nd bit of the stack pointer address is implicitly 0). The lower 3 bits of record 304 have the encoding 0b101, indicating that this is an ongoing token. Exception record 306 has the lower 5 bits set to 0b01001 and all the upper bits are 0. When exception record 306 is found on the stack, a defined number of subsequent records (all 64 bits are available to record exception state information) provide items of the exception return state, such as the exception return address and the stored processor state associated with the operation being returned.
[0114] This coding means that several reserved codings are left as spares for future expansions. • Encoding 308 has the lower 3 bits set to 0b001 (same as stack cap record 302 and exception record 306), but the next 9 bits are set to one of the following: 0b000000000 or 0b000000001. These encodings are at least 2 (by setting different “record type” indicators in bits [11:3]). 9 -2 = 510 additional record types can be encoded, each supporting the recording of other types of information in the remaining 52 bits of the record's bits [63:12]. This additional encoding space is freed as a result of the stack cap value record 302 specifying a page address instead of a full address. Encoding 310 having the lower two bits [1:0] set to 0b10 or 0b11, supporting a full 62-bit value specified in the remaining bits [63:2].
[0115] Figure 12 shows possible implementations of a simulator. While the above embodiments implement the present invention in terms of devices and methods for operating specific processing hardware that supports the technology, it is also possible to provide an instruction execution environment according to the embodiments described herein, which are implemented using a computer program. Such a computer program is often referred to as a simulator insofar as it provides a software-based implementation of a hardware architecture. Various simulator computer programs include emulators, virtual machines, models, and binary translators, including dynamic binary translators. Typically, a simulator implementation may run on a host processor 1330, optionally running a host operating system 1320 and supporting a simulator program 1310. In some configurations, there may be multiple layers of simulation between the hardware and the provided instruction execution environment, and / or multiple different instruction execution environments provided on the same host processor. Historically, powerful processors have been required to provide simulator implementations that run at reasonable speeds, but such techniques may be justified in certain circumstances, such as when it is desirable to run native code on a different processor for reasons of compatibility or reuse. For example, a simulator implementation may provide an instruction execution environment with additional functionality not supported by the host processor hardware, or it may provide an instruction execution environment typically associated with a different hardware architecture. An overview of the simulation is described in "Some Efficient Architecture Simulation Techniques," Robert Bedichek, 1990 Winter USENIX Conference, pp. 53-63.
[0116] While embodiments have been described so far with reference to specific hardware components or features, in simulated embodiments, equivalent functionality can be provided by suitable software components or features. For example, certain circuits may be implemented as computer program logic in simulated embodiments. Similarly, memory hardware such as registers or caches may be implemented as software data structures in simulated embodiments. In arrangements where one or more of the hardware elements referenced in the above embodiments reside on host hardware (e.g., host processor 1330), some simulated embodiments may, if preferred, utilize the host hardware.
[0117] The simulator program 1310 can be stored on a computer-readable storage medium (which may be a non-temporary medium), but it provides a program interface (instruction execution environment) to the target code 1300 (which may include an application, operating system, and hypervisor), which is the same as the interface of the hardware architecture modeled by the simulator program 1310. Thus, program instructions of the target code 1300, including the stack pointer switching instructions GCSSS1 and GCSSS2 described above, can be executed from within the instruction execution environment using the simulator program 1310, thereby enabling the host computer 1330, which does not actually possess the hardware functions of the device 2 described above, to emulate these functions. Similarly, various memory management check functions and memory access triggers, such as those described above for the MMU 28 and load / store unit 26, including support for GCS memory area types, can be emulated using the memory access program logic 1318 of the simulator program 1310.
[0118] Therefore, the simulator program 1310 may have processing program logic 1312 that simulates the state of the processing circuit 4 described above. For example, the processing program logic 1312 can simulate changes in the execution state in response to events that occur during the simulated execution of the target code 1300. Instruction decoding program logic 1314 (which can be considered part of the processing program logic) decodes the instructions of the target code 1300 and maps these instructions to the corresponding instruction set in the native instruction set of the host device 1330. Register emulation program logic 1316 maps register accesses requested by the target code to access corresponding data structures maintained on the host hardware of the host device 1330, such as by accessing registers of the host device 1330 or data in memory 1332 (for example, access to host locations representing simulated GCS pointer registers can be managed by the register emulation program logic 1316 when instructions such as GCS push / pop instructions or GCSSS1, GCSSS2 instructions that require access to GCS pointer registers are executed). The memory management program logic 1318 implements address translation, page table walk, and access control checks in a manner corresponding to the MMU 28 described in the hardware implementation embodiment above, but also has the additional function of mapping simulated physical addresses obtained by address translation based on the page table defined for target code 1300 to host virtual addresses used to access host memory 1332. These host virtual addresses can themselves be translated to host physical addresses using the standard address translation mechanism supported by the host (the translation of host virtual addresses to host physical addresses is outside the scope of control by the simulator program 1310).
[0119] In this application, the phrase “configured to” is used to mean that the elements of the device have a configuration that enables them to perform a defined operation. In this context, “configuration” means the arrangement or interconnection of hardware or software. For example, the device may have dedicated hardware to provide the defined operation, or a processor or other processing device may be programmed to perform the function. “Configured to” does not mean that any modifications must be made to the device elements to provide the defined operation.
[0120] In this application, the enumeration of features preceded by the phrase "at least one of" means that any one or more of those features can be provided individually or in combination. For example, "[A], [B] and [C]" includes any of the following options: A alone (without B or C), B alone (without A or C), C alone (without A or B), a combination of A and B (without C), a combination of A and C (without B), a combination of B and C (without A), or a combination of A, B and C.
[0121] While illustrative embodiments of the present invention are described in detail herein with reference to the accompanying drawings, it will be understood that the present invention is not limited to those exact embodiments, and that various changes and modifications can be made to the embodiments without departing from the scope of the present invention as defined by the appended claims.
Claims
1. It is a device, A memory access circuit that performs stack access to a stack data structure based on the stack pointer, A stack pointer switching validity check operation associated with switching the output stack pointer value of the stack pointer to the input stack pointer value, the stack pointer switching validity check operation includes verifying whether the input data value obtained by the memory access circuit in response to a memory access request specifying an address determined based on the input stack pointer value satisfies at least one stack cap value validity condition, which includes the condition that a predetermined portion of the input data value corresponds to a given page address indicating a page in the address space containing the address determined based on the input stack pointer value, and a processing circuit that performs the stack pointer switching validity check operation, The processing circuit is configured to determine whether the input data value satisfies the at least one stack cap value validity condition, regardless of whether any further portion of the input data value other than the predetermined portion corresponds to a subpage address bit of the address determined based on the input stack pointer value. The apparatus is configured such that the processing circuit triggers an error handling response in response to the determination that the input data value does not satisfy the at least one stack cap value validity condition.
2. The apparatus according to claim 1, wherein the given page address is a virtual page address indicating a page in a virtual address space that includes a virtual address determined based on the input stack pointer value.
3. The apparatus according to claim 1 or 2, wherein the processing circuit is configured to perform an output stack capping operation associated with switching the stack pointer from the output stack pointer value to the input stack pointer value in order to push the effective stack cap value to a location having an address selected based on the output stack pointer value, the effective stack cap value specifies a page address indicating a page in the address space containing the address selected based on the output stack pointer value in the predetermined portion of the effective stack cap value.
4. The apparatus according to claim 3, wherein the page address specified by the effective stack cap value is a virtual page address indicating a page in the virtual address space that includes a virtual address selected based on the output stack pointer value.
5. The apparatus according to any one of claims 1 to 4, wherein the stack pointer is a guarded control stack (GCS) pointer for controlling access to a guarded control stack (GCS) data structure for protecting the return address for returning from an exception or function call.
6. The apparatus according to claim 5, comprising a memory management circuit that determines whether access to the target address is permitted based on memory attribute data associated with the target address, wherein the memory attribute data specifies whether the target memory address space region containing the target address is a GCS region for storing the GCS data structure, and write access to the GCS region is restricted to a dedicated class of GCS access instructions.
7. The apparatus according to claim 6, wherein the memory management circuit is configured to reject an instruction fetch or branch to the target address when the memory attribute data specifies that the target memory address space area is the GCS area.
8. The apparatus according to claim 6 or 7, wherein the memory management circuit is configured to reject non-GCS store operations to the target address triggered by store instructions other than the dedicated class of the GCS access instruction, in response to determining that the target memory address space area is the GCS area.
9. The apparatus according to any one of claims 6 to 8, wherein the memory management circuit is configured to reject a GCS load / store operation to the target address triggered by one of the dedicated classes of the GCS access instruction in response to determining that the target memory address space is not the GCS area.
10. The apparatus according to any one of claims 1 to 9, wherein the least one stack cap value validity condition also includes the condition that the least significant portion of the input data value has a bit pattern that cannot be specified by the least significant portion of any valid instruction address.
11. The apparatus according to any one of claims 1 to 10, wherein the processing circuit is configured to perform the stack pointer switching validity check operation in response to a first stack pointer switching instruction that specifies an operand indicating the input stack pointer value.
12. The system includes a stack pointer register for storing the aforementioned stack pointer, where, The apparatus according to claim 11, wherein, in response to the first stack pointer switching instruction, when the stack pointer switching validity check operation is successful, the processing circuit is configured to update the stack pointer register from the output stack pointer value to the input stack pointer value.
13. The apparatus according to claim 12, wherein, in response to the first stack pointer switching instruction, the processing circuit is configured to push a progress token value specifying the output stack pointer value to a location having an address selected based on the input stack pointer value.
14. With respect to a load operation for loading the input data value to be verified in the stack pointer switching validity check operation, and a store operation for pushing the ongoing token value to the position having the address selected based on the input stack pointer value, the processing circuit is configured to perform the load operation and the store operation atomically, according to claim 13.
15. The processing circuit responds to the second stack pointer switching instruction, The memory access circuit verifies whether a given data value obtained in response to a memory access request specifying an address determined based on the current stack pointer in the stack pointer register is a validly formed ongoing token value. In response to verifying that the given data value is a validly formed ongoing token value, The apparatus according to claim 13 or 14, wherein the effective stack cap value, wherein the effective stack cap value specifies a page address indicating a page in an address space having an address determined based on a given stack pointer value, in a predetermined portion of the effective stack cap value, is configured to trigger writing the effective stack cap value to a location having an address determined based on a given stack pointer value specified by a portion of a given data value.
16. The apparatus according to claim 15, in response to the second stack pointer switching instruction when the given data value is verified to be the validly formed ongoing token value, the processing circuit is configured to update the current stack pointer in the stack pointer register to indicate the removal of the entry providing the given data value from the corresponding stack data structure.
17. The apparatus according to claim 15 or 16, wherein the processing circuit is configured to verify that the given data value is the validly formed ongoing token value when the least significant portion of the given data value has a bit pattern that cannot be specified by the least significant portion of any valid instruction address and cannot be specified by any value that satisfies the at least one stack cap value validity condition.
18. The apparatus according to any one of claims 15 to 17, wherein the processing circuit is configured to trigger an error handling response in response to determining that the given data value is not a validly formed ongoing token value.
19. The error handling response is: To notify of faults, Setting error reporting instructions, The apparatus according to any one of claims 1 to 18, comprising at least one of setting the stack pointer to an invalid value.
20. It is a method, A stack pointer switching validity check operation associated with switching the stack pointer from an output stack pointer value to an input stack pointer value, wherein the stack pointer switching validity check operation includes performing a stack pointer switching validity check operation that verifies whether an input data value obtained by a memory access circuit in response to a memory access request specifying an address determined based on the input stack pointer value satisfies at least one stack cap value validity condition, which includes the condition that a predetermined portion of the input data value corresponds to a given page address indicating a page in the address space containing the address determined based on the input stack pointer value, Whether the input data value satisfies the at least one stack cap value validity condition is determined independently of whether any further portion of the input data value other than the predetermined portion corresponds to the subpage address bits of the address determined based on the input stack pointer value. A method comprising triggering an error handling response in response to determining that the input data value does not satisfy the at least one stack cap value validity condition.
21. A computer program that includes instructions to control the host data processing device to provide an instruction execution environment for executing target code when executed by the host data processing device, wherein the computer program Memory access program logic that performs stack access to stack data structures based on the stack pointer, A stack pointer switching validity check operation associated with switching the output stack pointer value of the stack pointer to an input stack pointer value, the stack pointer switching validity check operation includes verifying whether the input data value obtained by the memory access program logic in response to a request specifying an address determined based on the input stack pointer value satisfies at least one stack cap value validity condition, which includes the condition that a predetermined portion of the input data value corresponds to a given page address indicating a page in the address space containing the address determined based on the input stack pointer value, and a processing program logic that performs the stack pointer switching validity check operation, The processing program logic is configured to determine whether the input data value satisfies the at least one stack cap value validity condition, regardless of whether any further portion of the input data value other than the predetermined portion corresponds to a subpage address bit of the address determined based on the input stack pointer value. A computer program wherein the processing program logic is configured to trigger an error handling response in response to determining that the input data value does not satisfy the at least one stack cap value validity condition.
22. A storage medium for storing the computer program described in claim 21.