Features/GuestAgent: Difference between revisions

From QEMU
Line 14: Line 14:
   -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
   -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
   -device virtio-serial \
   -device virtio-serial \
   -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0"
   -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0


Commands would be then be issued by connecting to /tmp/qga.sock, writing the QMP-formatted guest agent command, reading the QMP-formatted response, then disconnecting from the socket. (It's not strictly necessary to disconnect after a command, but should be done to allow sharing of the guest agent with multiple client when exposing it as a standalone service in this fashion. When guest agent passthrough support is added to QMP, QEMU/QMP will handle arbitration between multiple clients).
Commands would be then be issued by connecting to /tmp/qga.sock, writing the QMP-formatted guest agent command, reading the QMP-formatted response, then disconnecting from the socket. (It's not strictly necessary to disconnect after a command, but should be done to allow sharing of the guest agent with multiple client when exposing it as a standalone service in this fashion. When guest agent passthrough support is added to QMP, QEMU/QMP will handle arbitration between multiple clients).


When QAPI-based QMP is available (somewhere around the QEMU 0.16 timeframe), a different host-side invocation that doesn't involve access to the guest agent outside of QMP. Currently this is done as a pseudo-chardev that only QEMU/QMP, but the ultimate implementation may vary to some degree. The net effect should the same however: guest agent commands will be exposed in the same manner as QMP commands using the same QMP server, and communication with the agent will be done transparently to the client.
When QAPI-based QMP is available (somewhere around the QEMU 0.16 timeframe), a different host-side invocation that doesn't involve access to the guest agent outside of QMP will be used. Something like:
 
  qemu \
  ...
  -chardev qga_proxy,id=qga0 \
  -device virtio-serial \
  -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
  -qmp tcp:localhost:4444,server
 
Currently this is planned to be done as a pseudo-chardev that only QEMU/QMP sees or interacts with, but the ultimate implementation may vary to some degree. The net effect should the same however: guest agent commands will be exposed in the same manner as QMP commands using the same QMP server, and communication with the agent will be handled by QEMU, transparently to the client.


The current list of supported RPCs is documented in qemu.git/qapi-schema-guest.json.
The current list of supported RPCs is documented in qemu.git/qapi-schema-guest.json.

Revision as of 17:31, 25 July 2011

Summary

Implement support for QMP commands and events that terminate and originate respectively within the guest using an agent built as part of QEMU.

Detailed Summary

Ultimately the QEMU Guest Agent aims to provide access to a system-level agent via standard QMP commands.

This support is targeted for a future QAPI-based rework of QMP, however, so currently, for QEMU 0.15, the guest agent is exposed to the host via a separate QEMU chardev device (generally, a unix socket) that communicates with the agent using the QMP wire protocol (minus the negotiation) over a virtio-serial or isa-serial channel to the guest. Assuming the agent will be listening inside the guest using the virtio-serial device at /dev/virtio-ports/org.qemu.guest_agent.0 (the default), the corresponding host-side QEMU invocation would be something:

 qemu \
 ...
 -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
 -device virtio-serial \
 -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0

Commands would be then be issued by connecting to /tmp/qga.sock, writing the QMP-formatted guest agent command, reading the QMP-formatted response, then disconnecting from the socket. (It's not strictly necessary to disconnect after a command, but should be done to allow sharing of the guest agent with multiple client when exposing it as a standalone service in this fashion. When guest agent passthrough support is added to QMP, QEMU/QMP will handle arbitration between multiple clients).

When QAPI-based QMP is available (somewhere around the QEMU 0.16 timeframe), a different host-side invocation that doesn't involve access to the guest agent outside of QMP will be used. Something like:

 qemu \
 ...
 -chardev qga_proxy,id=qga0 \
 -device virtio-serial \
 -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
 -qmp tcp:localhost:4444,server

Currently this is planned to be done as a pseudo-chardev that only QEMU/QMP sees or interacts with, but the ultimate implementation may vary to some degree. The net effect should the same however: guest agent commands will be exposed in the same manner as QMP commands using the same QMP server, and communication with the agent will be handled by QEMU, transparently to the client.

The current list of supported RPCs is documented in qemu.git/qapi-schema-guest.json.

Schema Definition

All guest commands will use a guest- prefix to distinguish the fact that the commands are handled by the guest. Likewise, events will carry a GUEST_ prefix. Type names (complex types and enums) do not require a special prefix. The following is an example of the proposed guest agent schema:

// qemu/qmp-schema.json
[ 'guest-ping', {}, 'none' ]
[ 'guest-view-file', {'filename', 'str'}, 'str' ]

{ 'GuestType': [ 'linux', 'windows', 'freebsd', 'netbsd',
                 'openbsd', 'solaris' ] }
{ 'GuestInfo': { 'os-type': 'GuestType', 'os-version': 'str',
                 'agent-version': 'str' } }
{ 'GUEST_STARTUP': { 'GuestInfo': 'str' } }

libqmp

In libqmp, the code generated for a guest command is identical to the code generated for a normal command.

For instance, the guest-view-file command will have the following signature:

char *qmp_guest_view_file(QmpSession *sess, const char *filename, Error **errp);

QEMU

The only role QEMU plays in guest commands is unmarshalling and remarshalling the input and output. This means that data from the guest is not being sent directly to a management tool which significantly decreases the guest attack surface.

This works by combining the existing unmarshalling code for the QMP server with the marshalling code from libqmp. Here is an example of the code that will be generated:

void qmp_guest_ping(Error **errp)
{
    QDict *args = qdict_new();
    QObject *ret_data;
    // no arguments to marshal
    ret_data = qmp_guest_command_dispatch("guest-ping", args, errp);
    // ret_data should always be empty
    qobject_decref(ret_data);
    QDECREF(args);
}

static void qmp_marshal_guest_ping(const QDict *args, QObject **ret_data, Error **errp)

{

   // no arguments to unmarshal
   qmp_guest_ping(errp);
   // no retval to marshal

}

virtio-serial Transport

The qmp_guest_command_dispatch command will take the QObjects and generate a QMP command to send to the guest. This will be sent to the guest via a new CharDriverState implementation. This CharDriverState will provide a backend to virtio-serial. It will essentially act as an in-memory chardev except that it will parse the input from the guest for invalid UTF-8 characters. If an invalid character is detected, the CharDriverState will generate a reset.

This behavior will be utilized by the guest in order to reset the QMP session after the guest agent restarts. The first byte it writes to virtio-serial will always be 0xFF.

Guest Agent

The guest agent will be a daemon that connects to a virtio-serial device and feeds the input to a JSON parser. When a new command is received, it will hand the command over to the QAPI generated dispatch routines.

The guest agent will implement the server side of the QMP commands using the native signature for the function.

Asynchronous Commands

Since QEMU cannot rely on the guest agent responding immediately to a command (it is in fact impossible for it to do so), all guest commands most be implemented as asynchronous commands within QEMU. This does not change anything from a protocol visible perspective but is simply an implementation detail within QEMU.

Security Considerations

The following security issues need to be resolved in QMP:

1. The JSON parser uses a recursive decent parser. Malicious input could potentially cause a stack overflow. Either implement a recursion depth counter, or swith the parser to only use tail recursion. 1. The JSON parser may not handle premature EOI all that well. I think I've worked out most of these issues but more rigorious testing is needed.