KVM-VMI / kvm-vmi

KVM-based Virtual Machine Introspection
https://kvm-vmi.github.io/kvm-vmi/master/
298 stars 61 forks source link

Can't use KVMi functionality from QEMU monitor commands #171

Open Zhuzhzhalka opened 2 months ago

Zhuzhzhalka commented 2 months ago

I'm trying to implement some KVMi based introspection functionality from the QEMU monitor itself: under qmp and hmp commands. That is - booting a KVMi-patched QEMU instance, connecting to its monitor, typing a monitor command and get some implemented introspection results.

QEMU extra args:

-cpu host,kvm=off,migratable=off -chardev socket,path=/tmp/introspector,id=chardev0,reconnect=10 -object introspection,id=kvmi,chardev=chardev0 \

However, when executing the custom qmp command, something hangs in KVMi initialization process - seems to be related to Unix socket.

--found KVM
LibVMI Version 0.13.0
LibVMI Driver Mode 1
--libkvmi path: /usr/local/lib/libkvmi.so
--completed driver init.
--got name from id (1 --> kvmi)
**set image_type = kvmi
--KVMi socket path: /tmp/introspector
--Connecting to KVMI...
--KVMI failed
--Destroying KVM driver

Wait condition timeouts in this fragment of libvmi code:

    kvm->kvmi = kvm->libkvmi.kvmi_init_unix_socket(sock_path, new_guest_cb, handshake_cb, kvm);
    if (kvm->kvmi) {
        struct timeval now;
        if (gettimeofday(&now, NULL) == 0) {
            struct timespec t = {};
            t.tv_sec = now.tv_sec + 10;
            err = pthread_cond_timedwait(&kvm->kvm_start_cond, &kvm->kvm_connect_mutex, &t);
        }
    }

Checked that and turns out poll() doesn't succeed inside accept_worker() in libkvmi.

Custom qmp command implementation uses standard libvmi initialization mechanism:

VmiStatus *qmp_init_vmi(Error **errp)
{
    uint8_t init = VMI_INIT_DOMAINID;
    uint8_t config_type = VMI_CONFIG_JSON_PATH;
    char socket_path[] = "/tmp/introspector";
    struct VmiStatus *status = g_malloc0(sizeof(*status));
    vmi_instance_t *vmi = g_malloc0(sizeof(*vmi));
    uint64_t domid = 1;
    void *input = &domid;
    void *config = g_strndup("/tmp/profile.json", 17);
    vmi_init_data_t *init_data = g_malloc0(sizeof(vmi_init_data_t) + sizeof(vmi_init_data_entry_t));

    init_data->count = 1;
    init_data->entry[0].type = VMI_INIT_DATA_KVMI_SOCKET;
    init_data->entry[0].data = g_strndup(socket_path, sizeof(socket_path));

    status->status = vmi_init_complete(vmi, input, init, init_data, config_type, config, NULL);

    return status;
}

I've followed the instructions from https://kvm-vmi.github.io/kvm-vmi/master/setup.html for bare-metal setup. Everything is fine - all the examples work. Moreover, when executing the exact same libvmi-interacting code (which I wrote for qmp function) as a separate program, everything initializes and works correctly.

--found KVM
LibVMI Version 0.13.0
LibVMI Driver Mode 1
--libkvmi path: /usr/local/lib/libkvmi.so
--completed driver init.
--got name from id (1 --> kvmi)
**set image_type = kvmi
--KVMi socket path: /tmp/introspector
--Connecting to KVMI...
--KVMi handshake:
--    VM name: 
--    VM start time: 23:21:04 - Fri Jan 02 1970
--KVMi new guest:
--    UUID: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
--    FD: 6
--    Protocol version: 1
--KVMi features:
--    VMFUNC: Yes
--    EPTP: Yes
--    VE: Yes
--    SPP: No
--KVMI connected
--VCPU count: 4

I wonder if it is actually possible to use KVMi from inside QEMU monitor commands or it is impossible by design (maybe KVMi relies on the same QEMU functionality and it somehow deadlocks while handshaking)?

Please let me know if there is extra information I can provide you.