Source code for pyintrovirt.domain

"""Classes for dealing with a domain/VM being introspected."""

from contextlib import ContextDecorator
from typing import NamedTuple, Optional, Union

import introvirt  # pylint: disable=import-error


[docs] class DomainInformation(NamedTuple): """Domain information.""" domain_name: str domain_id: int def __str__(self): return f"DomainInformation(domain_name={self.domain_name}, domain_id={self.domain_id})"
[docs] class Domain(ContextDecorator): """An introspection target (VM/domain) that we are attached to for introspecting.""" def __init__(self, domain_id: Union[int, str], hypervisor: introvirt.Hypervisor): """ Initialize an target domain to be introspected. Args: domain_id: The domain to attach to. Can be an integer domain ID or a string domain name. hypervisor: The hypervisor instance with the target domain to attach to. """ domain = hypervisor.attach_domain(domain_id) if not domain.detect_guest(): raise RuntimeError("Failed to detect guest OS") self._domain: Optional[introvirt.Domain] = domain self._guest: introvirt.Guest = domain.guest() self._os: introvirt.OS = introvirt.OS(self._guest.os()) def _attached(self) -> introvirt.Domain: if self._domain is None: raise RuntimeError("Domain is detached") return self._domain def __enter__(self): return self def __exit__(self, _exc_type, _exc_value, _traceback): self.detach() def __del__(self): self.detach() @property def os(self) -> introvirt.OS: """Access the guest OS type enum.""" return self._os def _windows_guest(self) -> introvirt.WindowsGuest: win_guest = introvirt.WindowsGuest_from_guest(self._guest) if win_guest is None: raise RuntimeError("Guest is not a Windows guest") return win_guest @property def syscall_categories(self) -> tuple[str, ...]: """Get a list of system call categories.""" if self.os == introvirt.OS.Windows: return self._windows_guest().syscall_categories() # ty: ignore[too-many-positional-arguments] raise NotImplementedError("Only implemented for Windows guests right now.")
[docs] def detach(self) -> None: """Detach from the domain. Safe to call multiple times.""" if self._domain is None: return self._domain.interrupt() self._domain = None
[docs] def poll(self, event_handler: introvirt.EventCallback): """Start the poller for events. No events will be recieved until this is started.""" self._attached().poll(event_handler)
[docs] def clear_system_call_filter(self): """Clear the system call filter if set.""" self._attached().system_call_filter().clear()
[docs] def clear_task_filter(self): """Clear the process filter if set.""" self._attached().task_filter().clear()
[docs] def default_system_call_filter(self): """Set the system call filter to the default set of supported system calls for the OS.""" if self.os == introvirt.OS.Windows: self._windows_guest().default_syscall_filter(self._attached().system_call_filter()) else: raise NotImplementedError("Only implemented for Windows guests right now.")
[docs] def filter_system_call(self, syscall: introvirt.SystemCallIndex, enabled: bool): """Toggle filtering of a specific system call.""" if self.os == introvirt.OS.Windows: self._windows_guest().set_system_call_filter(self._attached().system_call_filter(), syscall.value, enabled) else: raise NotImplementedError("Only implemented for Windows guests right now.")
[docs] def filter_system_call_category(self, category: str): """Filter by a system call category.""" if self.os == introvirt.OS.Windows: self._windows_guest().enable_category(category, self._attached().system_call_filter()) else: raise NotImplementedError("Only implemented for Windows guests right now.")
[docs] def filter_system_calls(self, enabled: bool): """Toggle system call filtering on/off. Required for the filter to take effect.""" self._attached().system_call_filter().enabled(enabled)
[docs] def filter_task_name(self, name: str): """Filter by task name. Name is a case-insensitive process name prefix.""" self._attached().task_filter().add_name(name)
[docs] def filter_task_pid(self, pid: int): """Filter by task PID.""" self._attached().task_filter().add_pid(pid)
[docs] def filter_task_tid(self, tid: int): """Filter by task TID.""" self._attached().task_filter().add_tid(tid)
[docs] def unfilter_task_name(self, name: str): """Remove a name from the task filter.""" self._attached().task_filter().remove_name(name)
[docs] def unfilter_task_pid(self, pid: int): """Remove a PID from the task filter.""" self._attached().task_filter().remove_pid(pid)
[docs] def unfilter_task_tid(self, tid: int): """Remove a TID from the task filter.""" self._attached().task_filter().remove_tid(tid)
[docs] def intercept_system_calls(self, enabled: bool): """Toggle system call interception on/off. Required to received system call events at all.""" self._attached().intercept_system_calls(enabled)
[docs] def intercept_cr_writes(self, cr: int, enabled: bool): """Intercept CR writes.""" self._attached().intercept_cr_writes(cr, enabled)