@@ -659,6 +659,10 @@ The caller provides:
* `time` The upper bound of time (ns) the cmd should take. Zero means to use
the hypervisor default. If within the time the operation does not succeed
the operation would go in error state.
+ * `flags` provides additional parameters for an action:
+ * *LIVEPATCH_ACTION_APPLY_NODEPS* (1) Apply action ignores inter-module
+ buildid dependency. Checks only if module is built for given hypervisor by
+ comparing buildid.
* `pad` - *MUST* be zero.
The return value will be zero unless the provided fields are incorrect.
@@ -676,6 +680,10 @@ The structure is as follow:
/* hypervisor default. */
/* Or upper bound of time (ns) */
/* for operation to take. */
+ uint32_t flags; /* IN: action flags. */
+ /* Provide additional parameters */
+ /* for an action. */
+ uint32_t pad; /* IN: Always zero. */
};
@@ -2605,11 +2605,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, uint32_t flags);
+int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags);
+int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags);
+int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout, uint32_t flags);
/*
* Ensure cache coherency after memory modifications. A call to this function
@@ -854,7 +854,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,
+ uint32_t flags)
{
int rc;
DECLARE_SYSCTL;
@@ -880,6 +881,8 @@ 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.pad = 0;
sysctl.u.livepatch.u.action.name = def_name;
set_xen_guest_handle(sysctl.u.livepatch.u.action.name.name, name);
@@ -891,24 +894,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, uint32_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, uint32_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, uint32_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, uint32_t flags)
{
- return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REPLACE, timeout);
+ return _xc_livepatch_action(xch, name, LIVEPATCH_ACTION_REPLACE, timeout, flags);
}
/*
@@ -23,18 +23,23 @@ void show_help(void)
{
fprintf(stderr,
"xen-livepatch: live patching tool\n"
- "Usage: xen-livepatch <command> [args]\n"
+ "Usage: xen-livepatch <command> [args] [command-flags]\n"
" <name> An unique name of payload. Up to %d characters.\n"
"Commands:\n"
" help display this help\n"
" upload <name> <file> upload file <file> with <name> name\n"
" list list payloads uploaded.\n"
- " apply <name> apply <name> patch.\n"
+ " apply <name> [flags] apply <name> patch.\n"
+ " Supported flags:\n"
+ " --nodeps Disable inter-module buildid dependency check.\n"
+ " Check only against hypervisor buildid.\n"
" revert <name> revert name <name> patch.\n"
" replace <name> apply <name> patch and revert all others.\n"
" unload <name> unload name <name> patch.\n"
- " load <file> upload and apply <file>.\n"
- " name is the <file> name\n",
+ " load <file> [flags] upload and apply <file> with name as the <file> 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, uint32_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 32
+ * flags per action.
+ */
+struct {
+ const char *name;
+ const uint32_t flag;
+} flag_options[ACTION_NUM][8 * sizeof(uint32_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, uint32_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;
+ uint32_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 <id> [flags] input requirement, which must be constructed */
+ apply_argv = (char **) malloc(argc * sizeof(*apply_argv));
+ if ( !apply_argv )
+ return rc;
+
/* <file> */
- new_argv[1] = argv[0];
+ upload_argv[1] = argv[0];
/* Synthesize the <id> */
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 /* <id> <file> */, new_argv);
+ /* Fill in all user provided flags */
+ for ( i = 1; i < argc; i++ )
+ apply_argv[i] = argv[i];
+
+ rc = upload_func(2 /* <id> <file> */, upload_argv);
if ( rc )
- return rc;
+ goto error;
- rc = action_func(1 /* only <id> */, 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 <id> */, upload_argv, ACTION_UNLOAD);
+error:
+ free(apply_argv);
free(path);
return rc;
}
@@ -1510,6 +1510,9 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action)
char n[XEN_LIVEPATCH_NAME_SIZE];
int rc;
+ if ( action->pad )
+ return -EINVAL;
+
rc = get_name(&action->name, n);
if ( rc )
return rc;
@@ -1583,9 +1586,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);
}
@@ -35,7 +35,7 @@
#include "domctl.h"
#include "physdev.h"
-#define XEN_SYSCTL_INTERFACE_VERSION 0x00000012
+#define XEN_SYSCTL_INTERFACE_VERSION 0x00000013
/*
* Read console content from Xen buffer ring.
@@ -970,6 +970,16 @@ struct xen_sysctl_livepatch_action {
/* hypervisor default. */
/* Or upper bound of time (ns) */
/* for operation to take. */
+
+/*
+ * Override 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)
+ uint32_t flags; /* IN: action flags. */
+ /* Provide additional parameters */
+ /* for an action. */
+ uint32_t pad; /* IN: Always zero. */
};
struct xen_sysctl_livepatch_op {