From patchwork Thu Aug 15 11:26:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11095651 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40A166C5 for ; Thu, 15 Aug 2019 11:28:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2CCD7284C3 for ; Thu, 15 Aug 2019 11:28:07 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1EF4B288C3; Thu, 15 Aug 2019 11:28:07 +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=-4.2 required=2.0 tests=BAYES_00,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9CEAE284C3 for ; Thu, 15 Aug 2019 11:28:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyDu0-0005m7-He; Thu, 15 Aug 2019 11:26:44 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyDty-0005lp-UC for xen-devel@lists.xenproject.org; Thu, 15 Aug 2019 11:26:42 +0000 X-Inumbo-ID: 8e626208-bf4f-11e9-8b99-12813bfff9fa Received: from smtp-fw-4101.amazon.com (unknown [72.21.198.25]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 8e626208-bf4f-11e9-8b99-12813bfff9fa; Thu, 15 Aug 2019 11:26:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565868402; x=1597404402; h=from:to:cc:subject:date:message-id:mime-version; bh=QI6wli2naPKZ2dkOUa0rO1lOGiYl8olkF+nc+viaPks=; b=ajZ/q7Nj9bBqMkx8MKH6LhoGq9D+b02gYZ5GphP1ME/LJnCJPXxbqjX3 HfPeN/hc/2ZH6f3sV9q/M08Siw+19qDkNMVy/Fckl0p9+cGvEjPSWXERX yH0ZfuTVzbM1e1QvGEh28dXspJGlB/Dp1BaRveTCTfaDrhC98UrLoZG2M w=; X-IronPort-AV: E=Sophos;i="5.64,389,1559520000"; d="scan'208";a="779377624" Received: from iad6-co-svc-p1-lb1-vlan3.amazon.com (HELO email-inbound-relay-2b-4ff6265a.us-west-2.amazon.com) ([10.124.125.6]) by smtp-border-fw-out-4101.iad4.amazon.com with ESMTP; 15 Aug 2019 11:26:40 +0000 Received: from EX13MTAUEA001.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan3.pdx.amazon.com [10.170.41.166]) by email-inbound-relay-2b-4ff6265a.us-west-2.amazon.com (Postfix) with ESMTPS id 6C46FA283A; Thu, 15 Aug 2019 11:26:40 +0000 (UTC) Received: from EX13D03EUC003.ant.amazon.com (10.43.164.192) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:26:39 +0000 Received: from EX13MTAUWA001.ant.amazon.com (10.43.160.58) by EX13D03EUC003.ant.amazon.com (10.43.164.192) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:26:38 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.160.118) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Thu, 15 Aug 2019 11:26:36 +0000 From: Pawel Wieczorkiewicz To: Date: Thu, 15 Aug 2019 11:26:10 +0000 Message-ID: <20190815112610.11306-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH lp-metadata 1/3] livepatch: Add support for modules .modinfo section metadata X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: mpohlack@amazon.de, wipawel@amazon.de, Ross Lagerwall , xen-devel@lists.xenproject.org, Konrad Rzeszutek Wilk Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Having detailed hotpatch metadata helps to properly identify module's origin and version. It also allows to keep track of the history of hotpatch loads in the system (at least within dmesg buffer size limits). The hotpatch metadata are embedded in a form of .modinfo section. Each such section contains data of the following format: key=value\0key=value\0...key=value\0 The .modinfo section may be generated and appended to the resulting hotpatch ELF file optionally as an extra step of a higher level hotpatch build system. The metadata section pointer and the section length is stored in the hotpatch payload structure and is used to display the content upon hotpatch apply operation. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Bjoern Doebel Reviewed-by: Leonard Foerster Reviewed-by: Martin Pohlack Reviewed-by: Norbert Manthey --- xen/common/livepatch.c | 34 ++++++++++++++++++++++++++++++++++ xen/include/xen/livepatch_payload.h | 6 ++++++ 2 files changed, 40 insertions(+) diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 8aef2fd12e..f88cf3bc73 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -850,6 +850,23 @@ static int prepare_payload(struct payload *payload, #endif } + sec = livepatch_elf_sec_by_name(elf, ".modinfo"); + if ( sec ) + { + if ( !section_ok(elf, sec, sizeof(*payload->metadata.data)) ) + return -EINVAL; + + payload->metadata.data = sec->load_addr; + payload->metadata.len = sec->sec->sh_size; + + /* The metadata is required to consists of null terminated strings. */ + if ( payload->metadata.data[payload->metadata.len - 1] != '\0' ) + { + printk(XENLOG_ERR LIVEPATCH "%s: Incorrect metadata format detected\n", payload->name); + return -EINVAL; + } + } + return 0; } @@ -1200,6 +1217,19 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) * for XEN_SYSCTL_LIVEPATCH_ACTION operation (see livepatch_action). */ +static inline void livepatch_display_metadata(const struct livepatch_metadata *metadata) +{ + const char *str; + + if ( metadata && metadata->data && metadata->len > 0 ) + { + printk(XENLOG_INFO LIVEPATCH "module metadata:\n"); + for ( str = metadata->data; str < (metadata->data + metadata->len); str += (strlen(str) + 1) ) + printk(XENLOG_INFO LIVEPATCH " %s\n", str); + } + +} + static int apply_payload(struct payload *data) { unsigned int i; @@ -1232,6 +1262,8 @@ static int apply_payload(struct payload *data) arch_livepatch_revive(); + livepatch_display_metadata(&data->metadata); + return 0; } @@ -2008,6 +2040,8 @@ static void livepatch_printall(unsigned char key) data->name, state2str(data->state), data->state, data->text_addr, data->rw_addr, data->ro_addr, data->pages); + livepatch_display_metadata(&data->metadata); + for ( i = 0; i < data->nfuncs; i++ ) { struct livepatch_func *f = &(data->funcs[i]); diff --git a/xen/include/xen/livepatch_payload.h b/xen/include/xen/livepatch_payload.h index ff16af0dd6..9f5f064205 100644 --- a/xen/include/xen/livepatch_payload.h +++ b/xen/include/xen/livepatch_payload.h @@ -33,6 +33,11 @@ struct livepatch_hooks { } apply, revert; }; +struct livepatch_metadata { + const char *data; /* Ptr to .modinfo section with ASCII data. */ + uint32_t len; /* Length of the metadata section. */ +}; + struct payload { uint32_t state; /* One of the LIVEPATCH_STATE_*. */ int32_t rc; /* 0 or -XEN_EXX. */ @@ -63,6 +68,7 @@ struct payload { unsigned int n_load_funcs; /* Nr of the funcs to load and execute. */ unsigned int n_unload_funcs; /* Nr of funcs to call durung unload. */ char name[XEN_LIVEPATCH_NAME_SIZE]; /* Name of it. */ + struct livepatch_metadata metadata; /* Module meta data record */ }; /* From patchwork Thu Aug 15 11:27:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11095655 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id BEF27112C for ; Thu, 15 Aug 2019 11:29:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id ABE2A284C3 for ; Thu, 15 Aug 2019 11:29:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9D6C8288BF; Thu, 15 Aug 2019 11:29:04 +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=-4.2 required=2.0 tests=BAYES_00,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5DF5B284C3 for ; Thu, 15 Aug 2019 11:29:03 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyDup-0005ue-9i; Thu, 15 Aug 2019 11:27:35 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyDun-0005tv-JE for xen-devel@lists.xen.org; Thu, 15 Aug 2019 11:27:33 +0000 X-Inumbo-ID: aa8609bc-bf4f-11e9-8b9a-12813bfff9fa Received: from smtp-fw-33001.amazon.com (unknown [207.171.190.10]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id aa8609bc-bf4f-11e9-8b9a-12813bfff9fa; Thu, 15 Aug 2019 11:27:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565868450; x=1597404450; h=from:to:cc:subject:date:message-id:mime-version; bh=7k567wG9K2hRNMwJjysulFjLcC64lTQfbo5bK7gG7TA=; b=u/Ee4iTbJ40n4wcA2K77bykdG2h4wHhkF/tODp/LjuSjP/nFtVzUkGY2 ZW4NbokwMWcIeSfwevxgKK0L/TXXNMEmdEckRV+JnplDHA3wLIGTKDwrs wFg47pLMtGnF3w5V60ouxodq4hU3ylhv91qS3oJLnPOKDCKMTJnn+8BkY U=; X-IronPort-AV: E=Sophos;i="5.64,389,1559520000"; d="scan'208";a="820106037" Received: from sea3-co-svc-lb6-vlan2.sea.amazon.com (HELO email-inbound-relay-2a-6e2fc477.us-west-2.amazon.com) ([10.47.22.34]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP; 15 Aug 2019 11:27:27 +0000 Received: from EX13MTAUEA001.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan2.pdx.amazon.com [10.170.41.162]) by email-inbound-relay-2a-6e2fc477.us-west-2.amazon.com (Postfix) with ESMTPS id E31B4A22F2; Thu, 15 Aug 2019 11:27:26 +0000 (UTC) Received: from EX13D05EUB002.ant.amazon.com (10.43.166.45) by EX13MTAUEA001.ant.amazon.com (10.43.61.82) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:27:26 +0000 Received: from EX13MTAUEA001.ant.amazon.com (10.43.61.82) by EX13D05EUB002.ant.amazon.com (10.43.166.45) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:27:25 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.61.243) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Thu, 15 Aug 2019 11:27:23 +0000 From: Pawel Wieczorkiewicz To: Date: Thu, 15 Aug 2019 11:27:08 +0000 Message-ID: <20190815112708.11474-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH lp-metadata 2/3] livepatch: Handle arbitrary size names with the list operation X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ross Lagerwall , Ian Jackson , Tim Deegan , mpohlack@amazon.de, wipawel@amazon.de, Julien Grall , Jan Beulich , xen-devel@lists.xenproject.org Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP The payloads' name strings can be of arbitrary size (typically small with an upper bound of XEN_LIVEPATCH_NAME_SIZE). Current implementation of the list operation interface allows to copy names in the XEN_LIVEPATCH_NAME_SIZE chunks regardless of its actual size and enforces space allocation requirements on userland tools. To unify and simplify the interface, handle the name strings of arbitrary size by copying them in adhering chunks to the userland. In order to let the userland allocate enough space for the incoming data add an auxiliary interface xc_livepatch_list_get_sizes() that provides the current number of payload entries and the total size of all name strings. This is achieved by extending the sysctl list interface with an extra fields: name_total_size. The xc_livepatch_list_get_sizes() issues the livepatch sysctl list operation with the nr field set to 0. In this mode the operation returns the number of payload entries and calculates the total sizes for all payloads' names. When the sysctl operation is issued with a non-zero nr field (for instance with a value obtained earlier with the prior call to the xc_livepatch_list_get_sizes()) the new field name_total_size provides the total size of actually copied data. Extend the libxc to handle the name back-to-back data transfers. The xen-livepatch tool is modified to start the list operation with a call to the xc_livepatch_list_get_sizes() to obtain the actual number of payloads as well as the necessary space for names. The tool now always requests the actual number of entries and leaves the preemption handling to the libxc routine. The libxc still returns 'done' and 'left' parameters with the same semantic allowing the tool to detect anomalies and react to them. At the moment it is expected that the tool receives the exact number of entires as requested. The xen-livepatch tool has been also modified to handle the name back-to-back transfers correctly. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Bjoern Doebel Reviewed-by: Martin Pohlack --- tools/libxc/include/xenctrl.h | 49 ++++++++++++------ tools/libxc/xc_misc.c | 100 ++++++++++++++++++++++++++++--------- tools/misc/xen-livepatch.c | 112 ++++++++++++++++++++++-------------------- xen/common/livepatch.c | 31 +++++++++--- xen/include/public/sysctl.h | 15 +++--- 5 files changed, 204 insertions(+), 103 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 725697c132..e0ebb586b6 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2560,7 +2560,25 @@ int xc_livepatch_get(xc_interface *xch, xen_livepatch_status_t *status); /* - * The heart of this function is to get an array of xen_livepatch_status_t. + * Get a number of available payloads and get actual total size of + * the payloads' name array. + * + * This functions is typically executed first before the xc_livepatch_list() + * to obtain the sizes and correctly allocate all necessary data resources. + * + * The return value is zero if the hypercall completed successfully. + * + * If there was an error performing the sysctl operation, the return value + * will contain the hypercall error code value. + */ +int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, + uint64_t *name_total_size); + +/* + * The heart of this function is to get an array of the following objects: + * - xen_livepatch_status_t: states and return codes of payloads + * - name: names of payloads + * - len: lengths of corresponding payloads' names * * However it is complex because it has to deal with the hypervisor * returning some of the requested data or data being stale @@ -2571,21 +2589,20 @@ int xc_livepatch_get(xc_interface *xch, * 'left' are also updated with the number of entries filled out * and respectively the number of entries left to get from hypervisor. * - * It is expected that the caller of this function will take the - * 'left' and use the value for 'start'. This way we have an - * cursor in the array. Note that the 'info','name', and 'len' will - * be updated at the subsequent calls. + * It is expected that the caller of this function will first issue the + * xc_livepatch_list_get_sizes() in order to obtain total sizes of names + * as well as the current number of payload entries. + * The total sizes are required and supplied via the 'name_total_size' + * parameter. * - * The 'max' is to be provided by the caller with the maximum - * number of entries that 'info', 'name', and 'len' arrays can - * be filled up with. - * - * Each entry in the 'name' array is expected to be of XEN_LIVEPATCH_NAME_SIZE - * length. + * The 'max' is to be provided by the caller with the maximum number of + * entries that 'info', 'name', 'len' arrays can be filled up with. * * Each entry in the 'info' array is expected to be of xen_livepatch_status_t * structure size. * + * Each entry in the 'name' array may have an arbitrary size. + * * Each entry in the 'len' array is expected to be of uint32_t size. * * The return value is zero if the hypercall completed successfully. @@ -2597,10 +2614,12 @@ int xc_livepatch_get(xc_interface *xch, * will contain the number of entries that had been succesfully * retrieved (if any). */ -int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, - xen_livepatch_status_t *info, char *name, - uint32_t *len, unsigned int *done, - unsigned int *left); +int xc_livepatch_list(xc_interface *xch, const unsigned int max, + const unsigned int start, + struct xen_livepatch_status *info, + char *name, uint32_t *len, + const uint64_t name_total_size, + unsigned int *done, unsigned int *left); /* * The operations are asynchronous and the hypervisor may take a while diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index a8e9e7d1e2..d787f3f29f 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -662,7 +662,48 @@ int xc_livepatch_get(xc_interface *xch, } /* - * The heart of this function is to get an array of xen_livepatch_status_t. + * Get a number of available payloads and get actual total size of + * the payloads' name array. + * + * This functions is typically executed first before the xc_livepatch_list() + * to obtain the sizes and correctly allocate all necessary data resources. + * + * The return value is zero if the hypercall completed successfully. + * + * If there was an error performing the sysctl operation, the return value + * will contain the hypercall error code value. + */ +int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, + uint64_t *name_total_size) +{ + DECLARE_SYSCTL; + int rc; + + if ( !nr || !name_total_size ) + { + errno = EINVAL; + return -1; + } + + memset(&sysctl, 0, sizeof(sysctl)); + sysctl.cmd = XEN_SYSCTL_livepatch_op; + sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_LIST; + + rc = do_sysctl(xch, &sysctl); + if ( rc ) + return rc; + + *nr = sysctl.u.livepatch.u.list.nr; + *name_total_size = sysctl.u.livepatch.u.list.name_total_size; + + return 0; +} + +/* + * The heart of this function is to get an array of the following objects: + * - xen_livepatch_status_t: states and return codes of payloads + * - name: names of payloads + * - len: lengths of corresponding payloads' names * * However it is complex because it has to deal with the hypervisor * returning some of the requested data or data being stale @@ -673,21 +714,20 @@ int xc_livepatch_get(xc_interface *xch, * 'left' are also updated with the number of entries filled out * and respectively the number of entries left to get from hypervisor. * - * It is expected that the caller of this function will take the - * 'left' and use the value for 'start'. This way we have an - * cursor in the array. Note that the 'info','name', and 'len' will - * be updated at the subsequent calls. + * It is expected that the caller of this function will first issue the + * xc_livepatch_list_get_sizes() in order to obtain total sizes of names + * as well as the current number of payload entries. + * The total sizes are required and supplied via the 'name_total_size' + * parameter. * - * The 'max' is to be provided by the caller with the maximum - * number of entries that 'info', 'name', and 'len' arrays can - * be filled up with. - * - * Each entry in the 'name' array is expected to be of XEN_LIVEPATCH_NAME_SIZE - * length. + * The 'max' is to be provided by the caller with the maximum number of + * entries that 'info', 'name', 'len' arrays can be filled up with. * * Each entry in the 'info' array is expected to be of xen_livepatch_status_t * structure size. * + * Each entry in the 'name' array may have an arbitrary size. + * * Each entry in the 'len' array is expected to be of uint32_t size. * * The return value is zero if the hypercall completed successfully. @@ -699,11 +739,12 @@ int xc_livepatch_get(xc_interface *xch, * will contain the number of entries that had been succesfully * retrieved (if any). */ -int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, +int xc_livepatch_list(xc_interface *xch, const unsigned int max, + const unsigned int start, struct xen_livepatch_status *info, char *name, uint32_t *len, - unsigned int *done, - unsigned int *left) + const uint64_t name_total_size, + unsigned int *done, unsigned int *left) { int rc; DECLARE_SYSCTL; @@ -714,27 +755,33 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, uint32_t max_batch_sz, nr; uint32_t version = 0, retries = 0; uint32_t adjust = 0; - ssize_t sz; + off_t name_off = 0; + uint64_t name_sz; - if ( !max || !info || !name || !len ) + if ( !max || !info || !name || !len || !done || !left ) { errno = EINVAL; return -1; } + if ( name_total_size == 0 ) + { + errno = ENOENT; + return -1; + } + + memset(&sysctl, 0, sizeof(sysctl)); sysctl.cmd = XEN_SYSCTL_livepatch_op; sysctl.u.livepatch.cmd = XEN_SYSCTL_LIVEPATCH_LIST; - sysctl.u.livepatch.pad = 0; - sysctl.u.livepatch.u.list.version = 0; sysctl.u.livepatch.u.list.idx = start; - sysctl.u.livepatch.u.list.pad = 0; max_batch_sz = max; - /* Convience value. */ - sz = sizeof(*name) * XEN_LIVEPATCH_NAME_SIZE; + name_sz = name_total_size; *done = 0; *left = 0; do { + uint64_t _name_sz; + /* * The first time we go in this loop our 'max' may be bigger * than what the hypervisor is comfortable with - hence the first @@ -754,11 +801,11 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, sysctl.u.livepatch.u.list.nr = nr; /* Fix the size (may vary between hypercalls). */ HYPERCALL_BOUNCE_SET_SIZE(info, nr * sizeof(*info)); - HYPERCALL_BOUNCE_SET_SIZE(name, nr * nr); + HYPERCALL_BOUNCE_SET_SIZE(name, name_sz); HYPERCALL_BOUNCE_SET_SIZE(len, nr * sizeof(*len)); /* Move the pointer to proper offset into 'info'. */ (HYPERCALL_BUFFER(info))->ubuf = info + *done; - (HYPERCALL_BUFFER(name))->ubuf = name + (sz * *done); + (HYPERCALL_BUFFER(name))->ubuf = name + name_off; (HYPERCALL_BUFFER(len))->ubuf = len + *done; /* Allocate memory. */ rc = xc_hypercall_bounce_pre(xch, info); @@ -827,14 +874,19 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, break; } *left = sysctl.u.livepatch.u.list.nr; /* Total remaining count. */ + _name_sz = sysctl.u.livepatch.u.list.name_total_size; /* Total received name size. */ /* Copy only up 'rc' of data' - we could add 'min(rc,nr) if desired. */ HYPERCALL_BOUNCE_SET_SIZE(info, (rc * sizeof(*info))); - HYPERCALL_BOUNCE_SET_SIZE(name, (rc * sz)); + HYPERCALL_BOUNCE_SET_SIZE(name, _name_sz); HYPERCALL_BOUNCE_SET_SIZE(len, (rc * sizeof(*len))); /* Bounce the data and free the bounce buffer. */ xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + + name_sz -= _name_sz; + name_off += _name_sz; + /* And update how many elements of info we have copied into. */ *done += rc; /* Update idx. */ diff --git a/tools/misc/xen-livepatch.c b/tools/misc/xen-livepatch.c index a37b2457ff..8ac3d567fc 100644 --- a/tools/misc/xen-livepatch.c +++ b/tools/misc/xen-livepatch.c @@ -64,14 +64,14 @@ static const char *state2str(unsigned int state) return names[state]; } -/* This value was choosen adhoc. It could be 42 too. */ -#define MAX_LEN 11 static int list_func(int argc, char *argv[]) { - unsigned int idx, done, left, i; + unsigned int nr, done, left, i; xen_livepatch_status_t *info = NULL; char *name = NULL; uint32_t *len = NULL; + uint64_t name_total_size; + off_t name_off; int rc = ENOMEM; if ( argc ) @@ -79,65 +79,73 @@ static int list_func(int argc, char *argv[]) show_help(); return -1; } - idx = left = 0; - info = malloc(sizeof(*info) * MAX_LEN); - if ( !info ) - return rc; - name = malloc(sizeof(*name) * XEN_LIVEPATCH_NAME_SIZE * MAX_LEN); - if ( !name ) + done = left = 0; + + rc = xc_livepatch_list_get_sizes(xch, &nr, &name_total_size); + if ( rc ) { - free(info); + rc = errno; + fprintf(stderr, "Failed to get list sizes.\n" + "Error %d: %s\n", + rc, strerror(rc)); return rc; } - len = malloc(sizeof(*len) * MAX_LEN); - if ( !len ) { - free(name); - free(info); + + if ( nr == 0 ) + { + fprintf(stdout, "Nothing to list\n"); + return 0; + } + + info = malloc(nr * sizeof(*info)); + if ( !info ) return rc; + + name = malloc(name_total_size * sizeof(*name)); + if ( !name ) + goto error_name; + + len = malloc(nr * sizeof(*len)); + if ( !len ) + goto error_len; + + memset(info, 'A', nr * sizeof(*info)); + memset(name, 'B', name_total_size * sizeof(*name)); + memset(len, 'C', nr * sizeof(*len)); + name_off = 0; + + rc = xc_livepatch_list(xch, nr, 0, info, name, len, name_total_size, &done, &left); + if ( rc || done != nr || left > 0) + { + rc = errno; + fprintf(stderr, "Failed to list %d/%d.\n" + "Error %d: %s\n", + left, nr, rc, strerror(rc)); + goto error; } - do { - done = 0; - /* The memset is done to catch errors. */ - memset(info, 'A', sizeof(*info) * MAX_LEN); - memset(name, 'B', sizeof(*name) * MAX_LEN * XEN_LIVEPATCH_NAME_SIZE); - memset(len, 'C', sizeof(*len) * MAX_LEN); - rc = xc_livepatch_list(xch, MAX_LEN, idx, info, name, len, &done, &left); - if ( rc ) - { - rc = errno; - fprintf(stderr, "Failed to list %d/%d.\n" - "Error %d: %s\n", - idx, left, rc, strerror(rc)); - break; - } - if ( !idx ) - fprintf(stdout," ID | status\n" - "----------------------------------------+------------\n"); + fprintf(stdout," ID | status\n" + "----------------------------------------+------------\n"); - for ( i = 0; i < done; i++ ) - { - unsigned int j; - uint32_t sz; - char *str; - - sz = len[i]; - str = name + (i * XEN_LIVEPATCH_NAME_SIZE); - for ( j = sz; j < XEN_LIVEPATCH_NAME_SIZE; j++ ) - str[j] = '\0'; - - printf("%-40s| %s", str, state2str(info[i].state)); - if ( info[i].rc ) - printf(" (%d, %s)\n", -info[i].rc, strerror(-info[i].rc)); - else - puts(""); - } - idx += done; - } while ( left ); + for ( i = 0; i < done; i++ ) + { + char *name_str = name + name_off; + + printf("%-40.*s| %s", len[i], name_str, state2str(info[i].state)); + if ( info[i].rc ) + printf(" (%d, %s)\n", -info[i].rc, strerror(-info[i].rc)); + else + puts(""); + + name_off += len[i]; + } +error: + free(len); +error_len: free(name); +error_name: free(info); - free(len); return rc; } #undef MAX_LEN diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index f88cf3bc73..f486cb3021 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -1163,7 +1163,6 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) if ( list->nr && (!guest_handle_okay(list->status, list->nr) || - !guest_handle_okay(list->name, XEN_LIVEPATCH_NAME_SIZE * list->nr) || !guest_handle_okay(list->len, list->nr)) ) return -EINVAL; @@ -1174,23 +1173,35 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) return -EINVAL; } + list->name_total_size = 0; if ( list->nr ) { + uint64_t name_offset = 0; + list_for_each_entry( data, &payload_list, list ) { - uint32_t len; + uint32_t name_len; if ( list->idx > i++ ) continue; status.state = data->state; status.rc = data->rc; - len = strlen(data->name) + 1; + + name_len = strlen(data->name) + 1; + list->name_total_size += name_len; + + if ( !guest_handle_subrange_okay(list->name, name_offset, + name_offset + name_len - 1) ) + { + rc = -EINVAL; + break; + } /* N.B. 'idx' != 'i'. */ - if ( __copy_to_guest_offset(list->name, idx * XEN_LIVEPATCH_NAME_SIZE, - data->name, len) || - __copy_to_guest_offset(list->len, idx, &len, 1) || + if ( __copy_to_guest_offset(list->name, name_offset, + data->name, name_len) || + __copy_to_guest_offset(list->len, idx, &name_len, 1) || __copy_to_guest_offset(list->status, idx, &status, 1) ) { rc = -EFAULT; @@ -1198,11 +1209,19 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) } idx++; + name_offset += name_len; if ( (idx >= list->nr) || hypercall_preempt_check() ) break; } } + else + { + list_for_each_entry( data, &payload_list, list ) + { + list->name_total_size += strlen(data->name) + 1; + } + } list->nr = payload_cnt - i; /* Remaining amount. */ list->version = payload_version; spin_unlock(&payload_lock); diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 335e193712..b86804b7a6 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -926,10 +926,11 @@ struct xen_sysctl_livepatch_get { * * If the hypercall returns an positive number, it is the number (up to `nr`) * of the payloads returned, along with `nr` updated with the number of remaining - * payloads, `version` updated (it may be the same across hypercalls. If it - * varies the data is stale and further calls could fail). The `status`, - * `name`, and `len`' are updated at their designed index value (`idx`) with - * the returned value of data. + * payloads, `version` updated (it may be the same across hypercalls. If it varies + * the data is stale and further calls could fail) and the name_total_size + * containing total size of transfered data for the array. + * The `status`, `name`, `len` are updated at their designed index value (`idx`) + * with the returned value of data. * * If the hypercall returns E2BIG the `nr` is too big and should be * lowered. The upper limit of `nr` is left to the implemention. @@ -952,11 +953,13 @@ struct xen_sysctl_livepatch_list { amount of payloads and version. OUT: How many payloads left. */ uint32_t pad; /* IN: Must be zero. */ + uint64_t name_total_size; /* OUT: Total size of all transfer names */ XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough space allocate for nr of them. */ XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member - MUST XEN_LIVEPATCH_NAME_SIZE in size. - Must have nr of them. */ + may have an arbitrary length up to + XEN_LIVEPATCH_NAME_SIZE bytes. Must have + nr of them. */ XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. Must have nr of them. */ }; From patchwork Thu Aug 15 11:27:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 11095659 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DA1C56C5 for ; Thu, 15 Aug 2019 11:29:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C6BB9284C3 for ; Thu, 15 Aug 2019 11:29:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B8786288BF; Thu, 15 Aug 2019 11:29:41 +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=-4.2 required=2.0 tests=BAYES_00,DKIM_ADSP_ALL, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 76930284C3 for ; Thu, 15 Aug 2019 11:29:40 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyDvT-00063K-SX; Thu, 15 Aug 2019 11:28:15 +0000 Received: from us1-rack-iad1.inumbo.com ([172.99.69.81]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hyDvT-000630-3O for xen-devel@lists.xen.org; Thu, 15 Aug 2019 11:28:15 +0000 X-Inumbo-ID: c51981be-bf4f-11e9-b22b-bc764e2007e4 Received: from smtp-fw-2101.amazon.com (unknown [72.21.196.25]) by us1-rack-iad1.inumbo.com (Halon) with ESMTPS id c51981be-bf4f-11e9-b22b-bc764e2007e4; Thu, 15 Aug 2019 11:28:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1565868494; x=1597404494; h=from:to:cc:subject:date:message-id:mime-version; bh=rl67UTQymT8gd8EnfNxyVIyFrnY4hpvdg8DNu/XPny0=; b=LR9XCoSPJ2HwsePDnectuSC/K70V9LAUukgyAadAZ+/pW03I2xDJxfyM tD3E8poMirxW5HSWBqTF/uTuXn7Fu1rh2zrk+l3nz9P94Nw4JzNdYVtuE 1L+N0zznQm+xDH8sl4M+4M6EuzrP3yNtvf2ZwuQVxTVKTcGZOg2bLUfld 4=; X-IronPort-AV: E=Sophos;i="5.64,389,1559520000"; d="scan'208";a="746834990" Received: from iad6-co-svc-p1-lb1-vlan2.amazon.com (HELO email-inbound-relay-2c-1968f9fa.us-west-2.amazon.com) ([10.124.125.2]) by smtp-border-fw-out-2101.iad2.amazon.com with ESMTP; 15 Aug 2019 11:28:12 +0000 Received: from EX13MTAUEA001.ant.amazon.com (pdx4-ws-svc-p6-lb7-vlan3.pdx.amazon.com [10.170.41.166]) by email-inbound-relay-2c-1968f9fa.us-west-2.amazon.com (Postfix) with ESMTPS id AA08EA2234; Thu, 15 Aug 2019 11:28:10 +0000 (UTC) Received: from EX13D03EUC001.ant.amazon.com (10.43.164.245) by EX13MTAUEA001.ant.amazon.com (10.43.61.243) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 11:27:56 +0000 Received: from EX13MTAUEA001.ant.amazon.com (10.43.61.82) by EX13D03EUC001.ant.amazon.com (10.43.164.245) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Thu, 15 Aug 2019 04:27:55 -0700 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.61.243) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Thu, 15 Aug 2019 11:27:53 +0000 From: Pawel Wieczorkiewicz To: Date: Thu, 15 Aug 2019 11:27:50 +0000 Message-ID: <20190815112750.11581-1-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [PATCH lp-metadata 3/3] livepatch: Add metadata runtime retrieval mechanism X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Stefano Stabellini , Wei Liu , Konrad Rzeszutek Wilk , George Dunlap , Andrew Cooper , Ross Lagerwall , Ian Jackson , Tim Deegan , mpohlack@amazon.de, wipawel@amazon.de, Julien Grall , Jan Beulich , xen-devel@lists.xenproject.org Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Extend the livepatch list operation to fetch also payloads' metadata. This is achieved by extending the sysctl list interface with 2 extra guest handles: * metadata - an array of arbitrary size strings * metadata_len - an array of metadata strings' lengths (uin32_t each) Payloads' metadata is a string of arbitrary size and does not have an upper bound limit. It may also vary in size between payloads. In order to let the userland allocate enough space for the incoming data add a metadata total size field to the list sysctl operation and fill it with total size of all payloads' metadata. Extend the libxc to handle the metadata back-to-back data transfers as well as metadata length array data transfers. The xen-livepatch userland tool is extended to always display the metadata for each received module. The metadata is received with the following format: key=value\0key=value\0...key=value\0. The format is modified to the following one: key=value;key=value;...key=value. The new format allows to easily parse the metadata for a given module by a machine. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Martin Pohlack Reviewed-by: Norbert Manthey --- tools/libxc/include/xenctrl.h | 22 +++++++++++---- tools/libxc/xc_misc.c | 66 +++++++++++++++++++++++++++++++++++-------- tools/misc/xen-livepatch.c | 43 ++++++++++++++++++++++------ xen/common/livepatch.c | 22 +++++++++++---- xen/include/public/sysctl.h | 19 +++++++++---- 5 files changed, 134 insertions(+), 38 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index e0ebb586b6..7a3762f44e 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2561,7 +2561,7 @@ int xc_livepatch_get(xc_interface *xch, /* * Get a number of available payloads and get actual total size of - * the payloads' name array. + * the payloads' name and metadata arrays. * * This functions is typically executed first before the xc_livepatch_list() * to obtain the sizes and correctly allocate all necessary data resources. @@ -2572,13 +2572,16 @@ int xc_livepatch_get(xc_interface *xch, * will contain the hypercall error code value. */ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, - uint64_t *name_total_size); + uint64_t *name_total_size, + uint64_t *metadata_total_size); /* * The heart of this function is to get an array of the following objects: * - xen_livepatch_status_t: states and return codes of payloads * - name: names of payloads * - len: lengths of corresponding payloads' names + * - metadata: payloads' metadata + * - metadata_len: lengths of corresponding payloads' metadata * * However it is complex because it has to deal with the hypervisor * returning some of the requested data or data being stale @@ -2591,12 +2594,13 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * It is expected that the caller of this function will first issue the * xc_livepatch_list_get_sizes() in order to obtain total sizes of names - * as well as the current number of payload entries. - * The total sizes are required and supplied via the 'name_total_size' - * parameter. + * and all metadata as well as the current number of payload entries. + * The total sizes are required and supplied via the 'name_total_size' and + * 'metadata_total_size' parameters. * * The 'max' is to be provided by the caller with the maximum number of - * entries that 'info', 'name', 'len' arrays can be filled up with. + * entries that 'info', 'name', 'len', 'metadata' and 'metadata_len' arrays + * can be filled up with. * * Each entry in the 'info' array is expected to be of xen_livepatch_status_t * structure size. @@ -2605,6 +2609,10 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * Each entry in the 'len' array is expected to be of uint32_t size. * + * Each entry in the 'metadata' array may have an arbitrary size. + * + * Each entry in the 'metadata_len' array is expected to be of uint32_t size. + * * The return value is zero if the hypercall completed successfully. * Note that the return value is _not_ the amount of entries filled * out - that is saved in 'done'. @@ -2619,6 +2627,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, struct xen_livepatch_status *info, char *name, uint32_t *len, const uint64_t name_total_size, + char *metadata, uint32_t *metadata_len, + const uint64_t metadata_total_size, unsigned int *done, unsigned int *left); /* diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index d787f3f29f..618113011d 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -663,7 +663,7 @@ int xc_livepatch_get(xc_interface *xch, /* * Get a number of available payloads and get actual total size of - * the payloads' name array. + * the payloads' name and metadata arrays. * * This functions is typically executed first before the xc_livepatch_list() * to obtain the sizes and correctly allocate all necessary data resources. @@ -674,12 +674,13 @@ int xc_livepatch_get(xc_interface *xch, * will contain the hypercall error code value. */ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, - uint64_t *name_total_size) + uint64_t *name_total_size, + uint64_t *metadata_total_size) { DECLARE_SYSCTL; int rc; - if ( !nr || !name_total_size ) + if ( !nr || !name_total_size || !metadata_total_size ) { errno = EINVAL; return -1; @@ -695,6 +696,7 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, *nr = sysctl.u.livepatch.u.list.nr; *name_total_size = sysctl.u.livepatch.u.list.name_total_size; + *metadata_total_size = sysctl.u.livepatch.u.list.metadata_total_size; return 0; } @@ -704,6 +706,8 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * - xen_livepatch_status_t: states and return codes of payloads * - name: names of payloads * - len: lengths of corresponding payloads' names + * - metadata: payloads' metadata + * - metadata_len: lengths of corresponding payloads' metadata * * However it is complex because it has to deal with the hypervisor * returning some of the requested data or data being stale @@ -716,12 +720,13 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * It is expected that the caller of this function will first issue the * xc_livepatch_list_get_sizes() in order to obtain total sizes of names - * as well as the current number of payload entries. - * The total sizes are required and supplied via the 'name_total_size' - * parameter. + * and all metadata as well as the current number of payload entries. + * The total sizes are required and supplied via the 'name_total_size' and + * 'metadata_total_size' parameters. * * The 'max' is to be provided by the caller with the maximum number of - * entries that 'info', 'name', 'len' arrays can be filled up with. + * entries that 'info', 'name', 'len', 'metadata' and 'metadata_len' arrays + * can be filled up with. * * Each entry in the 'info' array is expected to be of xen_livepatch_status_t * structure size. @@ -730,6 +735,10 @@ int xc_livepatch_list_get_sizes(xc_interface *xch, unsigned int *nr, * * Each entry in the 'len' array is expected to be of uint32_t size. * + * Each entry in the 'metadata' array may have an arbitrary size. + * + * Each entry in the 'metadata_len' array is expected to be of uint32_t size. + * * The return value is zero if the hypercall completed successfully. * Note that the return value is _not_ the amount of entries filled * out - that is saved in 'done'. @@ -744,6 +753,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, struct xen_livepatch_status *info, char *name, uint32_t *len, const uint64_t name_total_size, + char *metadata, uint32_t *metadata_len, + const uint64_t metadata_total_size, unsigned int *done, unsigned int *left) { int rc; @@ -752,19 +763,22 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, DECLARE_HYPERCALL_BOUNCE(info, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); DECLARE_HYPERCALL_BOUNCE(name, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); DECLARE_HYPERCALL_BOUNCE(len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); + DECLARE_HYPERCALL_BOUNCE(metadata, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); + DECLARE_HYPERCALL_BOUNCE(metadata_len, 0, XC_HYPERCALL_BUFFER_BOUNCE_OUT); uint32_t max_batch_sz, nr; uint32_t version = 0, retries = 0; uint32_t adjust = 0; - off_t name_off = 0; - uint64_t name_sz; + off_t name_off = 0, metadata_off = 0; + uint64_t name_sz, metadata_sz; - if ( !max || !info || !name || !len || !done || !left ) + if ( !max || !info || !name || !len || + !metadata || !metadata_len || !done || !left ) { errno = EINVAL; return -1; } - if ( name_total_size == 0 ) + if ( name_total_size == 0 || metadata_total_size == 0 ) { errno = ENOENT; return -1; @@ -777,10 +791,11 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, max_batch_sz = max; name_sz = name_total_size; + metadata_sz = metadata_total_size; *done = 0; *left = 0; do { - uint64_t _name_sz; + uint64_t _name_sz, _metadata_sz; /* * The first time we go in this loop our 'max' may be bigger @@ -803,10 +818,14 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, HYPERCALL_BOUNCE_SET_SIZE(info, nr * sizeof(*info)); HYPERCALL_BOUNCE_SET_SIZE(name, name_sz); HYPERCALL_BOUNCE_SET_SIZE(len, nr * sizeof(*len)); + HYPERCALL_BOUNCE_SET_SIZE(metadata, metadata_sz); + HYPERCALL_BOUNCE_SET_SIZE(metadata_len, nr * sizeof(*metadata_len)); /* Move the pointer to proper offset into 'info'. */ (HYPERCALL_BUFFER(info))->ubuf = info + *done; (HYPERCALL_BUFFER(name))->ubuf = name + name_off; (HYPERCALL_BUFFER(len))->ubuf = len + *done; + (HYPERCALL_BUFFER(metadata))->ubuf = metadata + metadata_off; + (HYPERCALL_BUFFER(metadata_len))->ubuf = metadata_len + *done; /* Allocate memory. */ rc = xc_hypercall_bounce_pre(xch, info); if ( rc ) @@ -820,9 +839,19 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, if ( rc ) break; + rc = xc_hypercall_bounce_pre(xch, metadata); + if ( rc ) + break; + + rc = xc_hypercall_bounce_pre(xch, metadata_len); + if ( rc ) + break; + set_xen_guest_handle(sysctl.u.livepatch.u.list.status, info); set_xen_guest_handle(sysctl.u.livepatch.u.list.name, name); set_xen_guest_handle(sysctl.u.livepatch.u.list.len, len); + set_xen_guest_handle(sysctl.u.livepatch.u.list.metadata, metadata); + set_xen_guest_handle(sysctl.u.livepatch.u.list.metadata_len, metadata_len); rc = do_sysctl(xch, &sysctl); /* @@ -839,6 +868,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); continue; } else if ( rc < 0 ) /* For all other errors we bail out. */ @@ -863,6 +894,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); continue; } @@ -875,17 +908,24 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, } *left = sysctl.u.livepatch.u.list.nr; /* Total remaining count. */ _name_sz = sysctl.u.livepatch.u.list.name_total_size; /* Total received name size. */ + _metadata_sz = sysctl.u.livepatch.u.list.metadata_total_size; /* Total received metadata size. */ /* Copy only up 'rc' of data' - we could add 'min(rc,nr) if desired. */ HYPERCALL_BOUNCE_SET_SIZE(info, (rc * sizeof(*info))); HYPERCALL_BOUNCE_SET_SIZE(name, _name_sz); HYPERCALL_BOUNCE_SET_SIZE(len, (rc * sizeof(*len))); + HYPERCALL_BOUNCE_SET_SIZE(metadata, _metadata_sz); + HYPERCALL_BOUNCE_SET_SIZE(metadata_len, (rc * sizeof(*metadata_len))); /* Bounce the data and free the bounce buffer. */ xc_hypercall_bounce_post(xch, info); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, len); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); name_sz -= _name_sz; name_off += _name_sz; + metadata_sz -= _metadata_sz; + metadata_off += _metadata_sz; /* And update how many elements of info we have copied into. */ *done += rc; @@ -898,6 +938,8 @@ int xc_livepatch_list(xc_interface *xch, const unsigned int max, xc_hypercall_bounce_post(xch, len); xc_hypercall_bounce_post(xch, name); xc_hypercall_bounce_post(xch, info); + xc_hypercall_bounce_post(xch, metadata); + xc_hypercall_bounce_post(xch, metadata_len); } return rc > 0 ? 0 : rc; diff --git a/tools/misc/xen-livepatch.c b/tools/misc/xen-livepatch.c index 8ac3d567fc..61d4950001 100644 --- a/tools/misc/xen-livepatch.c +++ b/tools/misc/xen-livepatch.c @@ -69,9 +69,11 @@ static int list_func(int argc, char *argv[]) unsigned int nr, done, left, i; xen_livepatch_status_t *info = NULL; char *name = NULL; + char *metadata = NULL; uint32_t *len = NULL; - uint64_t name_total_size; - off_t name_off; + uint32_t *metadata_len = NULL; + uint64_t name_total_size, metadata_total_size; + off_t name_off, metadata_off; int rc = ENOMEM; if ( argc ) @@ -81,7 +83,7 @@ static int list_func(int argc, char *argv[]) } done = left = 0; - rc = xc_livepatch_list_get_sizes(xch, &nr, &name_total_size); + rc = xc_livepatch_list_get_sizes(xch, &nr, &name_total_size, &metadata_total_size); if ( rc ) { rc = errno; @@ -109,12 +111,23 @@ static int list_func(int argc, char *argv[]) if ( !len ) goto error_len; + metadata = malloc(metadata_total_size * sizeof(*metadata)); + if ( !metadata ) + goto error_metadata; + + metadata_len = malloc(nr * sizeof(*metadata_len)); + if ( !metadata_len ) + goto error_metadata_len; + memset(info, 'A', nr * sizeof(*info)); memset(name, 'B', name_total_size * sizeof(*name)); memset(len, 'C', nr * sizeof(*len)); - name_off = 0; + memset(metadata, 'D', metadata_total_size * sizeof(*metadata)); + memset(metadata_len, 'E', nr * sizeof(*metadata_len)); + name_off = metadata_off = 0; - rc = xc_livepatch_list(xch, nr, 0, info, name, len, name_total_size, &done, &left); + rc = xc_livepatch_list(xch, nr, 0, info, name, len, name_total_size, + metadata, metadata_len, metadata_total_size, &done, &left); if ( rc || done != nr || left > 0) { rc = errno; @@ -124,23 +137,35 @@ static int list_func(int argc, char *argv[]) goto error; } - fprintf(stdout," ID | status\n" - "----------------------------------------+------------\n"); + fprintf(stdout," ID | status | metadata\n" + "----------------------------------------+------------+---------------\n"); for ( i = 0; i < done; i++ ) { + unsigned int j; char *name_str = name + name_off; + char *metadata_str = metadata + metadata_off; printf("%-40.*s| %s", len[i], name_str, state2str(info[i].state)); if ( info[i].rc ) - printf(" (%d, %s)\n", -info[i].rc, strerror(-info[i].rc)); + printf(" (%d, %s) | ", -info[i].rc, strerror(-info[i].rc)); else - puts(""); + printf(" | "); + + /* Replace all '\0' with semi-colons. */ + for ( j = 0; j < metadata_len[i] - 1; j++ ) + metadata_str[j] = (metadata_str[j] ?: ';'); + printf("%.*s\n", metadata_len[i], metadata_str); name_off += len[i]; + metadata_off += metadata_len[i]; } error: + free(metadata_len); +error_metadata_len: + free(metadata); +error_metadata: free(len); error_len: free(name); diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index f486cb3021..49a76f1029 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -1163,7 +1163,8 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) if ( list->nr && (!guest_handle_okay(list->status, list->nr) || - !guest_handle_okay(list->len, list->nr)) ) + !guest_handle_okay(list->len, list->nr) || + !guest_handle_okay(list->metadata_len, list->nr)) ) return -EINVAL; spin_lock(&payload_lock); @@ -1174,13 +1175,14 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) } list->name_total_size = 0; + list->metadata_total_size = 0; if ( list->nr ) { - uint64_t name_offset = 0; + uint64_t name_offset = 0, metadata_offset = 0; list_for_each_entry( data, &payload_list, list ) { - uint32_t name_len; + uint32_t name_len, metadata_len; if ( list->idx > i++ ) continue; @@ -1191,8 +1193,13 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) name_len = strlen(data->name) + 1; list->name_total_size += name_len; + metadata_len = data->metadata.len; + list->metadata_total_size += metadata_len; + if ( !guest_handle_subrange_okay(list->name, name_offset, - name_offset + name_len - 1) ) + name_offset + name_len - 1) || + !guest_handle_subrange_okay(list->metadata, metadata_offset, + metadata_offset + metadata_len - 1) ) { rc = -EINVAL; break; @@ -1202,7 +1209,10 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) if ( __copy_to_guest_offset(list->name, name_offset, data->name, name_len) || __copy_to_guest_offset(list->len, idx, &name_len, 1) || - __copy_to_guest_offset(list->status, idx, &status, 1) ) + __copy_to_guest_offset(list->status, idx, &status, 1) || + __copy_to_guest_offset(list->metadata, metadata_offset, + data->metadata.data, metadata_len) || + __copy_to_guest_offset(list->metadata_len, idx, &metadata_len, 1) ) { rc = -EFAULT; break; @@ -1210,6 +1220,7 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) idx++; name_offset += name_len; + metadata_offset += metadata_len; if ( (idx >= list->nr) || hypercall_preempt_check() ) break; @@ -1220,6 +1231,7 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list) list_for_each_entry( data, &payload_list, list ) { list->name_total_size += strlen(data->name) + 1; + list->metadata_total_size += data->metadata.len; } } list->nr = payload_cnt - i; /* Remaining amount. */ diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index b86804b7a6..e4c8f4fe63 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -921,16 +921,17 @@ struct xen_sysctl_livepatch_get { }; /* - * Retrieve an array of abbreviated status and names of payloads that are - * loaded in the hypervisor. + * Retrieve an array of abbreviated status, names and metadata of payloads that + * are loaded in the hypervisor. * * If the hypercall returns an positive number, it is the number (up to `nr`) * of the payloads returned, along with `nr` updated with the number of remaining * payloads, `version` updated (it may be the same across hypercalls. If it varies - * the data is stale and further calls could fail) and the name_total_size - * containing total size of transfered data for the array. - * The `status`, `name`, `len` are updated at their designed index value (`idx`) - * with the returned value of data. + * the data is stale and further calls could fail), `name_total_size` and + * `metadata_total_size` containing total sizes of transfered data for both the + * arrays. + * The `status`, `name`, `len`, `metadata` and `metadata_len` are updated at their + * designed index value (`idx`) with the returned value of data. * * If the hypercall returns E2BIG the `nr` is too big and should be * lowered. The upper limit of `nr` is left to the implemention. @@ -954,6 +955,7 @@ struct xen_sysctl_livepatch_list { OUT: How many payloads left. */ uint32_t pad; /* IN: Must be zero. */ uint64_t name_total_size; /* OUT: Total size of all transfer names */ + uint64_t metadata_total_size; /* OUT: Total size of all transfer metadata */ XEN_GUEST_HANDLE_64(xen_livepatch_status_t) status; /* OUT. Must have enough space allocate for nr of them. */ XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member @@ -962,6 +964,11 @@ struct xen_sysctl_livepatch_list { nr of them. */ XEN_GUEST_HANDLE_64(uint32) len; /* OUT: Array of lengths of name's. Must have nr of them. */ + XEN_GUEST_HANDLE_64(char) metadata; /* OUT: Array of metadata strings. Each + member may have an arbitrary length. + Must have nr of them. */ + XEN_GUEST_HANDLE_64(uint32) metadata_len; /* OUT: Array of lengths of metadata's. + Must have nr of them. */ }; /*