linux-user: add plugin API to filter syscalls

This commit adds a syscall filter API to the TCG plugin API set.
Plugins can register a filter callback to QEMU to decide whether
to intercept a syscall, process it and bypass the QEMU syscall
handler.

Signed-off-by: Ziyang Zhang <functioner@sjtu.edu.cn>
Co-authored-by: Mingyuan Xia <xiamy@ultrarisc.com>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
[Pierrick - move send_through_syscall_filters to linux-user/syscall.c]
Link: https://lore.kernel.org/qemu-devel/20251214144620.179282-2-functioner@sjtu.edu.cn
Signed-off-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
This commit is contained in:
Ziyang Zhang
2025-12-14 22:46:19 +08:00
committed by Pierrick Bouvier
parent d37ce14f98
commit 5ed628d1d3
6 changed files with 123 additions and 11 deletions

View File

@@ -23,6 +23,7 @@ enum qemu_plugin_event {
QEMU_PLUGIN_EV_VCPU_INTERRUPT,
QEMU_PLUGIN_EV_VCPU_EXCEPTION,
QEMU_PLUGIN_EV_VCPU_HOSTCALL,
QEMU_PLUGIN_EV_VCPU_SYSCALL_FILTER,
QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
};

View File

@@ -55,15 +55,16 @@ void qemu_plugin_opt_parse(const char *optstr, QemuPluginList *head);
int qemu_plugin_load_list(QemuPluginList *head, Error **errp);
union qemu_plugin_cb_sig {
qemu_plugin_simple_cb_t simple;
qemu_plugin_udata_cb_t udata;
qemu_plugin_vcpu_simple_cb_t vcpu_simple;
qemu_plugin_vcpu_udata_cb_t vcpu_udata;
qemu_plugin_vcpu_discon_cb_t vcpu_discon;
qemu_plugin_vcpu_tb_trans_cb_t vcpu_tb_trans;
qemu_plugin_vcpu_mem_cb_t vcpu_mem;
qemu_plugin_vcpu_syscall_cb_t vcpu_syscall;
qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret;
qemu_plugin_simple_cb_t simple;
qemu_plugin_udata_cb_t udata;
qemu_plugin_vcpu_simple_cb_t vcpu_simple;
qemu_plugin_vcpu_udata_cb_t vcpu_udata;
qemu_plugin_vcpu_discon_cb_t vcpu_discon;
qemu_plugin_vcpu_tb_trans_cb_t vcpu_tb_trans;
qemu_plugin_vcpu_mem_cb_t vcpu_mem;
qemu_plugin_vcpu_syscall_cb_t vcpu_syscall;
qemu_plugin_vcpu_syscall_ret_cb_t vcpu_syscall_ret;
qemu_plugin_vcpu_syscall_filter_cb_t vcpu_syscall_filter;
void *generic;
};
@@ -169,6 +170,11 @@ qemu_plugin_vcpu_syscall(CPUState *cpu, int64_t num, uint64_t a1,
uint64_t a2, uint64_t a3, uint64_t a4, uint64_t a5,
uint64_t a6, uint64_t a7, uint64_t a8);
void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret);
bool
qemu_plugin_vcpu_syscall_filter(CPUState *cpu, int64_t num, uint64_t a1,
uint64_t a2, uint64_t a3, uint64_t a4,
uint64_t a5, uint64_t a6, uint64_t a7,
uint64_t a8, uint64_t *sysret);
void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
uint64_t value_low,
@@ -280,6 +286,15 @@ static inline
void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
{ }
static inline bool
qemu_plugin_vcpu_syscall_filter(CPUState *cpu, int64_t num, uint64_t a1,
uint64_t a2, uint64_t a3, uint64_t a4,
uint64_t a5, uint64_t a6, uint64_t a7,
uint64_t a8, uint64_t *sysret)
{
return false;
}
static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
uint64_t value_low,
uint64_t value_high,

View File

@@ -798,6 +798,33 @@ typedef void
uint64_t a3, uint64_t a4, uint64_t a5,
uint64_t a6, uint64_t a7, uint64_t a8);
/**
* typedef qemu_plugin_vcpu_syscall_filter_cb_t - vCPU syscall filter callback
* function type
* @id: plugin id
* @vcpu_index: the executing vCPU
* @num: the syscall number
* @a1: the 1st syscall argument
* @a2: the 2nd syscall argument
* @a3: the 3rd syscall argument
* @a4: the 4th syscall argument
* @a5: the 5th syscall argument
* @a6: the 6th syscall argument
* @a7: the 7th syscall argument
* @a8: the 8th syscall argument
* @sysret: reference of the syscall return value, must set this if filtered
*
* Returns true if you want to filter this syscall (i.e. stop it being
* handled further), otherwise returns false.
*/
typedef bool
(*qemu_plugin_vcpu_syscall_filter_cb_t)(qemu_plugin_id_t id,
unsigned int vcpu_index,
int64_t num, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5,
uint64_t a6, uint64_t a7, uint64_t a8,
uint64_t *sysret);
QEMU_PLUGIN_API
void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_syscall_cb_t cb);
@@ -811,6 +838,11 @@ void
qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_syscall_ret_cb_t cb);
QEMU_PLUGIN_API
void
qemu_plugin_register_vcpu_syscall_filter_cb(qemu_plugin_id_t id,
qemu_plugin_vcpu_syscall_filter_cb_t cb);
/**
* qemu_plugin_insn_disas() - return disassembly string for instruction