From patchwork Tue Nov 8 09:56:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Halil Pasic X-Patchwork-Id: 9417027 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 599A560459 for ; Tue, 8 Nov 2016 10:01:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 489C028B6D for ; Tue, 8 Nov 2016 10:01:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3919128B8A; Tue, 8 Nov 2016 10:01:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 79D6528B6D for ; Tue, 8 Nov 2016 10:01:20 +0000 (UTC) Received: from localhost ([::1]:59714 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c43DT-0004aS-MU for patchwork-qemu-devel@patchwork.kernel.org; Tue, 08 Nov 2016 05:01:19 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36839) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c438c-0000zd-4I for qemu-devel@nongnu.org; Tue, 08 Nov 2016 04:56:19 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1c438Y-0006u5-7C for qemu-devel@nongnu.org; Tue, 08 Nov 2016 04:56:18 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:38322 helo=mx0a-001b2d01.pphosted.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1c438Y-0006tl-1a for qemu-devel@nongnu.org; Tue, 08 Nov 2016 04:56:14 -0500 Received: from pps.filterd (m0098414.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.17/8.16.0.17) with SMTP id uA89s9DP047250 for ; Tue, 8 Nov 2016 04:56:13 -0500 Received: from e06smtp08.uk.ibm.com (e06smtp08.uk.ibm.com [195.75.94.104]) by mx0b-001b2d01.pphosted.com with ESMTP id 26ka1wr1j8-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Tue, 08 Nov 2016 04:56:13 -0500 Received: from localhost by e06smtp08.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 8 Nov 2016 09:56:11 -0000 Received: from d06dlp02.portsmouth.uk.ibm.com (9.149.20.14) by e06smtp08.uk.ibm.com (192.168.101.138) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Tue, 8 Nov 2016 09:56:10 -0000 Received: from b06cxnps4076.portsmouth.uk.ibm.com (d06relay13.portsmouth.uk.ibm.com [9.149.109.198]) by d06dlp02.portsmouth.uk.ibm.com (Postfix) with ESMTP id 768042190023 for ; Tue, 8 Nov 2016 09:55:23 +0000 (GMT) Received: from d06av02.portsmouth.uk.ibm.com (d06av02.portsmouth.uk.ibm.com [9.149.37.228]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id uA89u9Tu14549428 for ; Tue, 8 Nov 2016 09:56:09 GMT Received: from d06av02.portsmouth.uk.ibm.com (localhost [127.0.0.1]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id uA89u8Bj029338 for ; Tue, 8 Nov 2016 02:56:09 -0700 Received: from tuxmaker.boeblingen.de.ibm.com (tuxmaker.boeblingen.de.ibm.com [9.152.85.9]) by d06av02.portsmouth.uk.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id uA89u68Y029231 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA256 bits=256 verify=NO); Tue, 8 Nov 2016 02:56:08 -0700 From: Halil Pasic To: qemu-devel@nongnu.org Date: Tue, 8 Nov 2016 10:56:02 +0100 X-Mailer: git-send-email 2.8.4 In-Reply-To: <20161108095603.72301-1-pasic@linux.vnet.ibm.com> References: <20161108095603.72301-1-pasic@linux.vnet.ibm.com> X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 16110809-0032-0000-0000-00000238EE25 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 16110809-0033-0000-0000-00001D9C5130 Message-Id: <20161108095603.72301-8-pasic@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-11-08_03:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1609300000 definitions=main-1611080183 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x [generic] X-Received-From: 148.163.158.5 Subject: [Qemu-devel] [RFC PATCH v2 7/8] migration/vmstate: fix array of pointers to struct X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Amit Shah , Halil Pasic , Guenther Hutzl , "Dr. David Alan Gilbert" , Juan Quintela Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Make VMS_ARRAY_OF_POINTER cope with null pointers. Previously the reward for trying to migrate an array with some null pointers in it was an illegal memory access, that is a swift and painless death of the process. Let's make vmstate cope with this scenario at least for pointers to structs. The general approach is when we encounter a null pointer (element) instead of following the pointer to save/load the data behind it we save/load a placeholder. This way we can detect if we expected a null pointer at the load side but not null data was saved instead. Sadly all other error scenarios are not detected by this scheme (and would require the usage of the JSON meta data). Limitations: Does not work for pointers to primitives. Signed-off-by: Halil Pasic Reviewed-by: Guenther Hutzl --- We will need this to load/save some on demand created state from within the channel subsystem (see ChannelSubSys.css in hw/s390x/css.c for an example). --- include/migration/vmstate.h | 5 +++++ migration/vmstate.c | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 5940db0..86d4aca 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -236,6 +236,10 @@ extern const VMStateInfo vmstate_info_uint16; extern const VMStateInfo vmstate_info_uint32; extern const VMStateInfo vmstate_info_uint64; +/** Put this in the stream when migrating a null pointer.*/ +#define VMS_NULLPTR_MARKER ((int8_t) -1) +extern const VMStateInfo vmstate_info_nullptr; + extern const VMStateInfo vmstate_info_float64; extern const VMStateInfo vmstate_info_cpudouble; @@ -453,6 +457,7 @@ extern const VMStateInfo vmstate_info_bitmap; .size = sizeof(_type *), \ .flags = VMS_ARRAY|VMS_STRUCT|VMS_ARRAY_OF_POINTER, \ .offset = vmstate_offset_array(_s, _f, _type*, _n), \ + .info = &vmstate_info_nullptr, \ } #define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \ diff --git a/migration/vmstate.c b/migration/vmstate.c index 10a7645..ce3490a 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -109,7 +109,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_ARRAY_OF_POINTER) { curr_elem = *(void **)curr_elem; } - if (field->flags & VMS_STRUCT) { + if (!curr_elem) { + /* if null pointer check placeholder and do not follow */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + vmstate_info_nullptr.get(f, curr_elem, size); + } else if (field->flags & VMS_STRUCT) { ret = vmstate_load_state(f, field->vmsd, curr_elem, field->vmsd->version_id); } else { @@ -320,7 +324,11 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, assert(curr_elem); curr_elem = *(void **)curr_elem; } - if (field->flags & VMS_STRUCT) { + if (!curr_elem) { + /* if null pointer write placeholder and do not follow */ + assert(field->flags & VMS_ARRAY_OF_POINTER); + vmstate_info_nullptr.put(f, curr_elem, size); + } else if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop); } else { field->info->put(f, curr_elem, size); @@ -708,6 +716,26 @@ const VMStateInfo vmstate_info_uint64 = { .put = put_uint64, }; +static int get_nullptr(QEMUFile *f, void *pv, size_t size) +{ + int8_t tmp; + qemu_get_s8s(f, &tmp); + return tmp == VMS_NULLPTR_MARKER ? 0 : -EINVAL; +} + +static void put_nullptr(QEMUFile *f, void *pv, size_t size) +{ + int8_t tmp = VMS_NULLPTR_MARKER; + assert(pv == NULL); + qemu_put_s8s(f, &tmp); +} + +const VMStateInfo vmstate_info_nullptr = { + .name = "uint64", + .get = get_nullptr, + .put = put_nullptr, +}; + /* 64 bit unsigned int. See that the received value is the same than the one in the field */