From patchwork Wed Apr 15 00:59:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284360 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A793AC2BB1D for ; Wed, 15 Apr 2020 01:01:31 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 73C552072D for ; Wed, 15 Apr 2020 01:01:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 73C552072D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40880 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWQk-0002i7-EV for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:01:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58308) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWOx-0000vf-BL for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWOv-000509-T6 for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:39 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:48989) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWOv-0004xv-Kx for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:37 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 4413F30747C0; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 29190305B7A2; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 03/26] char-socket: fix the client mode when created through QMP Date: Wed, 15 Apr 2020 03:59:15 +0300 Message-Id: <20200415005938.23895-4-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" qmp_chardev_open_socket() ignores the absence of the 'server' argument and always switches to listen/server mode. CC: "Marc-André Lureau" CC: Paolo Bonzini Signed-off-by: Adalbert Lazăr --- chardev/char-socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 9b2deb0125..fd0106ab85 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1310,7 +1310,7 @@ static void qmp_chardev_open_socket(Chardev *chr, SocketChardev *s = SOCKET_CHARDEV(chr); ChardevSocket *sock = backend->u.socket.data; bool do_nodelay = sock->has_nodelay ? sock->nodelay : false; - bool is_listen = sock->has_server ? sock->server : true; + bool is_listen = sock->has_server ? sock->server : false; bool is_telnet = sock->has_telnet ? sock->telnet : false; bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false; bool is_waitconnect = sock->has_wait ? sock->wait : false; From patchwork Wed Apr 15 00:59:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284358 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9EE91C2BB1D for ; Wed, 15 Apr 2020 01:05:09 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 48DDB2072D for ; Wed, 15 Apr 2020 01:05:09 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 48DDB2072D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40912 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWUG-0006QH-BW for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:05:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58307) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWOx-0000ve-BV for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWOv-000504-T0 for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:38 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:48988) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWOv-0004xx-Kz for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:37 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 5BD0F30747C2; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 44546305B7A3; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 04/26] char-socket: add 'reconnecting' property Date: Wed, 15 Apr 2020 03:59:16 +0300 Message-Id: <20200415005938.23895-5-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This is used by the VM introspection object to check if the connection will be reestablished in case it disconnects from some reason. The closing of the socket is used by any of the three parties involved, KVM, the introspection tool and QEMU (eg. on force-reset), to signal the other parties that the session is over. As such, it is very important that the socket will reconnect. CC: "Marc-André Lureau" CC: Paolo Bonzini Signed-off-by: Adalbert Lazăr --- chardev/char-socket.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index fd0106ab85..22ab242748 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1492,6 +1492,13 @@ char_socket_get_connected(Object *obj, Error **errp) return s->state == TCP_CHARDEV_STATE_CONNECTED; } +static bool char_socket_get_reconnecting(Object *obj, Error **errp) +{ + SocketChardev *s = SOCKET_CHARDEV(obj); + + return s->reconnect_time > 0; +} + static int tcp_chr_reconnect_time(Chardev *chr, int secs) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -1528,6 +1535,10 @@ static void char_socket_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "connected", char_socket_get_connected, NULL, &error_abort); + + object_class_property_add_bool(oc, "reconnecting", + char_socket_get_reconnecting, + NULL, &error_abort); } static const TypeInfo char_socket_type_info = { From patchwork Wed Apr 15 00:59:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284356 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47DB8C2BB1D for ; Wed, 15 Apr 2020 01:08:23 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0B8922072D for ; Wed, 15 Apr 2020 01:08:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0B8922072D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40948 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWXO-0001sz-08 for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:08:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58353) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWOy-0000vq-Hf for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWOx-00051k-Cb for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:40 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49078) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWOx-00050k-41 for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:39 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 7395430747C3; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 5ACE2305B7A0; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 05/26] char-socket: add 'fd' property Date: Wed, 15 Apr 2020 03:59:17 +0300 Message-Id: <20200415005938.23895-6-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , =?utf-8?q?Marc-Andr=C3=A9_Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This is used by the VM introspection object, after handshake, to hand over the file descriptor to KVM. CC: "Marc-André Lureau" CC: Paolo Bonzini Signed-off-by: Adalbert Lazăr --- chardev/char-socket.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 22ab242748..76d0fb8839 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1499,6 +1499,21 @@ static bool char_socket_get_reconnecting(Object *obj, Error **errp) return s->reconnect_time > 0; } +static void +char_socket_get_fd(Object *obj, Visitor *v, const char *name, void *opaque, + Error **errp) +{ + int fd = -1; + SocketChardev *s = SOCKET_CHARDEV(obj); + QIOChannelSocket *sock = QIO_CHANNEL_SOCKET(s->sioc); + + if (sock) { + fd = sock->fd; + } + + visit_type_int32(v, name, &fd, errp); +} + static int tcp_chr_reconnect_time(Chardev *chr, int secs) { SocketChardev *s = SOCKET_CHARDEV(chr); @@ -1539,6 +1554,9 @@ static void char_socket_class_init(ObjectClass *oc, void *data) object_class_property_add_bool(oc, "reconnecting", char_socket_get_reconnecting, NULL, &error_abort); + + object_class_property_add(oc, "fd", "int32", char_socket_get_fd, + NULL, NULL, NULL, &error_abort); } static const TypeInfo char_socket_type_info = { From patchwork Wed Apr 15 00:59:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284349 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35D4EC2BB1D for ; Wed, 15 Apr 2020 01:15:17 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E6ACC206D9 for ; Wed, 15 Apr 2020 01:15:16 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E6ACC206D9 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41040 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWe4-0004r9-2j for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:15:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58502) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPB-0001Mz-4Z for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP7-0005BY-MB for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:53 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49086) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP7-00050u-8J for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:49 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 11C7830747C8 for ; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id F0C46305B7A1; Wed, 15 Apr 2020 03:59:34 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 10/26] kvm: vmi: add the handshake with the introspection tool Date: Wed, 15 Apr 2020 03:59:22 +0300 Message-Id: <20200415005938.23895-11-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" QEMU sends the name, the UUID and the VM start time and expects the hash of a secret shared with the introspection tool that can be used to authenticate it. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 290 +++++++++++++++++++++++++++++++++ include/sysemu/vmi-handshake.h | 45 +++++ 2 files changed, 335 insertions(+) create mode 100644 include/sysemu/vmi-handshake.h diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 883c666a2a..57ded2f69c 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu-common.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qom/object_interfaces.h" @@ -16,6 +17,8 @@ #include "chardev/char.h" #include "chardev/char-fe.h" +#include "sysemu/vmi-handshake.h" + typedef struct VMIntrospection { Object parent_obj; @@ -23,9 +26,19 @@ typedef struct VMIntrospection { char *chardevid; Chardev *chr; + CharBackend sock; + int sock_fd; + + qemu_vmi_from_introspector hsk_in; + uint64_t hsk_in_read_pos; + uint64_t hsk_in_read_size; + + int64_t vm_start_time; Notifier machine_ready; bool created_from_command_line; + + bool kvmi_hooked; } VMIntrospection; #define TYPE_VM_INTROSPECTION "introspection" @@ -50,6 +63,11 @@ static void machine_ready(Notifier *notifier, void *data) } } +static void update_vm_start_time(VMIntrospection *i) +{ + i->vm_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); +} + static void complete(UserCreatable *uc, Error **errp) { VMIntrospection *i = VM_INTROSPECTION(uc); @@ -87,6 +105,13 @@ static void prop_set_chardev(Object *obj, const char *value, Error **errp) i->chardevid = g_strdup(value); } +static bool chardev_is_connected(VMIntrospection *i, Error **errp) +{ + Object *obj = OBJECT(i->chr); + + return obj && object_property_get_bool(obj, "connected", errp); +} + static void class_init(ObjectClass *oc, void *data) { UserCreatableClass *uc = USER_CREATABLE_CLASS(oc); @@ -98,17 +123,60 @@ static void instance_init(Object *obj) { VMIntrospection *i = VM_INTROSPECTION(obj); + i->sock_fd = -1; i->created_from_command_line = (qdev_hotplug == false); + update_vm_start_time(i); + object_property_add_str(obj, "chardev", NULL, prop_set_chardev, NULL); } +static void disconnect_chardev(VMIntrospection *i) +{ + if (chardev_is_connected(i, NULL)) { + qemu_chr_fe_disconnect(&i->sock); + } +} + +static void unhook_kvmi(VMIntrospection *i) +{ + if (i->kvmi_hooked) { + if (kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_UNHOOK, NULL)) { + error_report("VMI: ioctl/KVM_INTROSPECTION_UNHOOK failed, errno %d", + errno); + } + i->kvmi_hooked = false; + } +} + +static void shutdown_socket_fd(VMIntrospection *i) +{ + /* signal both ends (kernel, introspector) */ + if (i->sock_fd != -1) { + shutdown(i->sock_fd, SHUT_RDWR); + i->sock_fd = -1; + } +} + +static void disconnect_and_unhook_kvmi(VMIntrospection *i) +{ + shutdown_socket_fd(i); + disconnect_chardev(i); + unhook_kvmi(i); +} + static void instance_finalize(Object *obj) { VMIntrospection *i = VM_INTROSPECTION(obj); g_free(i->chardevid); + if (i->chr) { + shutdown_socket_fd(i); + qemu_chr_fe_deinit(&i->sock, true); + unhook_kvmi(i); + } + error_free(i->init_error); } @@ -132,6 +200,210 @@ static void register_types(void) type_init(register_types); +static bool send_handshake_info(VMIntrospection *i, Error **errp) +{ + qemu_vmi_to_introspector send = {}; + const char *vm_name; + int r; + + send.struct_size = sizeof(send); + send.start_time = i->vm_start_time; + memcpy(&send.uuid, &qemu_uuid, sizeof(send.uuid)); + vm_name = qemu_get_vm_name(); + if (vm_name) { + snprintf(send.name, sizeof(send.name), "%s", vm_name); + send.name[sizeof(send.name) - 1] = 0; + } + + r = qemu_chr_fe_write_all(&i->sock, (uint8_t *)&send, sizeof(send)); + if (r != sizeof(send)) { + error_setg_errno(errp, errno, "VMI: error writing to '%s'", + i->chardevid); + return false; + } + + /* tcp_chr_write may call tcp_chr_disconnect/CHR_EVENT_CLOSED */ + if (!chardev_is_connected(i, errp)) { + error_append_hint(errp, "VMI: qemu_chr_fe_write_all() failed"); + return false; + } + + return true; +} + +static bool validate_handshake(VMIntrospection *i, Error **errp) +{ + uint32_t min_accepted_size; + + min_accepted_size = offsetof(qemu_vmi_from_introspector, cookie_hash) + + QEMU_VMI_COOKIE_HASH_SIZE; + + if (i->hsk_in.struct_size < min_accepted_size) { + error_setg(errp, "VMI: not enough or invalid handshake data"); + return false; + } + + /* + * Check hsk_in.struct_size and sizeof(hsk_in) before accessing any + * other fields. We might get fewer bytes from applications using + * old versions if we extended the qemu_vmi_from_introspector structure. + */ + + return true; +} + +static bool connect_kernel(VMIntrospection *i, Error **errp) +{ + struct kvm_introspection_feature commands, events; + struct kvm_introspection_hook kernel; + const __s32 all_ids = -1; + + memset(&kernel, 0, sizeof(kernel)); + memcpy(kernel.uuid, &qemu_uuid, sizeof(kernel.uuid)); + kernel.fd = i->sock_fd; + + if (kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_HOOK, &kernel)) { + error_setg_errno(errp, -errno, + "VMI: ioctl/KVM_INTROSPECTION_HOOK failed"); + if (errno == -EPERM) { + error_append_hint(errp, + "Reload the kvm module with kvm.introspection=on"); + } + return false; + } + + i->kvmi_hooked = true; + + commands.allow = 1; + commands.id = all_ids; + if (kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_COMMAND, &commands)) { + error_setg_errno(errp, -errno, + "VMI: ioctl/KVM_INTROSPECTION_COMMAND failed"); + unhook_kvmi(i); + return false; + } + + events.allow = 1; + events.id = all_ids; + if (kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_EVENT, &events)) { + error_setg_errno(errp, -errno, + "VMI: ioctl/KVM_INTROSPECTION_EVENT failed"); + unhook_kvmi(i); + return false; + } + + return true; +} + +/* + * We should read only the handshake structure, + * which might have a different size than what we expect. + */ +static int chr_can_read(void *opaque) +{ + VMIntrospection *i = opaque; + + if (i->sock_fd == -1) { + return 0; + } + + /* first, we read the incoming structure size */ + if (i->hsk_in_read_pos == 0) { + return sizeof(i->hsk_in.struct_size); + } + + /* validate the incoming structure size */ + if (i->hsk_in.struct_size < sizeof(i->hsk_in.struct_size)) { + return 0; + } + + /* read the rest of the incoming structure */ + return i->hsk_in.struct_size - i->hsk_in_read_pos; +} + +static bool enough_bytes_for_handshake(VMIntrospection *i) +{ + return i->hsk_in_read_pos >= sizeof(i->hsk_in.struct_size) + && i->hsk_in_read_size == i->hsk_in.struct_size; +} + +static void validate_and_connect(VMIntrospection *i) +{ + Error *local_err = NULL; + + if (!validate_handshake(i, &local_err) || !connect_kernel(i, &local_err)) { + error_append_hint(&local_err, "reconnecting\n"); + warn_report_err(local_err); + disconnect_chardev(i); + } +} + +static void chr_read(void *opaque, const uint8_t *buf, int size) +{ + VMIntrospection *i = opaque; + size_t to_read; + + i->hsk_in_read_size += size; + + to_read = sizeof(i->hsk_in) - i->hsk_in_read_pos; + if (to_read > size) { + to_read = size; + } + + if (to_read) { + memcpy((uint8_t *)&i->hsk_in + i->hsk_in_read_pos, buf, to_read); + i->hsk_in_read_pos += to_read; + } + + if (enough_bytes_for_handshake(i)) { + validate_and_connect(i); + } +} + +static void chr_event_open(VMIntrospection *i) +{ + Error *local_err = NULL; + + if (!send_handshake_info(i, &local_err)) { + error_append_hint(&local_err, "reconnecting\n"); + warn_report_err(local_err); + disconnect_chardev(i); + return; + } + + info_report("VMI: introspection tool connected"); + + i->sock_fd = object_property_get_int(OBJECT(i->chr), "fd", NULL); + + memset(&i->hsk_in, 0, sizeof(i->hsk_in)); + i->hsk_in_read_pos = 0; + i->hsk_in_read_size = 0; +} + +static void chr_event_close(VMIntrospection *i) +{ + if (i->sock_fd != -1) { + warn_report("VMI: introspection tool disconnected"); + disconnect_and_unhook_kvmi(i); + } +} + +static void chr_event(void *opaque, QEMUChrEvent event) +{ + VMIntrospection *i = opaque; + + switch (event) { + case CHR_EVENT_OPENED: + chr_event_open(i); + break; + case CHR_EVENT_CLOSED: + chr_event_close(i); + break; + default: + break; + } +} + static Error *vm_introspection_init(VMIntrospection *i) { Error *err = NULL; @@ -162,7 +434,25 @@ static Error *vm_introspection_init(VMIntrospection *i) return err; } + if (!qemu_chr_fe_init(&i->sock, chr, &err)) { + error_append_hint(&err, "VMI: device '%s' not initialized", + i->chardevid); + return err; + } + i->chr = chr; + qemu_chr_fe_set_handlers(&i->sock, chr_can_read, chr_read, chr_event, + NULL, i, NULL, true); + + /* + * The reconnect timer is triggered by either machine init or by a chardev + * disconnect. For the QMP creation, when the machine is already started, + * use an artificial disconnect just to restart the timer. + */ + if (!i->created_from_command_line) { + qemu_chr_fe_disconnect(&i->sock); + } + return NULL; } diff --git a/include/sysemu/vmi-handshake.h b/include/sysemu/vmi-handshake.h new file mode 100644 index 0000000000..19bdfb6740 --- /dev/null +++ b/include/sysemu/vmi-handshake.h @@ -0,0 +1,45 @@ +/* + * QEMU VM Introspection Handshake + * + */ + +#ifndef QEMU_VMI_HANDSHAKE_H +#define QEMU_VMI_HANDSHAKE_H + +enum { QEMU_VMI_NAME_SIZE = 64 }; +enum { QEMU_VMI_COOKIE_HASH_SIZE = 20}; + +/** + * qemu_vmi_to_introspector: + * + * This structure is passed to the introspection tool during the handshake. + * + * @struct_size: the structure size + * @uuid: the UUID + * @start_time: the VM start time + * @name: the VM name + */ +typedef struct qemu_vmi_to_introspector { + uint32_t struct_size; + uint8_t uuid[16]; + uint32_t padding; + int64_t start_time; + char name[QEMU_VMI_NAME_SIZE]; + /* ... */ +} qemu_vmi_to_introspector; + +/** + * qemu_vmi_from_introspector: + * + * This structure is passed by the introspection tool during the handshake. + * + * @struct_size: the structure size + * @cookie_hash: the hash of the cookie know by the introspection tool + */ +typedef struct qemu_vmi_from_introspector { + uint32_t struct_size; + uint8_t cookie_hash[QEMU_VMI_COOKIE_HASH_SIZE]; + /* ... */ +} qemu_vmi_from_introspector; + +#endif /* QEMU_VMI_HANDSHAKE_H */ From patchwork Wed Apr 15 00:59:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284354 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01793C2BB1D for ; Wed, 15 Apr 2020 01:11:31 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C67B320732 for ; Wed, 15 Apr 2020 01:11:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C67B320732 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40984 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWaP-0005c8-VC for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:11:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58435) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWP9-0001Hi-2a for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP7-0005Bd-MF for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:50 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49088) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP7-00050x-9E for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:49 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 2809C30747C9 for ; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 148FB305B7A2; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 11/26] kvm: vmi: add 'handshake_timeout' property Date: Wed, 15 Apr 2020 03:59:23 +0300 Message-Id: <20200415005938.23895-12-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" By having a timer during handshake, the blocked connections can be restored. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 57ded2f69c..5659663caa 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -19,6 +19,8 @@ #include "sysemu/vmi-handshake.h" +#define HANDSHAKE_TIMEOUT_SEC 10 + typedef struct VMIntrospection { Object parent_obj; @@ -32,6 +34,8 @@ typedef struct VMIntrospection { qemu_vmi_from_introspector hsk_in; uint64_t hsk_in_read_pos; uint64_t hsk_in_read_size; + GSource *hsk_timer; + uint32_t handshake_timeout; int64_t vm_start_time; @@ -105,6 +109,26 @@ static void prop_set_chardev(Object *obj, const char *value, Error **errp) i->chardevid = g_strdup(value); } +static void prop_get_uint32(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t *value = opaque; + + visit_type_uint32(v, name, value, errp); +} + +static void prop_set_uint32(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + uint32_t *value = opaque; + Error *local_err = NULL; + + visit_type_uint32(v, name, value, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } +} + static bool chardev_is_connected(VMIntrospection *i, Error **errp) { Object *obj = OBJECT(i->chr); @@ -129,6 +153,11 @@ static void instance_init(Object *obj) update_vm_start_time(i); object_property_add_str(obj, "chardev", NULL, prop_set_chardev, NULL); + + i->handshake_timeout = HANDSHAKE_TIMEOUT_SEC; + object_property_add(obj, "handshake_timeout", "uint32", + prop_set_uint32, prop_get_uint32, + NULL, &i->handshake_timeout, NULL); } static void disconnect_chardev(VMIntrospection *i) @@ -165,12 +194,28 @@ static void disconnect_and_unhook_kvmi(VMIntrospection *i) unhook_kvmi(i); } +static void cancel_timer(GSource *timer) +{ + if (timer) { + g_source_destroy(timer); + g_source_unref(timer); + } +} + +static void cancel_handshake_timer(VMIntrospection *i) +{ + cancel_timer(i->hsk_timer); + i->hsk_timer = NULL; +} + static void instance_finalize(Object *obj) { VMIntrospection *i = VM_INTROSPECTION(obj); g_free(i->chardevid); + cancel_handshake_timer(i); + if (i->chr) { shutdown_socket_fd(i); qemu_chr_fe_deinit(&i->sock, true); @@ -303,7 +348,7 @@ static int chr_can_read(void *opaque) { VMIntrospection *i = opaque; - if (i->sock_fd == -1) { + if (i->hsk_timer == NULL || i->sock_fd == -1) { return 0; } @@ -356,10 +401,24 @@ static void chr_read(void *opaque, const uint8_t *buf, int size) } if (enough_bytes_for_handshake(i)) { + cancel_handshake_timer(i); validate_and_connect(i); } } +static gboolean chr_timeout(gpointer opaque) +{ + VMIntrospection *i = opaque; + + warn_report("VMI: the handshake takes too long"); + + g_source_unref(i->hsk_timer); + i->hsk_timer = NULL; + + disconnect_and_unhook_kvmi(i); + return FALSE; +} + static void chr_event_open(VMIntrospection *i) { Error *local_err = NULL; @@ -378,6 +437,9 @@ static void chr_event_open(VMIntrospection *i) memset(&i->hsk_in, 0, sizeof(i->hsk_in)); i->hsk_in_read_pos = 0; i->hsk_in_read_size = 0; + i->hsk_timer = qemu_chr_timeout_add_ms(i->chr, + i->handshake_timeout * 1000, + chr_timeout, i); } static void chr_event_close(VMIntrospection *i) @@ -386,6 +448,8 @@ static void chr_event_close(VMIntrospection *i) warn_report("VMI: introspection tool disconnected"); disconnect_and_unhook_kvmi(i); } + + cancel_handshake_timer(i); } static void chr_event(void *opaque, QEMUChrEvent event) From patchwork Wed Apr 15 00:59:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284359 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 63C93C2BB1D for ; Wed, 15 Apr 2020 01:01:43 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 348882072D for ; Wed, 15 Apr 2020 01:01:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 348882072D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40884 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWQw-00034i-9a for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:01:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58354) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWOy-0000vs-IE for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWOx-00051u-GE for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:40 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49092) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWOx-000511-7t for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:39 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 50B2930747CC for ; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 3F091305B7A4; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 13/26] kvm: vmi: block the object destruction if the chardev is connected Date: Wed, 15 Apr 2020 03:59:25 +0300 Message-Id: <20200415005938.23895-14-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The introspection tool can modify the VM while it is running (e.g. it can set breakpoints), and when the VM is no longer introspected these changes need to be removed. Until then, we block the destruction of the introspection object that would lead to the unexpected shutdown of the introspection channel. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index f456ca56ef..2ce8a60565 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -151,11 +151,19 @@ static bool chardev_is_connected(VMIntrospection *i, Error **errp) return obj && object_property_get_bool(obj, "connected", errp); } +static bool introspection_can_be_deleted(UserCreatable *uc) +{ + VMIntrospection *i = VM_INTROSPECTION(uc); + + return !chardev_is_connected(i, NULL); +} + static void class_init(ObjectClass *oc, void *data) { UserCreatableClass *uc = USER_CREATABLE_CLASS(oc); uc->complete = complete; + uc->can_be_deleted = introspection_can_be_deleted; } static void instance_init(Object *obj) From patchwork Wed Apr 15 00:59:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284357 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C08F0C2BB1D for ; Wed, 15 Apr 2020 01:05:14 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 916E72072D for ; Wed, 15 Apr 2020 01:05:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 916E72072D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40916 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWUL-0006d7-Ij for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:05:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58426) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWP8-0001Gx-Nv for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP7-0005BN-GO for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:50 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49094) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP7-000512-8k for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:49 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 65CA930747CD for ; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 54760305B7A0; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 14/26] kvm: vmi: allow only one instance of the introspection object Date: Wed, 15 Apr 2020 03:59:26 +0300 Message-Id: <20200415005938.23895-15-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Because only one introspection tool must introspect a VM at a given time, we block the completion of the second instance. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 2ce8a60565..54c56c6e13 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -52,10 +52,18 @@ typedef struct VMIntrospection { bool kvmi_hooked; } VMIntrospection; +typedef struct VMIntrospectionClass { + ObjectClass parent_class; + uint32_t instance_counter; + VMIntrospection *uniq; +} VMIntrospectionClass; + #define TYPE_VM_INTROSPECTION "introspection" #define VM_INTROSPECTION(obj) \ OBJECT_CHECK(VMIntrospection, (obj), TYPE_VM_INTROSPECTION) +#define VM_INTROSPECTION_CLASS(class) \ + OBJECT_CLASS_CHECK(VMIntrospectionClass, (class), TYPE_VM_INTROSPECTION) static Error *vm_introspection_init(VMIntrospection *i); @@ -81,8 +89,14 @@ static void update_vm_start_time(VMIntrospection *i) static void complete(UserCreatable *uc, Error **errp) { + VMIntrospectionClass *ic = VM_INTROSPECTION_CLASS(OBJECT(uc)->class); VMIntrospection *i = VM_INTROSPECTION(uc); + if (ic->instance_counter > 1) { + error_setg(errp, "VMI: only one introspection object can be created"); + return; + } + if (!i->chardevid) { error_setg(errp, "VMI: chardev is not set"); return; @@ -106,6 +120,8 @@ static void complete(UserCreatable *uc, Error **errp) i->init_error = NULL; return; } + + ic->uniq = i; } static void prop_set_chardev(Object *obj, const char *value, Error **errp) @@ -168,8 +184,11 @@ static void class_init(ObjectClass *oc, void *data) static void instance_init(Object *obj) { + VMIntrospectionClass *ic = VM_INTROSPECTION_CLASS(obj->class); VMIntrospection *i = VM_INTROSPECTION(obj); + ic->instance_counter++; + i->sock_fd = -1; i->created_from_command_line = (qdev_hotplug == false); @@ -234,6 +253,7 @@ static void cancel_handshake_timer(VMIntrospection *i) static void instance_finalize(Object *obj) { + VMIntrospectionClass *ic = VM_INTROSPECTION_CLASS(obj->class); VMIntrospection *i = VM_INTROSPECTION(obj); g_free(i->chardevid); @@ -248,12 +268,18 @@ static void instance_finalize(Object *obj) } error_free(i->init_error); + + ic->instance_counter--; + if (!ic->instance_counter) { + ic->uniq = NULL; + } } static const TypeInfo info = { .name = TYPE_VM_INTROSPECTION, .parent = TYPE_OBJECT, .class_init = class_init, + .class_size = sizeof(VMIntrospectionClass), .instance_size = sizeof(VMIntrospection), .instance_finalize = instance_finalize, .instance_init = instance_init, From patchwork Wed Apr 15 00:59:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284355 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E4E67C2BB1D for ; Wed, 15 Apr 2020 01:08:53 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B49862072D for ; Wed, 15 Apr 2020 01:08:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B49862072D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40952 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWXr-0002DR-Rs for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:08:51 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58477) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPA-0001Kf-6f for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP8-0005Bu-QT for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:52 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49096) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052I-Hl for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:50 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 7E08530747CE; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 6A050305B7A5; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 15/26] kvm: vmi: reconnect the socket on reset Date: Wed, 15 Apr 2020 03:59:27 +0300 Message-Id: <20200415005938.23895-16-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , Marian Rotariu Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Marian Rotariu The guest could be reset from various reasons and by disconnecting the socket (which would reconnect), KVM and the introspection tool will be notified and can clean up the introspection structures. Signed-off-by: Marian Rotariu Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 54c56c6e13..5beec2b091 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -13,6 +13,7 @@ #include "qemu/error-report.h" #include "qom/object_interfaces.h" #include "sysemu/sysemu.h" +#include "sysemu/reset.h" #include "sysemu/kvm.h" #include "crypto/secret.h" #include "crypto/hash.h" @@ -66,6 +67,7 @@ typedef struct VMIntrospectionClass { OBJECT_CLASS_CHECK(VMIntrospectionClass, (class), TYPE_VM_INTROSPECTION) static Error *vm_introspection_init(VMIntrospection *i); +static void vm_introspection_reset(void *opaque); static void machine_ready(Notifier *notifier, void *data) { @@ -122,6 +124,8 @@ static void complete(UserCreatable *uc, Error **errp) } ic->uniq = i; + + qemu_register_reset(vm_introspection_reset, i); } static void prop_set_chardev(Object *obj, const char *value, Error **errp) @@ -273,6 +277,8 @@ static void instance_finalize(Object *obj) if (!ic->instance_counter) { ic->uniq = NULL; } + + qemu_unregister_reset(vm_introspection_reset, i); } static const TypeInfo info = { @@ -534,6 +540,18 @@ static void chr_event(void *opaque, QEMUChrEvent event) } } +static void vm_introspection_reset(void *opaque) +{ + VMIntrospection *i = opaque; + + if (i->sock_fd != -1) { + info_report("VMI: Reset detected. Closing the socket..."); + disconnect_and_unhook_kvmi(i); + } + + update_vm_start_time(i); +} + static bool make_cookie_hash(const char *key_id, uint8_t *cookie_hash, Error **errp) { From patchwork Wed Apr 15 00:59:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284348 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 39AC2C2BB1D for ; Wed, 15 Apr 2020 01:18:44 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 116B4214AF for ; Wed, 15 Apr 2020 01:18:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 116B4214AF Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41097 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWhP-0000KF-8w for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:18:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58505) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPB-0001NF-88 for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP9-0005CN-2n for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:53 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49098) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052H-HW for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:50 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id A96CA30747D2; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 80EC9305B7A1; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 16/26] kvm: vmi: intercept pause/resume Date: Wed, 15 Apr 2020 03:59:28 +0300 Message-Id: <20200415005938.23895-17-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , Marian Rotariu , Markus Armbruster Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Marian Rotariu Because the introspection tool can run on another VM, suspending either of these two VMs requires signaling the introspection tool to remove any changes made to the introspected VM. This is done through the KVM_INTROSPECTION_PREUNHOOK ioctl. KVM will send an event through the introspection socket, if active. QEMU will wait for the introspection tool to let the VM run without being introspected and close the socket. While the guest is suspended, the socket reconnection is disabled. CC: Markus Armbruster Signed-off-by: Marian Rotariu Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 147 +++++++++++++++++++++++++++++++++ accel/stubs/Makefile.objs | 1 + accel/stubs/vmi-stubs.c | 7 ++ include/sysemu/vmi-intercept.h | 21 +++++ monitor/qmp-cmds.c | 10 +++ 5 files changed, 186 insertions(+) create mode 100644 accel/stubs/vmi-stubs.c create mode 100644 include/sysemu/vmi-intercept.h diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 5beec2b091..151e27265a 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -14,12 +14,14 @@ #include "qom/object_interfaces.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" +#include "sysemu/runstate.h" #include "sysemu/kvm.h" #include "crypto/secret.h" #include "crypto/hash.h" #include "chardev/char.h" #include "chardev/char-fe.h" +#include "sysemu/vmi-intercept.h" #include "sysemu/vmi-handshake.h" #define HANDSHAKE_TIMEOUT_SEC 10 @@ -45,6 +47,10 @@ typedef struct VMIntrospection { GSource *hsk_timer; uint32_t handshake_timeout; + int intercepted_action; + + int reconnect_time; + int64_t vm_start_time; Notifier machine_ready; @@ -59,6 +65,14 @@ typedef struct VMIntrospectionClass { VMIntrospection *uniq; } VMIntrospectionClass; +static const char *action_string[] = { + "none", + "suspend", + "resume", +}; + +static bool suspend_pending; + #define TYPE_VM_INTROSPECTION "introspection" #define VM_INTROSPECTION(obj) \ @@ -412,6 +426,39 @@ static bool connect_kernel(VMIntrospection *i, Error **errp) return true; } +static void enable_socket_reconnect(VMIntrospection *i) +{ + if (i->sock_fd == -1 && i->reconnect_time) { + qemu_chr_fe_reconnect_time(&i->sock, i->reconnect_time); + qemu_chr_fe_disconnect(&i->sock); + i->reconnect_time = 0; + } +} + +static void maybe_disable_socket_reconnect(VMIntrospection *i) +{ + if (i->reconnect_time == 0) { + info_report("VMI: disable socket reconnect"); + i->reconnect_time = qemu_chr_fe_reconnect_time(&i->sock, 0); + } +} + +static void continue_with_the_intercepted_action(VMIntrospection *i) +{ + switch (i->intercepted_action) { + case VMI_INTERCEPT_SUSPEND: + vm_stop(RUN_STATE_PAUSED); + break; + default: + error_report("VMI: %s: unexpected action %d", + __func__, i->intercepted_action); + break; + } + + info_report("VMI: continue with '%s'", + action_string[i->intercepted_action]); +} + /* * We should read only the handshake structure, * which might have a different size than what we expect. @@ -495,6 +542,14 @@ static void chr_event_open(VMIntrospection *i) { Error *local_err = NULL; + if (suspend_pending) { + info_report("VMI: %s: too soon (suspend=%d)", + __func__, suspend_pending); + maybe_disable_socket_reconnect(i); + qemu_chr_fe_disconnect(&i->sock); + return; + } + if (!send_handshake_info(i, &local_err)) { error_append_hint(&local_err, "reconnecting\n"); warn_report_err(local_err); @@ -522,6 +577,15 @@ static void chr_event_close(VMIntrospection *i) } cancel_handshake_timer(i); + + if (suspend_pending) { + maybe_disable_socket_reconnect(i); + + if (i->intercepted_action != VMI_INTERCEPT_NONE) { + continue_with_the_intercepted_action(i); + i->intercepted_action = VMI_INTERCEPT_NONE; + } + } } static void chr_event(void *opaque, QEMUChrEvent event) @@ -540,6 +604,89 @@ static void chr_event(void *opaque, QEMUChrEvent event) } } +static VMIntrospection *vm_introspection_object(void) +{ + VMIntrospectionClass *ic; + + ic = VM_INTROSPECTION_CLASS(object_class_by_name(TYPE_VM_INTROSPECTION)); + + return ic ? ic->uniq : NULL; +} + +/* + * This ioctl succeeds only when KVM signals the introspection tool. + * (the socket is connected and the event was sent without error). + */ +static bool signal_introspection_tool_to_unhook(VMIntrospection *i) +{ + int err; + + err = kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_PREUNHOOK, NULL); + + return !err; +} + +static bool record_intercept_action(VMI_intercept_command action) +{ + switch (action) { + case VMI_INTERCEPT_SUSPEND: + suspend_pending = true; + break; + case VMI_INTERCEPT_RESUME: + suspend_pending = false; + break; + default: + return false; + } + + return true; +} + +static bool intercept_action(VMIntrospection *i, + VMI_intercept_command action, Error **errp) +{ + if (i->intercepted_action != VMI_INTERCEPT_NONE) { + error_report("VMI: unhook in progress"); + return false; + } + + switch (action) { + case VMI_INTERCEPT_RESUME: + enable_socket_reconnect(i); + return false; + default: + break; + } + + if (!signal_introspection_tool_to_unhook(i)) { + disconnect_and_unhook_kvmi(i); + return false; + } + + i->intercepted_action = action; + return true; +} + +bool vm_introspection_intercept(VMI_intercept_command action, Error **errp) +{ + VMIntrospection *i = vm_introspection_object(); + bool intercepted = false; + + info_report("VMI: intercept command: %s", + action < ARRAY_SIZE(action_string) + ? action_string[action] + : "unknown"); + + if (record_intercept_action(action) && i) { + intercepted = intercept_action(i, action, errp); + } + + info_report("VMI: intercept action: %s", + intercepted ? "delayed" : "continue"); + + return intercepted; +} + static void vm_introspection_reset(void *opaque) { VMIntrospection *i = opaque; diff --git a/accel/stubs/Makefile.objs b/accel/stubs/Makefile.objs index 3894caf95d..fcec6edf0f 100644 --- a/accel/stubs/Makefile.objs +++ b/accel/stubs/Makefile.objs @@ -2,4 +2,5 @@ obj-$(call lnot,$(CONFIG_HAX)) += hax-stub.o obj-$(call lnot,$(CONFIG_HVF)) += hvf-stub.o obj-$(call lnot,$(CONFIG_WHPX)) += whpx-stub.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o +obj-$(call lnot,$(CONFIG_KVM)) += vmi-stubs.o obj-$(call lnot,$(CONFIG_TCG)) += tcg-stub.o diff --git a/accel/stubs/vmi-stubs.c b/accel/stubs/vmi-stubs.c new file mode 100644 index 0000000000..1bd93b2ca5 --- /dev/null +++ b/accel/stubs/vmi-stubs.c @@ -0,0 +1,7 @@ +#include "qemu/osdep.h" +#include "sysemu/vmi-intercept.h" + +bool vm_introspection_intercept(VMI_intercept_command ic, Error **errp) +{ + return false; +} diff --git a/include/sysemu/vmi-intercept.h b/include/sysemu/vmi-intercept.h new file mode 100644 index 0000000000..06998ff18a --- /dev/null +++ b/include/sysemu/vmi-intercept.h @@ -0,0 +1,21 @@ +/* + * QEMU VM Introspection + * + * Copyright (C) 2018-2020 Bitdefender S.R.L. + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef QEMU_VMI_INTERCEPT_H +#define QEMU_VMI_INTERCEPT_H + +typedef enum { + VMI_INTERCEPT_NONE = 0, + VMI_INTERCEPT_SUSPEND, + VMI_INTERCEPT_RESUME, +} VMI_intercept_command; + +bool vm_introspection_intercept(VMI_intercept_command ic, Error **errp); + +#endif /* QEMU_VMI_INTERCEPT_H */ diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index 864cbfa32e..eabd20fca3 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -39,6 +39,8 @@ #include "hw/mem/memory-device.h" #include "hw/acpi/acpi_dev_interface.h" +#include "sysemu/vmi-intercept.h" + NameInfo *qmp_query_name(Error **errp) { NameInfo *info = g_malloc0(sizeof(*info)); @@ -87,6 +89,9 @@ void qmp_stop(Error **errp) if (runstate_check(RUN_STATE_INMIGRATE)) { autostart = 0; } else { + if (vm_introspection_intercept(VMI_INTERCEPT_SUSPEND, errp)) { + return; + } vm_stop(RUN_STATE_PAUSED); } } @@ -158,6 +163,11 @@ void qmp_cont(Error **errp) autostart = 1; } else { vm_start(); + /* + * this interception is post-event as we might need the vm to run before + * doing the interception, therefore we do not need the return value. + */ + vm_introspection_intercept(VMI_INTERCEPT_RESUME, errp); } } From patchwork Wed Apr 15 00:59:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284353 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9CEF2C2BB1D for ; Wed, 15 Apr 2020 01:11:45 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6BFE720732 for ; Wed, 15 Apr 2020 01:11:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6BFE720732 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40988 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWae-00063D-Hq for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:11:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58494) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPA-0001Lk-Ld for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP9-0005Ce-5K for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:52 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49102) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052P-J0 for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:50 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id BCBB630747D3 for ; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id AC5CE305B7A0; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 17/26] kvm: vmi: add 'unhook_timeout' property Date: Wed, 15 Apr 2020 03:59:29 +0300 Message-Id: <20200415005938.23895-18-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" When the introspection tool has to remove all changes made to the introspected VM, the guest must run because some hooks can be removed only in certain conditions. But this shouldn't take too long even with a host under heavy load. So, if the socket is not closed by the introspection tool at the end of this unhook process in the time specified by the unhook_timeout property, QEMU will shutdown the socket. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 151e27265a..1f3aff3bfe 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -25,6 +25,7 @@ #include "sysemu/vmi-handshake.h" #define HANDSHAKE_TIMEOUT_SEC 10 +#define UNHOOK_TIMEOUT_SEC 60 typedef struct VMIntrospection { Object parent_obj; @@ -48,6 +49,8 @@ typedef struct VMIntrospection { uint32_t handshake_timeout; int intercepted_action; + GSource *unhook_timer; + uint32_t unhook_timeout; int reconnect_time; @@ -219,6 +222,11 @@ static void instance_init(Object *obj) object_property_add(obj, "handshake_timeout", "uint32", prop_set_uint32, prop_get_uint32, NULL, &i->handshake_timeout, NULL); + + i->unhook_timeout = UNHOOK_TIMEOUT_SEC; + object_property_add(obj, "unhook_timeout", "uint32", + prop_set_uint32, prop_get_uint32, + NULL, &i->unhook_timeout, NULL); } static void disconnect_chardev(VMIntrospection *i) @@ -269,6 +277,12 @@ static void cancel_handshake_timer(VMIntrospection *i) i->hsk_timer = NULL; } +static void cancel_unhook_timer(VMIntrospection *i) +{ + cancel_timer(i->unhook_timer); + i->unhook_timer = NULL; +} + static void instance_finalize(Object *obj) { VMIntrospectionClass *ic = VM_INTROSPECTION_CLASS(obj->class); @@ -277,6 +291,7 @@ static void instance_finalize(Object *obj) g_free(i->chardevid); g_free(i->keyid); + cancel_unhook_timer(i); cancel_handshake_timer(i); if (i->chr) { @@ -576,6 +591,7 @@ static void chr_event_close(VMIntrospection *i) disconnect_and_unhook_kvmi(i); } + cancel_unhook_timer(i); cancel_handshake_timer(i); if (suspend_pending) { @@ -604,6 +620,19 @@ static void chr_event(void *opaque, QEMUChrEvent event) } } +static gboolean unhook_timeout_cbk(gpointer opaque) +{ + VMIntrospection *i = opaque; + + warn_report("VMI: the introspection tool is too slow"); + + g_source_unref(i->unhook_timer); + i->unhook_timer = NULL; + + disconnect_and_unhook_kvmi(i); + return FALSE; +} + static VMIntrospection *vm_introspection_object(void) { VMIntrospectionClass *ic; @@ -663,6 +692,10 @@ static bool intercept_action(VMIntrospection *i, return false; } + i->unhook_timer = qemu_chr_timeout_add_ms(i->chr, + i->unhook_timeout * 1000, + unhook_timeout_cbk, i); + i->intercepted_action = action; return true; } From patchwork Wed Apr 15 00:59:31 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284352 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6DA76C2BB1D for ; Wed, 15 Apr 2020 01:13:28 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 23D2420732 for ; Wed, 15 Apr 2020 01:13:28 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 23D2420732 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41008 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWcJ-0001CV-53 for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:13:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58484) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPA-0001L6-Cv for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP8-0005C6-SX for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:52 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49104) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052R-JG for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:50 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id EBB1E30747D5; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id D6C48305B7A3; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 19/26] kvm: vmi: intercept force-reset Date: Wed, 15 Apr 2020 03:59:31 +0300 Message-Id: <20200415005938.23895-20-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , Marian Rotariu , Markus Armbruster Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Marian Rotariu On forced reset, KVM and the instrospection tool must clean-up the introspection structures. An important thing that must by done by KVM is to unlink the shared memory pages (the introspection tool can map memory pages from the introspected VM in its own process/VM). CC: Markus Armbruster Signed-off-by: Marian Rotariu Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 6 ++++++ include/sysemu/vmi-intercept.h | 2 ++ monitor/qmp-cmds.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index e511558f3d..90906478b4 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -73,6 +73,7 @@ static const char *action_string[] = { "none", "suspend", "resume", + "force-reset", }; static bool suspend_pending; @@ -677,6 +678,8 @@ static bool record_intercept_action(VMI_intercept_command action) case VMI_INTERCEPT_RESUME: suspend_pending = false; break; + case VMI_INTERCEPT_FORCE_RESET: + break; default: return false; } @@ -693,6 +696,9 @@ static bool intercept_action(VMIntrospection *i, } switch (action) { + case VMI_INTERCEPT_FORCE_RESET: + disconnect_and_unhook_kvmi(i); + return false; case VMI_INTERCEPT_RESUME: enable_socket_reconnect(i); return false; diff --git a/include/sysemu/vmi-intercept.h b/include/sysemu/vmi-intercept.h index 06998ff18a..ef591b49e7 100644 --- a/include/sysemu/vmi-intercept.h +++ b/include/sysemu/vmi-intercept.h @@ -14,8 +14,10 @@ typedef enum { VMI_INTERCEPT_NONE = 0, VMI_INTERCEPT_SUSPEND, VMI_INTERCEPT_RESUME, + VMI_INTERCEPT_FORCE_RESET, } VMI_intercept_command; bool vm_introspection_intercept(VMI_intercept_command ic, Error **errp); +bool vm_introspection_qmp_delay(void *mon, QObject *id, bool resume); #endif /* QEMU_VMI_INTERCEPT_H */ diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c index eabd20fca3..d164635b5f 100644 --- a/monitor/qmp-cmds.c +++ b/monitor/qmp-cmds.c @@ -98,6 +98,10 @@ void qmp_stop(Error **errp) void qmp_system_reset(Error **errp) { + if (vm_introspection_intercept(VMI_INTERCEPT_FORCE_RESET, errp)) { + return; + } + qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET); } From patchwork Wed Apr 15 00:59:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284351 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9F468C352BE for ; Wed, 15 Apr 2020 01:13:34 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 76C7720732 for ; Wed, 15 Apr 2020 01:13:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 76C7720732 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41012 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWcP-0001Si-Id for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:13:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58559) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPC-0001RE-BP for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP9-0005Cp-5D for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:54 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49106) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052Q-Ih for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:51 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 165A53074838; Wed, 15 Apr 2020 03:59:36 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id EE47F305B7A4; Wed, 15 Apr 2020 03:59:35 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 20/26] kvm: vmi: intercept live migration Date: Wed, 15 Apr 2020 03:59:32 +0300 Message-Id: <20200415005938.23895-21-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= , Marian Rotariu , "Dr. David Alan Gilbert" , Juan Quintela Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Marian Rotariu It is possible that the introspection tool has made some changes inside the introspected VM which can make the guest crash if the introspection connection is suddenly closed. When the live migration starts, for now, the introspection tool is signaled to remove its hooks from the introspected VM. CC: Juan Quintela CC: "Dr. David Alan Gilbert" Signed-off-by: Marian Rotariu Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 31 +++++++++++++++++++++++++++---- include/sysemu/vmi-intercept.h | 1 + migration/migration.c | 18 +++++++++++++++--- migration/migration.h | 2 ++ 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 90906478b4..ea7191e48d 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -21,6 +21,8 @@ #include "chardev/char.h" #include "chardev/char-fe.h" #include "migration/vmstate.h" +#include "migration/migration.h" +#include "migration/misc.h" #include "sysemu/vmi-intercept.h" #include "sysemu/vmi-handshake.h" @@ -58,6 +60,7 @@ typedef struct VMIntrospection { int64_t vm_start_time; Notifier machine_ready; + Notifier migration_state_change; bool created_from_command_line; bool kvmi_hooked; @@ -74,9 +77,11 @@ static const char *action_string[] = { "suspend", "resume", "force-reset", + "migrate", }; static bool suspend_pending; +static bool migrate_pending; #define TYPE_VM_INTROSPECTION "introspection" @@ -88,6 +93,15 @@ static bool suspend_pending; static Error *vm_introspection_init(VMIntrospection *i); static void vm_introspection_reset(void *opaque); +static void migration_state_notifier(Notifier *notifier, void *data) +{ + MigrationState *s = data; + + if (migration_has_failed(s)) { + migrate_pending = false; + } +} + static void machine_ready(Notifier *notifier, void *data) { VMIntrospection *i = container_of(notifier, VMIntrospection, machine_ready); @@ -144,6 +158,9 @@ static void complete(UserCreatable *uc, Error **errp) ic->uniq = i; + i->migration_state_change.notify = migration_state_notifier; + add_migration_state_change_notifier(&i->migration_state_change); + qemu_register_reset(vm_introspection_reset, i); } @@ -478,6 +495,9 @@ static void continue_with_the_intercepted_action(VMIntrospection *i) case VMI_INTERCEPT_SUSPEND: vm_stop(RUN_STATE_PAUSED); break; + case VMI_INTERCEPT_MIGRATE: + start_live_migration_thread(migrate_get_current()); + break; default: error_report("VMI: %s: unexpected action %d", __func__, i->intercepted_action); @@ -571,9 +591,9 @@ static void chr_event_open(VMIntrospection *i) { Error *local_err = NULL; - if (suspend_pending) { - info_report("VMI: %s: too soon (suspend=%d)", - __func__, suspend_pending); + if (suspend_pending || migrate_pending) { + info_report("VMI: %s: too soon (suspend=%d, migrate=%d)", + __func__, suspend_pending, migrate_pending); maybe_disable_socket_reconnect(i); qemu_chr_fe_disconnect(&i->sock); return; @@ -608,7 +628,7 @@ static void chr_event_close(VMIntrospection *i) cancel_unhook_timer(i); cancel_handshake_timer(i); - if (suspend_pending) { + if (suspend_pending || migrate_pending) { maybe_disable_socket_reconnect(i); if (i->intercepted_action != VMI_INTERCEPT_NONE) { @@ -680,6 +700,9 @@ static bool record_intercept_action(VMI_intercept_command action) break; case VMI_INTERCEPT_FORCE_RESET: break; + case VMI_INTERCEPT_MIGRATE: + migrate_pending = true; + break; default: return false; } diff --git a/include/sysemu/vmi-intercept.h b/include/sysemu/vmi-intercept.h index ef591b49e7..b4a9a3faa7 100644 --- a/include/sysemu/vmi-intercept.h +++ b/include/sysemu/vmi-intercept.h @@ -15,6 +15,7 @@ typedef enum { VMI_INTERCEPT_SUSPEND, VMI_INTERCEPT_RESUME, VMI_INTERCEPT_FORCE_RESET, + VMI_INTERCEPT_MIGRATE, } VMI_intercept_command; bool vm_introspection_intercept(VMI_intercept_command ic, Error **errp); diff --git a/migration/migration.c b/migration/migration.c index 187ac0410c..222037d739 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -55,6 +55,8 @@ #include "qemu/queue.h" #include "multifd.h" +#include "sysemu/vmi-intercept.h" + #define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */ /* Amount of time to allocate to each "chunk" of bandwidth-throttled @@ -3471,6 +3473,13 @@ static void *migration_thread(void *opaque) return NULL; } +void start_live_migration_thread(MigrationState *s) +{ + qemu_thread_create(&s->thread, "live_migration", migration_thread, s, + QEMU_THREAD_JOINABLE); + s->migration_thread_running = true; +} + void migrate_fd_connect(MigrationState *s, Error *error_in) { Error *local_err = NULL; @@ -3534,9 +3543,12 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) migrate_fd_cleanup(s); return; } - qemu_thread_create(&s->thread, "live_migration", migration_thread, s, - QEMU_THREAD_JOINABLE); - s->migration_thread_running = true; + + if (vm_introspection_intercept(VMI_INTERCEPT_MIGRATE, &error_in)) { + return; + } + + start_live_migration_thread(s); } void migration_global_dump(Monitor *mon) diff --git a/migration/migration.h b/migration/migration.h index 507284e563..eb5668e1f2 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -263,6 +263,8 @@ struct MigrationState uint8_t clear_bitmap_shift; }; +void start_live_migration_thread(MigrationState *s); + void migrate_set_state(int *state, int old_state, int new_state); void migration_fd_process_incoming(QEMUFile *f, Error **errp); From patchwork Wed Apr 15 00:59:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284350 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD6D7C38A29 for ; Wed, 15 Apr 2020 01:15:08 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A50B32076C for ; Wed, 15 Apr 2020 01:15:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A50B32076C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41034 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWdv-0004dd-Rp for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:15:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58485) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPA-0001L8-EN for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP9-0005CY-3z for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:52 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49110) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052b-Mg for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:51 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 3AA83307483A for ; Wed, 15 Apr 2020 03:59:36 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 2B115305B7A1; Wed, 15 Apr 2020 03:59:36 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 22/26] kvm: vmi: add 'async_unhook' property Date: Wed, 15 Apr 2020 03:59:34 +0300 Message-Id: <20200415005938.23895-23-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The default method to handle the intercepted commands (pause/suspend/migrate) might not be the simplest method. We add an alternative method, used when async_unhook is set to false, that runs the main loop until the introspection tool finish the unhook process and closes the introspection socket. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index 01034d460e..bee9798e54 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -57,6 +57,7 @@ typedef struct VMIntrospection { int intercepted_action; GSource *unhook_timer; uint32_t unhook_timeout; + bool async_unhook; int reconnect_time; @@ -186,6 +187,20 @@ static void prop_set_key(Object *obj, const char *value, Error **errp) i->keyid = g_strdup(value); } +static bool prop_get_async_unhook(Object *obj, Error **errp) +{ + VMIntrospection *i = VM_INTROSPECTION(obj); + + return i->async_unhook; +} + +static void prop_set_async_unhook(Object *obj, bool value, Error **errp) +{ + VMIntrospection *i = VM_INTROSPECTION(obj); + + i->async_unhook = value; +} + static void prop_get_uint32(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -263,6 +278,11 @@ static void instance_init(Object *obj) prop_set_uint32, prop_get_uint32, NULL, &i->unhook_timeout, NULL); + i->async_unhook = true; + object_property_add_bool(obj, "async_unhook", + prop_get_async_unhook, + prop_set_async_unhook, NULL); + vmstate_register(NULL, 0, &vmstate_introspection, i); } @@ -739,6 +759,19 @@ static bool record_intercept_action(VMI_intercept_command action) return true; } +static void wait_until_the_socket_is_closed(VMIntrospection *i) +{ + info_report("VMI: start waiting until fd=%d is closed", i->sock_fd); + + while (i->sock_fd != -1) { + main_loop_wait(false); + } + + info_report("VMI: continue with the intercepted action fd=%d", i->sock_fd); + + maybe_disable_socket_reconnect(i); +} + static bool intercept_action(VMIntrospection *i, VMI_intercept_command action, Error **errp) { @@ -767,6 +800,11 @@ static bool intercept_action(VMIntrospection *i, i->unhook_timeout * 1000, unhook_timeout_cbk, i); + if (!i->async_unhook) { + wait_until_the_socket_is_closed(i); + return false; + } + i->intercepted_action = action; return true; } From patchwork Wed Apr 15 00:59:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Adalbert_Laz=C4=83r?= X-Patchwork-Id: 284347 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05AF1C2BB1D for ; Wed, 15 Apr 2020 01:21:32 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BD0522087E for ; Wed, 15 Apr 2020 01:21:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BD0522087E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=bitdefender.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41136 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWk6-0003s3-Tz for qemu-devel@archiver.kernel.org; Tue, 14 Apr 2020 21:21:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58571) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jOWPD-0001TS-1O for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jOWP9-0005DE-Bc for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:54 -0400 Received: from mx01.bbu.dsd.mx.bitdefender.com ([91.199.104.161]:49118) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1jOWP8-00052o-Rg for qemu-devel@nongnu.org; Tue, 14 Apr 2020 20:59:51 -0400 Received: from smtp.bitdefender.com (smtp02.buh.bitdefender.net [10.17.80.76]) by mx01.bbu.dsd.mx.bitdefender.com (Postfix) with ESMTPS id 8C91A3074898 for ; Wed, 15 Apr 2020 03:59:36 +0300 (EEST) Received: from localhost.localdomain (unknown [91.199.104.27]) by smtp.bitdefender.com (Postfix) with ESMTPSA id 7D8F1305B7A0; Wed, 15 Apr 2020 03:59:36 +0300 (EEST) From: =?utf-8?q?Adalbert_Laz=C4=83r?= To: qemu-devel@nongnu.org Subject: [RFC PATCH v1 26/26] kvm: vmi: add 'command' and 'event' properties Date: Wed, 15 Apr 2020 03:59:38 +0300 Message-Id: <20200415005938.23895-27-alazar@bitdefender.com> In-Reply-To: <20200415005938.23895-1-alazar@bitdefender.com> References: <20200415005938.23895-1-alazar@bitdefender.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 91.199.104.161 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?utf-8?q?Adalbert_Laz=C4=83r?= Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" There are cases when the access to an introspected VM must be limited to certain introspection commands/events. Signed-off-by: Adalbert Lazăr --- accel/kvm/vmi.c | 86 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/accel/kvm/vmi.c b/accel/kvm/vmi.c index f70d78848a..1574a643c4 100644 --- a/accel/kvm/vmi.c +++ b/accel/kvm/vmi.c @@ -73,6 +73,9 @@ typedef struct VMIntrospection { QDict *qmp_rsp; bool kvmi_hooked; + + GArray *allowed_commands; + GArray *allowed_events; } VMIntrospection; typedef struct VMIntrospectionClass { @@ -94,6 +97,8 @@ static bool suspend_pending; static bool migrate_pending; static bool shutdown_pending; +static __s32 all_IDs = -1; + #define TYPE_VM_INTROSPECTION "introspection" #define VM_INTROSPECTION(obj) \ @@ -239,6 +244,25 @@ static void prop_set_uint32(Object *obj, Visitor *v, const char *name, } } +static void prop_add_to_array(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + Error *local_err = NULL; + GArray *arr = opaque; + uint32_t value; + + visit_type_uint32(v, name, &value, &local_err); + if (!local_err && value == (uint32_t)all_IDs) { + error_setg(&local_err, "VMI: add %s: invalid id %d", name, value); + } + if (local_err) { + error_propagate(errp, local_err); + } else { + g_array_append_val(arr, value); + } +} + static bool chardev_is_connected(VMIntrospection *i, Error **errp) { Object *obj = OBJECT(i->chr); @@ -286,6 +310,15 @@ static void instance_init(Object *obj) object_property_add_str(obj, "chardev", NULL, prop_set_chardev, NULL); object_property_add_str(obj, "key", NULL, prop_set_key, NULL); + i->allowed_commands = g_array_new(FALSE, FALSE, sizeof(uint32_t)); + object_property_add(obj, "command", "uint32", + prop_add_to_array, NULL, + NULL, i->allowed_commands, NULL); + i->allowed_events = g_array_new(FALSE, FALSE, sizeof(uint32_t)); + object_property_add(obj, "event", "uint32", + prop_add_to_array, NULL, + NULL, i->allowed_events, NULL); + i->handshake_timeout = HANDSHAKE_TIMEOUT_SEC; object_property_add(obj, "handshake_timeout", "uint32", prop_set_uint32, prop_get_uint32, @@ -368,6 +401,13 @@ static void instance_finalize(Object *obj) VMIntrospectionClass *ic = VM_INTROSPECTION_CLASS(obj->class); VMIntrospection *i = VM_INTROSPECTION(obj); + if (i->allowed_commands) { + g_array_free(i->allowed_commands, TRUE); + } + if (i->allowed_events) { + g_array_free(i->allowed_events, TRUE); + } + g_free(i->chardevid); g_free(i->keyid); @@ -531,11 +571,39 @@ static bool validate_handshake(VMIntrospection *i, Error **errp) return true; } +static bool set_allowed_features(int ioctl, GArray *allowed, Error **errp) +{ + struct kvm_introspection_feature feature; + gint i; + + feature.allow = 1; + + if (allowed->len == 0) { + feature.id = all_IDs; + if (kvm_vm_ioctl(kvm_state, ioctl, &feature)) { + goto out_err; + } + } else { + for (i = 0; i < allowed->len; i++) { + feature.id = g_array_index(allowed, uint32_t, i); + if (kvm_vm_ioctl(kvm_state, ioctl, &feature)) { + goto out_err; + } + } + } + + return true; + +out_err: + error_setg_errno(errp, -errno, + "VMI: feature %d with id %d failed", + ioctl, feature.id); + return false; +} + static bool connect_kernel(VMIntrospection *i, Error **errp) { - struct kvm_introspection_feature commands, events; struct kvm_introspection_hook kernel; - const __s32 all_ids = -1; memset(&kernel, 0, sizeof(kernel)); memcpy(kernel.uuid, &qemu_uuid, sizeof(kernel.uuid)); @@ -553,20 +621,14 @@ static bool connect_kernel(VMIntrospection *i, Error **errp) i->kvmi_hooked = true; - commands.allow = 1; - commands.id = all_ids; - if (kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_COMMAND, &commands)) { - error_setg_errno(errp, -errno, - "VMI: ioctl/KVM_INTROSPECTION_COMMAND failed"); + if (!set_allowed_features(KVM_INTROSPECTION_COMMAND, + i->allowed_commands, errp)) { unhook_kvmi(i); return false; } - events.allow = 1; - events.id = all_ids; - if (kvm_vm_ioctl(kvm_state, KVM_INTROSPECTION_EVENT, &events)) { - error_setg_errno(errp, -errno, - "VMI: ioctl/KVM_INTROSPECTION_EVENT failed"); + if (!set_allowed_features(KVM_INTROSPECTION_EVENT, + i->allowed_events, errp)) { unhook_kvmi(i); return false; }