From patchwork Tue Apr 16 12:58:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wieczorkiewicz, Pawel" X-Patchwork-Id: 10902955 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 C45D617E1 for ; Tue, 16 Apr 2019 13:02:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9EC4F2891F for ; Tue, 16 Apr 2019 13:02:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 92AC5289A7; Tue, 16 Apr 2019 13:02:54 +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 95CE32899C for ; Tue, 16 Apr 2019 13:02:53 +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 1hGNhO-0005Nq-T0; Tue, 16 Apr 2019 13:00:30 +0000 Received: from us1-rack-dfw2.inumbo.com ([104.130.134.6]) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hGNhN-0005Nl-ES for xen-devel@lists.xen.org; Tue, 16 Apr 2019 13:00:29 +0000 X-Inumbo-ID: 9a6cffe1-6047-11e9-92d7-bc764e045a96 Received: from smtp-fw-33001.amazon.com (unknown [207.171.190.10]) by us1-rack-dfw2.inumbo.com (Halon) with ESMTPS id 9a6cffe1-6047-11e9-92d7-bc764e045a96; Tue, 16 Apr 2019 13:00:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1555419626; x=1586955626; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version; bh=sQDJql5TGsp+Fbhfjt2xT56EsNQJlew0V5YIldD7KHU=; b=ais+ZS0cY50X80cXxhvIK7Ut17WizW4Ssn+e3N3sLKoirFCIyMwo9kSI aQtL7kStSveB7W4K10DjvSLszEp6rHAw3lrNy/MDCIFfgNLExvq84ZMja XYTCfSkaXdTtz0Vo7/988xe0f23BWXqEV4WnQcqFCkWaaSjGVzGJ4lAO+ o=; X-IronPort-AV: E=Sophos;i="5.60,357,1549929600"; d="scan'208";a="794613445" Received: from sea3-co-svc-lb6-vlan2.sea.amazon.com (HELO email-inbound-relay-1d-2c665b5d.us-east-1.amazon.com) ([10.47.22.34]) by smtp-border-fw-out-33001.sea14.amazon.com with ESMTP/TLS/DHE-RSA-AES256-SHA; 16 Apr 2019 12:59:14 +0000 Received: from EX13MTAUEA001.ant.amazon.com (iad55-ws-svc-p15-lb9-vlan3.iad.amazon.com [10.40.159.166]) by email-inbound-relay-1d-2c665b5d.us-east-1.amazon.com (8.14.7/8.14.7) with ESMTP id x3GCwnJN126803 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=FAIL); Tue, 16 Apr 2019 12:58:49 GMT 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; Tue, 16 Apr 2019 12:58:48 +0000 Received: from EX13MTAUEB001.ant.amazon.com (10.43.60.96) by EX13D03EUC003.ant.amazon.com (10.43.164.192) with Microsoft SMTP Server (TLS) id 15.0.1367.3; Tue, 16 Apr 2019 12:58:47 +0000 Received: from dev-dsk-wipawel-1a-0c4e6d58.eu-west-1.amazon.com (10.4.134.33) by mail-relay.amazon.com (10.43.60.129) with Microsoft SMTP Server id 15.0.1367.3 via Frontend Transport; Tue, 16 Apr 2019 12:58:46 +0000 From: Pawel Wieczorkiewicz To: Date: Tue, 16 Apr 2019 12:58:31 +0000 Message-ID: <20190416125832.32881-2-wipawel@amazon.de> X-Mailer: git-send-email 2.16.5 In-Reply-To: <20190416125832.32881-1-wipawel@amazon.de> References: <20190416125832.32881-1-wipawel@amazon.de> MIME-Version: 1.0 Precedence: Bulk Subject: [Xen-devel] [livepatch: independ. modules 2/3] livepatch: Allow to override inter-modules buildid dependency 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, ross.lagerwall@citrix.com, Pawel Wieczorkiewicz , konrad.wilk@oracle.com Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP By default Livepatch enforces the following buildid-based dependency chain between hotpatch modules: 1) first module depends on given hypervisor buildid 2) every consecutive module depends on previous module's buildid This way proper hotpatch stack order is maintained and enforced. While it is important for production hotpatches it limits agility and blocks usage of testing or debug hotpatches. These kinds of hotpatch modules are typically expected to be loaded at any time irrespective of current state of the modules stack. To enable testing and debug hotpatches allow user dynamically ignore the inter-modules dependency. In this case only hypervisor buildid match is verified and enforced. To allow userland pass additional paremeters for livepatch actions add support for action flags. Each of the apply, revert, unload and revert action gets additional 64-bit parameter 'flags' where extra flags can be applied in a mask form. Initially only one flag '--nodeps' is added for the apply action. This flag modifies the default buildid dependency check as described above. The global sysctl interface input flag parameter is defined with a single corresponding flag macro: LIVEPATCH_ACTION_APPLY_NODEPS (1 << 0) The userland xen-livepatch tool is modified to support the '--nodeps' flag for apply and load commands. A general mechanism for specifying more flags in the future for apply and other action is however added. Signed-off-by: Pawel Wieczorkiewicz Reviewed-by: Andra-Irina Paraschiv Reviewed-by: Eslam Elnikety Reviewed-by: Petre Eftime Reviewed-by: Leonard Foerster Reviewed-by: Martin Pohlack Reviewed-by: Norbert Manthey --- tools/libxc/include/xenctrl.h | 9 ++-- tools/libxc/xc_misc.c | 20 +++---- tools/misc/xen-livepatch.c | 121 +++++++++++++++++++++++++++++++++++------- xen/common/livepatch.c | 14 +++-- xen/include/public/sysctl.h | 9 ++++ 5 files changed, 138 insertions(+), 35 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index a3628e56bb..6e1e41c0c9 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2618,11 +2618,12 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, * to complete them. The `timeout` offers an option to expire the * operation if it could not be completed within the specified time * (in ns). Value of 0 means let hypervisor decide the best timeout. + * The `flags` allows to pass extra parameters to the actions. */ -int xc_livepatch_apply(xc_interface *xch, char *name, uint32_t timeout); -int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout); -int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout); -int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout); +int xc_livepatch_apply(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags); +int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags); +int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags); +int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags); /* * Ensure cache coherency after memory modifications. A call to this function diff --git a/tools/libxc/xc_misc.c b/tools/libxc/xc_misc.c index 5e6714ae2b..b7289c2d4d 100644 --- a/tools/libxc/xc_misc.c +++ b/tools/libxc/xc_misc.c @@ -831,7 +831,8 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start, static int _xc_livepatch_action(xc_interface *xch, char *name, unsigned int action, - uint32_t timeout) + uint32_t timeout, + uint64_t flags) { int rc; DECLARE_SYSCTL; @@ -857,6 +858,7 @@ static int _xc_livepatch_action(xc_interface *xch, sysctl.u.livepatch.pad = 0; sysctl.u.livepatch.u.action.cmd = action; sysctl.u.livepatch.u.action.timeout = timeout; + sysctl.u.livepatch.u.action.flags = flags; sysctl.u.livepatch.u.action.name = def_name; set_xen_guest_handle(sysctl.u.livepatch.u.action.name.name, name); @@ -868,24 +870,24 @@ static int _xc_livepatch_action(xc_interface *xch, return rc; } -int xc_livepatch_apply(xc_interface *xch, char *name, uint32_t timeout) +int xc_livepatch_apply(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags) { - return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_APPLY, timeout); + return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_APPLY, timeout, flags); } -int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout) +int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags) { - return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REVERT, timeout); + return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REVERT, timeout, flags); } -int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout) +int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags) { - return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_UNLOAD, timeout); + return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_UNLOAD, timeout, flags); } -int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout) +int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags) { - return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REPLACE, timeout); + return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REPLACE, timeout, flags); } /* diff --git a/tools/misc/xen-livepatch.c b/tools/misc/xen-livepatch.c index 3233472157..a37b2457ff 100644 --- a/tools/misc/xen-livepatch.c +++ b/tools/misc/xen-livepatch.c @@ -23,18 +23,23 @@ void show_help(void) { fprintf(stderr, "xen-livepatch: live patching tool\n" - "Usage: xen-livepatch [args]\n" + "Usage: xen-livepatch [args] [command-flags]\n" " An unique name of payload. Up to %d characters.\n" "Commands:\n" " help display this help\n" " upload upload file with name\n" " list list payloads uploaded.\n" - " apply apply patch.\n" + " apply [flags] apply patch.\n" + " Supported flags:\n" + " --nodeps Disable inter-module buildid dependency check.\n" + " Check only against hypervisor buildid.\n" " revert revert name patch.\n" " replace apply patch and revert all others.\n" " unload unload name patch.\n" - " load upload and apply .\n" - " name is the name\n", + " load [flags] upload and apply with name as the name\n" + " Supported flags:\n" + " --nodeps Disable inter-module buildid dependency check.\n" + " Check only against hypervisor buildid.\n", XEN_LIVEPATCH_NAME_SIZE); } @@ -225,12 +230,13 @@ static int upload_func(int argc, char *argv[]) return rc; } -/* These MUST match to the 'action_options[]' array slots. */ +/* These MUST match to the 'action_options[]' and 'flag_options[]' array slots. */ enum { ACTION_APPLY = 0, ACTION_REVERT = 1, ACTION_UNLOAD = 2, ACTION_REPLACE = 3, + ACTION_NUM }; struct { @@ -238,7 +244,7 @@ struct { int expected; /* The state to be in after the function. */ const char *name; const char *verb; - int (*function)(xc_interface *xch, char *name, uint32_t timeout); + int (*function)(xc_interface *xch, char *name, uint32_t timeout, uint64_t flags); } action_options[] = { { .allow = LIVEPATCH_STATE_CHECKED, .expected = LIVEPATCH_STATE_APPLIED, @@ -266,6 +272,66 @@ struct { }, }; +/* + * This structure defines supported flag options for actions. + * It defines entries for each action and supports up to 64 + * flags per action. + */ +struct { + const char *name; + const uint64_t flag; +} flag_options[ACTION_NUM][8 * sizeof(uint64_t)] = { + { /* ACTION_APPLY */ + { .name = "--nodeps", + .flag = LIVEPATCH_ACTION_APPLY_NODEPS, + }, + }, + { /* ACTION_REVERT */ + }, + { /* ACTION_UNLOAD */ + }, + { /* ACTION_REPLACE */ + } +}; + +/* + * Parse user provided action flags. + * This function expects to only receive an array of input parameters being flags. + * Expected action is specified via idx paramater (index of flag_options[]). + */ +static int get_flags(int argc, char *argv[], unsigned int idx, uint64_t *flags) +{ + int i, j; + + if ( !flags || idx >= ARRAY_SIZE(flag_options) ) + return -1; + + *flags = 0; + for ( i = 0; i < argc; i++ ) + { + for ( j = 0; j < ARRAY_SIZE(flag_options[idx]); j++ ) + { + if ( !flag_options[idx][j].name ) + goto error; + + if ( !strcmp(flag_options[idx][j].name, argv[i]) ) + { + *flags |= flag_options[idx][j].flag; + break; + } + } + + if ( j == ARRAY_SIZE(flag_options[idx]) ) + goto error; + } + + return 0; +error: + fprintf(stderr, "Unsupported flag: %s.\n", argv[i]); + errno = EINVAL; + return errno; +} + /* The hypervisor timeout for the live patching operation is 30 msec, * but it could take some time for the operation to start, so wait twice * that period. */ @@ -291,8 +357,9 @@ int action_func(int argc, char *argv[], unsigned int idx) char name[XEN_LIVEPATCH_NAME_SIZE]; int rc; xen_livepatch_status_t status; + uint64_t flags; - if ( argc != 1 ) + if ( argc < 1 ) { show_help(); return -1; @@ -301,7 +368,10 @@ int action_func(int argc, char *argv[], unsigned int idx) if ( idx >= ARRAY_SIZE(action_options) ) return -1; - if ( get_name(argc, argv, name) ) + if ( get_name(argc--, argv++, name) ) + return EINVAL; + + if ( get_flags(argc, argv, idx, &flags) ) return EINVAL; /* Check initial status. */ @@ -332,7 +402,7 @@ int action_func(int argc, char *argv[], unsigned int idx) if ( action_options[idx].allow & status.state ) { printf("%s %s... ", action_options[idx].verb, name); - rc = action_options[idx].function(xch, name, HYPERVISOR_TIMEOUT_NS); + rc = action_options[idx].function(xch, name, HYPERVISOR_TIMEOUT_NS, flags); if ( rc ) { int saved_errno = errno; @@ -394,17 +464,23 @@ int action_func(int argc, char *argv[], unsigned int idx) static int load_func(int argc, char *argv[]) { - int rc; - char *new_argv[2]; - char *path, *name, *lastdot; + int i, rc = ENOMEM; + char *upload_argv[2]; + char **apply_argv, *path, *name, *lastdot; - if ( argc != 1 ) + if ( argc < 1 ) { show_help(); return -1; } + + /* apply action has [flags] input requirement, which must be constructed */ + apply_argv = (char **) malloc(argc * sizeof(*apply_argv)); + if ( !apply_argv ) + return rc; + /* */ - new_argv[1] = argv[0]; + upload_argv[1] = argv[0]; /* Synthesize the */ path = strdup(argv[0]); @@ -413,16 +489,23 @@ static int load_func(int argc, char *argv[]) lastdot = strrchr(name, '.'); if ( lastdot != NULL ) *lastdot = '\0'; - new_argv[0] = name; + upload_argv[0] = name; + apply_argv[0] = name; - rc = upload_func(2 /* */, new_argv); + /* Fill in all user provided flags */ + for ( i = 0; i < argc - 1; i++ ) + apply_argv[i + 1] = argv[i + 1]; + + rc = upload_func(2 /* */, upload_argv); if ( rc ) - return rc; + goto error; - rc = action_func(1 /* only */, new_argv, ACTION_APPLY); + rc = action_func(argc, apply_argv, ACTION_APPLY); if ( rc ) - action_func(1, new_argv, ACTION_UNLOAD); + action_func(1 /* only */, upload_argv, ACTION_UNLOAD); +error: + free(apply_argv); free(path); return rc; } diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c index 6a4af6ce57..fb91d5095c 100644 --- a/xen/common/livepatch.c +++ b/xen/common/livepatch.c @@ -1575,9 +1575,17 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action) break; } - rc = build_id_dep(data, !!list_empty(&applied_list)); - if ( rc ) - break; + /* + * Check if action is issued with nodeps flags to ignore module + * stack dependencies. + */ + if ( !(action->flags & LIVEPATCH_ACTION_APPLY_NODEPS) ) + { + rc = build_id_dep(data, !!list_empty(&applied_list)); + if ( rc ) + break; + } + data->rc = -EAGAIN; rc = schedule_work(data, action->cmd, action->timeout); } diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index c49b4dcc99..270b5e6728 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -1037,6 +1037,15 @@ struct xen_sysctl_livepatch_action { /* hypervisor default. */ /* Or upper bound of time (ns) */ /* for operation to take. */ + +/* + * Overwrite default inter-module buildid dependency chain enforcement. + * Check only if module is built for given hypervisor by comparing buildid. + */ +#define LIVEPATCH_ACTION_APPLY_NODEPS (1 << 0) + uint64_t flags; /* IN: action flags. */ + /* Provide additional parameters */ + /* for an action. */ }; struct xen_sysctl_livepatch_op {