Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ ARG LTRACE_PROTOTYPES_HASH="9db3bdee7cf3e11c87d8cc7673d4d25b"
ARG MUSL_VERSION="1.2.5"
ARG VHOST_DEVICE_VERSION="vhost-device-vsock-v0.2.0"
ARG FW2TAR_TAG="v2.0.6"
ARG QEMU_VERSION="0.0.6"
ARG QEMU_VERSION="0.0.8"
ARG RIPGREP_VERSION="14.1.1"
ARG APT_MIRROR="ubuntu"

Expand Down
8 changes: 8 additions & 0 deletions pyplugins/apis/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ def generic_portalcall(*raw_args):
else:
raise ValueError(f"Unknown argument type {arg}")

# Portalcalls arrive via a syscall hypercall on the vCPU thread,
# so the current CPU is valid here. Subscribers receive the same
# (cpu, *args) signature as on the hypercall delivery path.
cpu = self.panda.get_cpu()
if cpu == self.panda.ffi.NULL:
cpu = None
args[0] = cpu

result = 0
for cb in plugins.plugin_cbs[self][self.callbacks[magic]]:
if not hasattr(cb, '__self__') and hasattr(cb, '__qualname__') and '.' in cb.__qualname__:
Expand Down
10 changes: 9 additions & 1 deletion pyplugins/apis/hypercall.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,15 @@ def dispatch(self, cpu, nr: int, ret_ptr) -> int:
if isinstance(result, int):
self.panda._set_current_retval(result)
except Exception as exc:
self.logger.exception("Error in hypercall handler for %#x: %s", nr, exc)
# Fail fast (PyPANDA parity): record the error and stop the
# emulation rather than letting the guest continue with a
# half-serviced hypercall.
self.logger.exception("Fatal error in hypercall handler for %#x: %s", nr, exc)
record = getattr(self.panda, "_record_callback_exception", None)
if record is None:
raise
record(exc)
break

if ret_ptr[0] == 0:
ret_ptr[0] = self.panda._current_retval
Expand Down
15 changes: 13 additions & 2 deletions pyplugins/apis/portalcall.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ def my_portalcall_handler(arg1, arg2):
PORTAL_MAGIC_64 = 0xffffffffc1d1e1f1
PORTAL_MAGIC_MASK = 0xffffffff

# Sentinel distinguishing "no handler registered" from a handler returning
# None: with no handler we must let the guest's real syscall execute (and
# fail loudly) instead of faking a successful return.
_MISSING_HANDLER = object()


class PortalCall(Plugin):
"""
Expand Down Expand Up @@ -69,6 +74,8 @@ def _portalcall_syscall_handler(self, regs, proto, syscall, magic, user_magic, a
if not self._is_portal_magic(magic):
return
result = yield from self._dispatch_portalcall(user_magic, argc, args)
if result is _MISSING_HANDLER:
return
syscall.skip_syscall = True
if isinstance(result, int):
syscall.retval = result
Expand All @@ -83,10 +90,14 @@ def _dispatch_portalcall(self, user_magic, argc, args):
handler = self._portalcall_registry.get(user_magic)
if handler is None:
if user_magic not in self._seen_missing_magics:
self.logger.error(
f"No handler registered for user_magic {user_magic:#x}; "
"letting the guest syscall run unhandled")
self._seen_missing_magics.add(user_magic)
else:
self.logger.debug(
f"No handler registered for user_magic {user_magic:#x}")
self._seen_missing_magics.add(user_magic)
return
return _MISSING_HANDLER
fn_to_call = resolve_bound_method_from_class(handler)
if handler != fn_to_call:
self._portalcall_registry[user_magic] = fn_to_call
Expand Down
9 changes: 8 additions & 1 deletion pyplugins/apis/syscalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,14 @@ def _syscall_event(self, cpu: int, is_enter: Optional[bool] = None) -> Any:
new = bytes(sce)
if original != new:
if getattr(self.panda, "direct_syscall_event_writeback", False):
plugins.mem.write_bytes_panda(cpu, arg, new)
try:
plugins.mem.write_bytes_panda(
cpu, arg & plugins.mem.addr_mask, new)
except ValueError:
# Direct write failed (e.g. page not resident); fall
# back to the guest-mediated portal write so the
# syscall modification is not silently dropped.
yield from plugins.mem.write_bytes(arg, new)
else:
yield from plugins.mem.write_bytes(arg, new)

Expand Down
Loading
Loading