unicorn-engine / unicorn

Unicorn CPU emulator framework (ARM, AArch64, M68K, Mips, Sparc, PowerPC, RiscV, S390x, TriCore, X86)
http://www.unicorn-engine.org
GNU General Public License v2.0
7.58k stars 1.34k forks source link

Unicorn 2 regression: ARM mode transition from USR32 to SVC32 is ineffective #1500

Closed gerph closed 2 years ago

gerph commented 2 years ago

Unicorn 2 is failng to allow the transition from USR32 to SVC32 using direct register access. No emulated code is involved - the system state does not change. It is as if the unicorn environment is enforcing the emulated environment's restrictions on the CPSR.

Source environment

I built unicorn on the dev branch at sha 558fb9c155e739444636dfdc434a536cc1a7a79f. This is after the fix for https://github.com/unicorn-engine/unicorn/issues/1494 (which relates to corruption of banked registers on a mode change). This has been tested on OSX system on Intel hardware (10.14.6)

Failure mode

The failures appears to be that once you are in USR32, an unprivileged, you are unable programatically to enter a privileged mode. This is necessary for a number of reasons, not least of which is providing entry to SVC32 when a SWI call is made, or IRQ32 when an interrupt is being forced.

What are we testing?

We want to set up the state of the system, and observe that we can freely change moves.

Sequence of tests

  1. Set up SVC32 mode
    • CPSR = 0x40000093 (SVC32)
    • sp_svc = 0x12345678
    • Dump the registers (they look fine)
  2. Set up UND32 mode
    • CPSR = 0x4000009b (UND32)
    • SPSR = 0x40000093 (SVC32)
    • sp_und = 0xDEAD0000
    • Dump the registers (they look fine)
  3. Set up USR32 mode
    • CPSR = 0x40000090 (USR32)
    • sp_usr = 0x0010000
    • Dump the registers (they look fine)
  4. Reenter SVC32 mode
    • CPSR = 0x40000093 (SVC32)
    • Dump the registers (the mode has not changed - we're still in USR32 with USR32 registers)

What is the problem?

The emulation environment should be able to be manipulated in ways that would not be allowed for the emulated system. This allows the operating system to initialise its state and begin execution of code. At present it is unable to execute any system calls because once in USR32 we can never get out.

Test code

Test code which exhibits this problem:

#!/usr/bin/env python
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>

import sys
from unicorn import *
from unicorn.arm_const import *

reg_map = [
        UC_ARM_REG_R0,
        UC_ARM_REG_R1,
        UC_ARM_REG_R2,
        UC_ARM_REG_R3,
        UC_ARM_REG_R4,
        UC_ARM_REG_R5,
        UC_ARM_REG_R6,
        UC_ARM_REG_R7,
        UC_ARM_REG_R8,
        UC_ARM_REG_R9,
        UC_ARM_REG_R10,
        UC_ARM_REG_R11,
        UC_ARM_REG_R12,
        UC_ARM_REG_SP,
        UC_ARM_REG_LR,
        UC_ARM_REG_PC,
    ]
arm_names = [
        'r0', 'r1', 'r2', 'r3',
        'r4', 'r5', 'r6', 'r7',
        'r8', 'r9', 'r10', 'r11',
        'r12', 'sp', 'lr', 'pc'
    ]

def dump_registers(uc):
    print("Registers: ")
    for rn in range(0, 16):
        value = uc.reg_read(reg_map[rn])
        sys.stdout.write("  %3s : 0x%08x" % (arm_names[rn], value))
        if rn % 4 == 3:
            sys.stdout.write("\n")
    print("  CPSR = 0x{:08x}".format(uc.reg_read(UC_ARM_REG_CPSR)))
    print("  SPSR = 0x{:08x}".format(uc.reg_read(UC_ARM_REG_SPSR)))

# Test ARM
def test_arm():
    print("Testing under Unicorn : {!r}".format(uc_version()))
    print("Header version: {!r}".format((UC_VERSION_MAJOR, UC_VERSION_MINOR, UC_VERSION_EXTRA)))

    print("Changing ARM modes")
    try:
        # Initialize emulator in ARM mode
        mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)

        # initialize machine registers in different modes
        mu.reg_write(UC_ARM_REG_CPSR, 0x40000093)   # Current mode = SVC32 mode
        mu.reg_write(UC_ARM_REG_R13, 0x12345678)    # SVC stack value
        print("--- Should be in SVC32, with R13 = 0x12345678")
        dump_registers(mu)

        mu.reg_write(UC_ARM_REG_CPSR, 0x4000009b)   # Current mode = UND32 mode
        mu.reg_write(UC_ARM_REG_SPSR, 0x40000093)   # Saved mode = SVC32 mode
        mu.reg_write(UC_ARM_REG_R13, 0xDEAD0000)    # UND stack value
        print("--- Should be in UND32, with R13 = 0xDEAD0000")
        dump_registers(mu)

        mu.reg_write(UC_ARM_REG_CPSR, 0x40000090)   # Current mode = USR32 mode
        mu.reg_write(UC_ARM_REG_R13, 0x0010000)     # USR stack value
        print("--- Should be in UND32, with R13 = 0x00010000")
        dump_registers(mu)

        mu.reg_write(UC_ARM_REG_CPSR, 0x40000093)   # Current mode = SVC32 mode
        print("--- Should be in SVC32, with R13 = 0x12345678")
        dump_registers(mu)

    except UcError as e:
        print("ERROR: %s" % e)

if __name__ == '__main__':
    test_arm()

Failing output (Unicorn 2)

This produces the following output on Unicorn 2 (failing output):

Testing under Unicorn : (2, 0, 262656L)
Header version: (2, 0, 0)
Changing ARM modes
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x12345678   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000093
  SPSR = 0x00000000
--- Should be in UND32, with R13 = 0xDEAD0000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0xdead0000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x4000009b
  SPSR = 0x40000093
--- Should be in UND32, with R13 = 0x00010000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x00010000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000090
  SPSR = 0x00000000
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x00010000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000090
  SPSR = 0x00000000

The final register dump should have sp = 0x12345678, and CPSR = 0x40000093

Successful output (Unicorn 1)

Testing under Unicorn : (1, 0, 256L)
Header version: (1, 0, 2)
Changing ARM modes
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x12345678   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000093
  SPSR = 0x00000000
--- Should be in UND32, with R13 = 0xDEAD0000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0xdead0000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x4000009b
  SPSR = 0x40000093
--- Should be in UND32, with R13 = 0x00010000
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x00010000   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000090
  SPSR = 0x00000000
--- Should be in SVC32, with R13 = 0x12345678
Registers: 
   r0 : 0x00000000   r1 : 0x00000000   r2 : 0x00000000   r3 : 0x00000000
   r4 : 0x00000000   r5 : 0x00000000   r6 : 0x00000000   r7 : 0x00000000
   r8 : 0x00000000   r9 : 0x00000000  r10 : 0x00000000  r11 : 0x00000000
  r12 : 0x00000000   sp : 0x12345678   lr : 0x00000000   pc : 0x00000000
  CPSR = 0x40000093
  SPSR = 0x00000000
wtdcode commented 2 years ago

Thanks for detailed report and I would have a look ASAP.

wtdcode commented 2 years ago

Fixed in 4f73d75ea8d86600f3bf2bb9428ae1df86f26218