plugins: Add enforcement of QEMU_PLUGIN_CB flags in register R/W callbacks

This patch adds functionality to enforce the requested QEMU_PLUGIN_CB_
flags level passed when registering a callback function using the
plugins API. Each time a callback is about to be invoked, a thread-local
variable will be updated with the level that callback requested. Then,
called API functions (in particular, the register read and write API)
will call qemu_plugin_get_cb_flags() to check the level is at least the
level they require.

Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Signed-off-by: Rowan Hart <rowanbhart@gmail.com>
Message-ID: <20250624175351.440780-4-rowanbhart@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-ID: <20250627112512.1880708-8-alex.bennee@linaro.org>
This commit is contained in:
Rowan Hart 2025-06-27 12:25:03 +01:00 committed by Alex Bennée
parent 1a92b65859
commit 766e00bd57
6 changed files with 96 additions and 6 deletions

View file

@ -368,6 +368,7 @@ typedef struct CPUNegativeOffsetState {
GArray *plugin_mem_cbs;
uint64_t plugin_mem_value_low;
uint64_t plugin_mem_value_high;
int32_t plugin_cb_flags;
#endif
IcountDecr icount_decr;
bool can_do_io;

View file

@ -209,6 +209,21 @@ void qemu_plugin_user_prefork_lock(void);
*/
void qemu_plugin_user_postfork(bool is_child);
enum qemu_plugin_cb_flags tcg_call_to_qemu_plugin_cb_flags(int flags);
static inline void qemu_plugin_set_cb_flags(CPUState *cpu,
enum qemu_plugin_cb_flags flags)
{
assert(cpu);
cpu->neg.plugin_cb_flags = flags;
}
static inline enum qemu_plugin_cb_flags qemu_plugin_get_cb_flags(void)
{
assert(current_cpu);
return current_cpu->neg.plugin_cb_flags;
}
#else /* !CONFIG_PLUGIN */
static inline void qemu_plugin_add_opts(void)

View file

@ -254,9 +254,6 @@ typedef struct {
* @QEMU_PLUGIN_CB_NO_REGS: callback does not access the CPU's regs
* @QEMU_PLUGIN_CB_R_REGS: callback reads the CPU's regs
* @QEMU_PLUGIN_CB_RW_REGS: callback reads and writes the CPU's regs
*
* Note: currently QEMU_PLUGIN_CB_RW_REGS is unused, plugins cannot change
* system register state.
*/
enum qemu_plugin_cb_flags {
QEMU_PLUGIN_CB_NO_REGS,
@ -901,7 +898,12 @@ GArray *qemu_plugin_get_registers(void);
* @buf: A GByteArray for the data owned by the plugin
*
* This function is only available in a context that register read access is
* explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag.
* explicitly requested via the QEMU_PLUGIN_CB_R_REGS flag, if called inside a
* callback that can be registered with a qemu_plugin_cb_flags argument. This
* function can also be used in any callback context that does not use a flags
* argument, such as in a callback registered with
* qemu_plugin_register_vcpu_init_cb(), except for callbacks registered with
* qemu_plugin_register_atexit_cb() and qemu_plugin_register_flush_cb().
*
* Returns the size of the read register. The content of @buf is in target byte
* order. On failure returns -1.
@ -916,8 +918,13 @@ int qemu_plugin_read_register(struct qemu_plugin_register *handle,
* @handle: a @qemu_plugin_reg_handle handle
* @buf: A GByteArray for the data owned by the plugin
*
* This function is only available in a context that register write access is
* explicitly requested via the QEMU_PLUGIN_CB_RW_REGS flag.
* This function is only available in a context that register read access is
* explicitly requested via the QEMU_PLUGIN_CB_RW_REGS flag, if called inside a
* callback that can be registered with a qemu_plugin_cb_flags argument. This
* function can also be used in any callback context that does not use a flags
* argument, such as in a callback registered with
* qemu_plugin_register_vcpu_init_cb(), except for callbacks registered with
* qemu_plugin_register_atexit_cb() and qemu_plugin_register_flush_cb().
*
* The size of @buf must be at least the size of the requested register.
* Attempting to write a register with @buf smaller than the register size