All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: Ziyang Zhang <functioner@sjtu.edu.cn>
Cc: qemu-devel <qemu-devel@nongnu.org>,
	 Riku Voipio <riku.voipio@iki.fi>,
	Laurent Vivier <laurent@vivier.eu>,
	 Alexandre Iooss <erdnaxe@crans.org>,
	Mahmoud Mandour <ma.mandourr@gmail.com>,
	 Pierrick Bouvier <pierrick.bouvier@linaro.org>,
	 Richard Henderson <richard.henderson@linaro.org>,
	 Zhengwei Qi <qizhwei@sjtu.edu.cn>,
	 Yun Wang <yunwang94@sjtu.edu.cn>,
	 Mingyuan Xia <xiamy@ultrarisc.com>,
	Kailiang Xu <xukl2019@sjtu.edu.cn>
Subject: Re: [PATCH 1/2] linux-user: add a plugin API to filter syscalls
Date: Fri, 12 Dec 2025 14:29:09 +0000	[thread overview]
Message-ID: <87v7ibsrii.fsf@draig.linaro.org> (raw)
In-Reply-To: <20251110133442.579086-2-functioner@sjtu.edu.cn> (Ziyang Zhang's message of "Mon, 10 Nov 2025 21:34:42 +0800")

Ziyang Zhang <functioner@sjtu.edu.cn> writes:

> 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>
> ---
>  include/qemu/plugin-event.h  |  1 +
>  include/qemu/plugin.h        | 29 +++++++++++++++++++++--------
>  include/qemu/qemu-plugin.h   | 24 ++++++++++++++++++++++++
>  include/user/syscall-trace.h | 17 +++++++++++++++++
>  linux-user/syscall.c         |  7 +++++--
>  plugins/api.c                |  7 +++++++
>  plugins/core.c               | 36 ++++++++++++++++++++++++++++++++++++
>  7 files changed, 111 insertions(+), 10 deletions(-)
>
> diff --git a/include/qemu/plugin-event.h b/include/qemu/plugin-event.h
> index 7056d8427b..bbb1c2b91f 100644
> --- a/include/qemu/plugin-event.h
> +++ b/include/qemu/plugin-event.h
> @@ -20,6 +20,7 @@ enum qemu_plugin_event {
>      QEMU_PLUGIN_EV_VCPU_SYSCALL_RET,
>      QEMU_PLUGIN_EV_FLUSH,
>      QEMU_PLUGIN_EV_ATEXIT,
> +    QEMU_PLUGIN_EV_VCPU_SYSCALL_FILTER,
>      QEMU_PLUGIN_EV_MAX, /* total number of plugin events we support */
>  };
>  
> diff --git a/include/qemu/plugin.h b/include/qemu/plugin.h
> index f355c7cb8a..9f90a233e7 100644
> --- a/include/qemu/plugin.h
> +++ b/include/qemu/plugin.h
> @@ -55,14 +55,15 @@ 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_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_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;
>  };
>  
> @@ -165,6 +166,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 *ret);
>  
>  void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
>                               uint64_t value_low,
> @@ -267,6 +273,13 @@ 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 *ret)
> +{ }
> +

This needs to return false so it compile and work with --disable-plugins.

>  static inline void qemu_plugin_vcpu_mem_cb(CPUState *cpu, uint64_t vaddr,
>                                             uint64_t value_low,
>                                             uint64_t value_high,
> diff --git a/include/qemu/qemu-plugin.h b/include/qemu/qemu-plugin.h
> index c450106af1..cdd0b2c4da 100644
> --- a/include/qemu/qemu-plugin.h
> +++ b/include/qemu/qemu-plugin.h
> @@ -738,6 +738,25 @@ 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
> + * @vcpu_index: the executing vCPU
> + * @num: the syscall number
> + * @a1-a8: the syscall arguments
> + * @ret: the address of the syscall return value, set this if
> filtered

"must set this..."

> + *
> + * Returns: true if you want to filter this syscall (i.e. stop it being
> + * handled further), otherwise return 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 *ret);
> +
>  QEMU_PLUGIN_API
>  void qemu_plugin_register_vcpu_syscall_cb(qemu_plugin_id_t id,
>                                            qemu_plugin_vcpu_syscall_cb_t cb);
> @@ -751,6 +770,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
> diff --git a/include/user/syscall-trace.h b/include/user/syscall-trace.h
> index 9bd7ca19c8..61cdbd7583 100644
> --- a/include/user/syscall-trace.h
> +++ b/include/user/syscall-trace.h
> @@ -39,5 +39,22 @@ static inline void record_syscall_return(CPUState *cpu, int num, abi_long ret)
>      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 *ret)
> +{
> +    uint64_t sysret64 = 0;
> +    bool filtered = qemu_plugin_vcpu_syscall_filter(cpu, num, arg1, arg2,
> +                                                    arg3, arg4, arg5, arg6,
> +                                                    arg7, arg8, &sysret64);
> +    if (filtered) {
> +        *ret = sysret64;
> +    }
> +    return filtered;
> +}
> +
>  
>  #endif /* SYSCALL_TRACE_H */
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index d78b2029fa..1fb99dcf0c 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -14084,8 +14084,11 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
>          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,
> diff --git a/plugins/api.c b/plugins/api.c
> index eac04cc1f6..478d0c8889 100644
> --- a/plugins/api.c
> +++ b/plugins/api.c
> @@ -208,6 +208,13 @@ qemu_plugin_register_vcpu_syscall_ret_cb(qemu_plugin_id_t id,
>      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
>   *
> diff --git a/plugins/core.c b/plugins/core.c
> index ead09fd2f1..8cd773cbca 100644
> --- a/plugins/core.c
> +++ b/plugins/core.c
> @@ -538,6 +538,42 @@ void qemu_plugin_vcpu_syscall_ret(CPUState *cpu, int64_t num, int64_t ret)
>      }
>  }
>  
> +/*
> + * 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 *ret)
> +{
> +    struct qemu_plugin_cb *cb, *next;
> +    enum qemu_plugin_event ev = QEMU_PLUGIN_EV_VCPU_SYSCALL_FILTER;
> +
> +    if (!test_bit(ev, cpu->plugin_state->event_mask)) {
> +        return false;
> +    }
> +
> +    bool filtered = false;

nit: keep args together in the block

> +    QLIST_FOREACH_SAFE_RCU(cb, &plugin.cb_lists[ev], entry, next) {
> +        qemu_plugin_vcpu_syscall_filter_cb_t func = cb->f.vcpu_syscall_filter;
> +
> +        qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_RW_REGS);

I think setting these flags could be outside the loop.

> +        if (func(cb->ctx->id, cpu->cpu_index, num, a1, a2, a3, a4,
> +                 a5, a6, a7, a8, ret)) {
> +            filtered = true;

then you could just break here.

> +        }
> +        qemu_plugin_set_cb_flags(cpu, QEMU_PLUGIN_CB_NO_REGS);
> +
> +        if (filtered)
> +            break;

nit: brackets

> +    }
> +    return filtered;
> +}
> +
>  void qemu_plugin_vcpu_idle_cb(CPUState *cpu)
>  {
>      /* idle and resume cb may be called before init, ignore in this case */

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro


  parent reply	other threads:[~2025-12-12 14:29 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-10 13:34 [PATCH 0/2] linux-user: add a syscall-filter plugin API Ziyang Zhang
2025-11-10 13:34 ` [PATCH 1/2] linux-user: add a plugin API to filter syscalls Ziyang Zhang
2025-12-03  2:07   ` Pierrick Bouvier
2025-12-12 14:29   ` Alex Bennée [this message]
2025-11-10 13:34 ` [PATCH 2/2] tcg tests: add a test to verify the syscall filter plugin API Ziyang Zhang
2025-12-03  2:08   ` Pierrick Bouvier
2025-12-12 12:44 ` [PATCH 0/2] linux-user: add a syscall-filter " Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87v7ibsrii.fsf@draig.linaro.org \
    --to=alex.bennee@linaro.org \
    --cc=erdnaxe@crans.org \
    --cc=functioner@sjtu.edu.cn \
    --cc=laurent@vivier.eu \
    --cc=ma.mandourr@gmail.com \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qizhwei@sjtu.edu.cn \
    --cc=richard.henderson@linaro.org \
    --cc=riku.voipio@iki.fi \
    --cc=xiamy@ultrarisc.com \
    --cc=xukl2019@sjtu.edu.cn \
    --cc=yunwang94@sjtu.edu.cn \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.