Restoring a state with MMIO causes an exception

Open
#1,136 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
python

Research direction

Start in qiling/os/memory.py around restore(), especially the RAM and MMIO restoration loops at the linked lines. Run the sample that maps MMIO, saves state, and restores it, then verify that restoring the state no longer raises the Unicorn invalid-mapping exception and that the MMIO region is restored.

Written by the indexing model from the issue text.

Description

Describe the bug
Mapping an MMIO region, then saving the qiling state and then restoring the qiling state causes an exception. See the script below.

Sample Code

import qiling
from qiling.const import QL_ARCH

ql = qiling.Qiling(code=bytes(0x1000), archtype=QL_ARCH.ARM, ostype='linux')
ql.mem.map_mmio(addr=0, size=0x1000, read_cb=lambda *args: 0, write_cb=lambda *args: None)
qiling_state = ql.save()

# ...

ql.restore(qiling_state)

Actual behavior

$ python main.py 
Traceback (most recent call last):
  File "main.py", line 15, in <module>
    ql.restore(qiling_state)
  File "~/.local/lib/python3.8/site-packages/qiling/core.py", line 783, in restore
    self.mem.restore(saved_states["mem"])
  File "~/.local/lib/python3.8/site-packages/qiling/os/memory.py", line 275, in restore
    self.map_mmio(lbound, ubound - lbound, read_cb, write_cb, info=label)
  File "~/.local/lib/python3.8/site-packages/qiling/os/memory.py", line 547, in map_mmio
    self.ql.uc.mmio_map(addr, size, __mmio_read, read_cb, __mmio_write, write_cb)
  File "~/.local/lib/python3.8/site-packages/unicorn/unicorn.py", line 527, in mmio_map
    raise UcError(status)
unicorn.unicorn.UcError: Invalid memory mapping (UC_ERR_MAP)

Expected behavior
No exception.

Additional context
An exception occurs in unicorn because the MMIO memory region is mapped, while it is already mapped. I think the best way to handle this is to first unmap the existing memory region, and then map the MMIO region. I don't think simply ignoring the MMIO region if it overlaps with a region that is already mapped is possible, since the read/write handler might be different.

https://github.com/qilingframework/qiling/blob/f3e66ec290b8c7a0ee60bc2f2715ddc6e9389216/qiling/os/memory.py#L280-L299

Proposed patch

    def restore(self, mem_dict):
        """Restore saved memory content.
        """
        # clear existing memory map
        self.unmap_all()

        # restore RAM
        for lbound, ubound, perms, label, data in mem_dict['ram']:
            self.ql.log.debug(f'restoring memory range: {lbound:#08x} {ubound:#08x} {label}')

            size = ubound - lbound
            if self.is_available(lbound, size):
                self.ql.log.debug(f'mapping {lbound:#08x} {ubound:#08x}, mapsize = {size:#x}')
                self.map(lbound, size, perms, label)

            self.ql.log.debug(f'writing {len(data):#x} bytes at {lbound:#08x}')
            self.write(lbound, data)

        # restore MMIO
        for lbound, ubound, perms, label, read_cb, write_cb in mem_dict['mmio']:
            self.ql.log.debug(f"restoring mmio range: {lbound:#08x} {ubound:#08x} {label}")

            #TODO: Handle overlapped MMIO?
            self.map_mmio(lbound, ubound - lbound, read_cb, write_cb, info=label)
Dominant language
Python
Stars
6.1k
Forks
798
Avg merge
1d 1h
Merged PRs (30d)
9

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from qilingframework/qiling

All issues in qilingframework/qiling

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.