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 */
};
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;
};
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,
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,
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);
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
gdb_syscall_return(cpu, num);
}
+static bool send_through_syscall_filters(CPUState *cpu, int num,
+ abi_long arg1, abi_long arg2,
+ abi_long arg3, abi_long arg4,
+ abi_long arg5, abi_long arg6,
+ abi_long arg7, abi_long arg8,
+ abi_long *sysret)
+{
+ uint64_t sysret64 = 0;
+ bool filtered = qemu_plugin_vcpu_syscall_filter(cpu, num, arg1, arg2,
+ arg3, arg4, arg5, arg6,
+ arg7, arg8, &sysret64);
+ if (filtered) {
+ *sysret = sysret64;
+ }
+ return filtered;
+}
+
abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
abi_long arg2, abi_long arg3, abi_long arg4,
abi_long arg5, abi_long arg6, abi_long arg7,
print_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6);
}
- ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
- arg5, arg6, arg7, arg8);
+ if (!send_through_syscall_filters(cpu, num, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, &ret)) {
+ ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8);
+ }
if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
print_syscall_ret(cpu_env, num, ret, arg1, arg2,
plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_RET, cb);
}
+void
+qemu_plugin_register_vcpu_syscall_filter_cb(qemu_plugin_id_t id,
+ qemu_plugin_vcpu_syscall_filter_cb_t cb)
+{
+ plugin_register_cb(id, QEMU_PLUGIN_EV_VCPU_SYSCALL_FILTER, cb);
+}
+
/*
* Plugin Queries
*
}
}
+/*
+ * Disable CFI checks.
+ * The callback function has been loaded from an external library so we do not
+ * have type information
+ */
+QEMU_DISABLE_CFI
+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)
+{
+ struct qemu_plugin_cb *cb, *next;
+ enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL_FILTER;
+ bool filtered = false;
+
+ if (!test_bit(ev, cpu->plugin_state->event_mask)) {
+ return false;
+ }
+
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);
+
+ QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
+ qemu_plugin_vcpu_syscall_filter_cb_t func = cb->f.vcpu_syscall_filter;
+
+ if (func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4,
+ a5, a6, a7, a8, sysret)) {
+ filtered = true;
+ break;
+ }
+ }
+
+ qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
+
+ return filtered;
+}
+
void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
{
/* idle and resume cb may be called before init, ignore in this case */