Merge branch 'livepatch.aws.v6' into staging

* livepatch.aws.v6:
  livepatch: Add metadata runtime retrieval mechanism
  livepatch: Handle arbitrary size names with the list operation
  livepatch: Add support for modules .modinfo section metadata
  livepatch: Add support for inline asm livepatching expectations
  livepatch: Add per-function applied/reverted state tracking marker
  livepatch: Do not enforce ELF_LIVEPATCH_FUNC section presence
  livepatch: Add support for apply|revert action replacement hooks
  livepatch: Implement pre-|post- apply|revert hooks
  livepatch: Export payload structure via livepatch_payload.h
  livepatch: Allow to override inter-modules buildid dependency
  livepatch: Always check hypervisor build ID upon livepatch upload

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
This commit is contained in:
Konrad Rzeszutek Wilk committed 2019-12-19 20:16:43 -05:00
commit 25164571fc
19 files changed
+2296 -287

No files matched your search

+2 -4
View File
@@ -308,10 +308,8 @@ xen/include/xen/acm_policy.h
xen/include/xen/compile.h
xen/include/xen/lib/x86/cpuid-autogen.h
xen/test/livepatch/config.h
xen/test/livepatch/xen_bye_world.livepatch
xen/test/livepatch/xen_hello_world.livepatch
xen/test/livepatch/xen_nop.livepatch
xen/test/livepatch/xen_replace_world.livepatch
xen/test/livepatch/expect_config.h
xen/test/livepatch/*.livepatch
xen/tools/kconfig/.tmp_gtkcheck
xen/tools/kconfig/.tmp_qtcheck
xen/tools/symbols
+221 -27
View File
@@ -1,4 +1,4 @@
# Xen Live Patching Design v1
# Xen Live Patching Design v2
## Rationale
@@ -23,6 +23,9 @@ The document is split in four sections:
* payload - telemetries of the old code along with binary blob of the new
function (if needed).
* reloc - telemetries contained in the payload to construct proper trampoline.
* hook - an auxiliary function being called before, during or after payload
application or revert.
* quiescing zone - period when all CPUs are lock-step with each other.
## History
@@ -270,6 +273,13 @@ like what the Linux kernel module loader does.
The payload contains at least three sections:
* `.livepatch.funcs` - which is an array of livepatch_func structures.
and/or any of:
* `.livepatch.hooks.{preapply,postapply,prerevert,postrevert}'
* `.livepatch.hooks.{apply,revert}`
- which are a pointer to a hook function pointer.
* `.livepatch.xen_depends` - which is an ELF Note that describes what Xen
build-id the payload depends on. **MUST** have one.
* `.livepatch.depends` - which is an ELF Note that describes what the payload
depends on. **MUST** have one.
* `.note.gnu.build-id` - the build-id of this payload. **MUST** have one.
@@ -287,10 +297,15 @@ which describe the functions to be patched:
uint32_t old_size;
uint8_t version;
uint8_t opaque[31];
/* Added to livepatch payload version 2: */
uint8_t applied;
uint8_t _pad[7];
livepatch_expectation_t expect;
};
The size of the structure is 64 bytes on 64-bit hypervisors. It will be
52 on 32-bit hypervisors.
The size of the structure is 104 bytes on 64-bit hypervisors. It will be
92 on 32-bit hypervisors.
The version 2 of the payload adds additional 8 bytes to the structure size.
* `name` is the symbol name of the old function. Only used if `old_addr` is
zero, otherwise will be used during dynamic linking (when hypervisor loads
@@ -314,9 +329,37 @@ The size of the structure is 64 bytes on 64-bit hypervisors. It will be
* If the value of `new_addr` is zero then `new_size` determines how many
instruction bytes to NOP (up to opaque size modulo smallest platform
instruction - 1 byte x86 and 4 bytes on ARM).
* `version` is to be one.
* `version` indicates version of the generated payload.
* `opaque` **MUST** be zero.
The version 2 of the payload adds the following fields to the structure:
* `applied` tracks function's applied/reverted state. It has a boolean type
either LIVEPATCH_FUNC_NOT_APPLIED or LIVEPATCH_FUNC_APPLIED.
* `_pad[7]` adds padding to align to 8 bytes.
* `expect` is an optional structure containing expected to-be-replaced data
(mostly for inline asm patching). The `expect` structure format is:
struct livepatch_expectation {
uint8_t enabled : 1;
uint8_t len : 5;
uint8_t rsv: 2;
uint8_t data[LIVEPATCH_OPAQUE_SIZE]; /* Same size as opaque[] buffer of
struct livepatch_func. This is the
max number of bytes to be patched */
};
typedef struct livepatch_expectation livepatch_expectation_t;
* `enabled` allows to enable the expectation check for given function.
Default state is disabled.
* `len` specifies the number of valid bytes in `data` array. 5 bits is
enough to specify values up to 32 (of bytes), which is above the array
size.
* `rsv` reserved bitfields. **MUST** be zero.
* `data` contains expected bytes of content to be replaced. Same size as
`opaque` buffer of `struct livepatch_func` (max number of bytes to be
patched).
The size of the `livepatch_func` array is determined from the ELF section
size.
@@ -328,12 +371,32 @@ When reverting a patch, the hypervisor iterates over each `livepatch_func`
and the core code copies the data from the undo buffer (private internal copy)
to `old_addr`.
It optionally may contain the address of functions to be called right before
being applied and after being reverted:
It optionally may contain the address of hooks to be called right before
being applied and after being reverted (while all CPUs are still in quiescing
zone). These hooks do not have access to payload structure.
* `.livepatch.hooks.load` - an array of function pointers.
* `.livepatch.hooks.unload` - an array of function pointers.
It optionally may also contain the address of pre- and post- vetoing hooks to
be called before (pre) or after (post) apply and revert payload actions (while
all CPUs are already released from quiescing zone). These hooks do have
access to payload structure. The pre-apply hook can prevent from loading the
payload if encoded in it condition is not met. Accordingly, the pre-revert
hook can prevent from unloading the livepatch if encoded in it condition is not
met.
* `.livepatch.hooks.{preapply,postapply}`
* `.livepatch.hooks.{prerevert,postrevert}`
- which are a pointer to a single hook function pointer.
Finally, it optionally may also contain the address of apply or revert action
hooks to be called instead of the default apply and revert payload actions
(while all CPUs are kept in quiescing zone). These hooks do have access to
payload structure.
* `.livepatch.hooks.{apply,revert}`
- which are a pointer to a single hook function pointer.
### Example of .livepatch.funcs
@@ -348,6 +411,10 @@ A simple example of what a payload file can be:
uint32_t old_size;
uint8_t version;
uint8_t pad[31];
/* Added to livepatch payload version 2: */
uint8_t applied;
uint8_t _pad[7];
livepatch_expectation_t expect;
};
/* Our replacement function for xen_extra_version. */
@@ -365,11 +432,20 @@ A simple example of what a payload file can be:
.old_addr = (void *)0xffff82d08013963c, /* Extracted from xen-syms. */
.new_size = 13, /* To be be computed by scripts. */
.old_size = 13, /* -----------""--------------- */
/* Added to livepatch payload version 2: */
.expect = { /* All fields to be filled manually */
.enabled = 1,
.len = 5,
.rsv = 0,
.data = { 0x48, 0x8d, 0x05, 0x33, 0x1C }
},
} __attribute__((__section__(".livepatch.funcs")));
Code must be compiled with `-fPIC`.
### .livepatch.hooks.load and .livepatch.hooks.unload
### Hooks
#### .livepatch.hooks.load and .livepatch.hooks.unload
This section contains an array of function pointers to be executed
before payload is being applied (.livepatch.funcs) or after reverting
@@ -383,16 +459,93 @@ The type definition of the function are as follow:
typedef void (*livepatch_loadcall_t)(void);
typedef void (*livepatch_unloadcall_t)(void);
### .livepatch.depends and .note.gnu.build-id
#### .livepatch.hooks.preapply
This section contains a pointer to a single function pointer to be executed
before apply action is scheduled (and thereby before CPUs are put into
quiescing zone). This is useful to prevent from applying a payload when
certain expected conditions aren't met or when mutating actions implemented
in the hook fail or cannot be executed.
This type of hooks do have access to payload structure.
Each entry in this array is eight bytes.
The type definition of the function are as follow:
typedef int livepatch_precall_t(livepatch_payload_t *arg);
#### .livepatch.hooks.postapply
This section contains a pointer to a single function pointer to be executed
after apply action has finished and after all CPUs left the quiescing zone.
This is useful to provide an ability to follow up on actions performed by
the preapply hook. Especially, when module application was successful or to
be able to undo certain preparation steps of the preapply hook in case of a
failure. The success/failure error code is provided to the postapply hooks
via the `rc` field of the payload structure.
This type of hooks do have access to payload structure.
Each entry in this array is eight bytes.
The type definition of the function are as follow:
typedef void livepatch_postcall_t(livepatch_payload_t *arg);
#### .livepatch.hooks.prerevert
This section contains a pointer to a single function pointer to be executed
before revert action is scheduled (and thereby before CPUs are put into
quiescing zone). This is useful to prevent from reverting a payload when
certain expected conditions aren't met or when mutating actions implemented
in the hook fail or cannot be executed.
This type of hooks do have access to payload structure.
Each entry in this array is eight bytes.
The type definition of the function are as follow:
typedef int livepatch_precall_t(livepatch_payload_t *arg);
#### .livepatch.hooks.postrevert
This section contains a pointer to a single function pointer to be executed
after revert action has finished and after all CPUs left the quiescing zone.
This is useful to provide an ability to perform cleanup of all previously
executed mutating actions in order to restore the original system state from
before the current payload application. The success/failure error code is
provided to the postrevert hook via the `rc` field of the payload structure.
This type of hooks do have access to payload structure.
Each entry in this array is eight bytes.
The type definition of the function are as follow:
typedef void livepatch_postcall_t(livepatch_payload_t *arg);
#### .livepatch.hooks.apply and .livepatch.hooks.revert
This section contains a pointer to a single function pointer to be executed
instead of a default apply (or revert) action function. This is useful to
replace or augment default behavior of the apply (or revert) action that
requires all CPUs to be in the quiescing zone.
This type of hooks do have access to payload structure.
Each entry in this array is eight bytes.
The type definition of the function are as follow:
typedef int livepatch_actioncall_t(livepatch_payload_t *arg);
### .livepatch.xen_depends, .livepatch.depends and .note.gnu.build-id
To support dependencies checking and safe loading (to load the
appropiate payload against the right hypervisor) there is a need
to embbed an build-id dependency.
This is done by the payload containing an section `.livepatch.depends`
which follows the format of an ELF Note. The contents of this
(name, and description) are specific to the linker utilized to
build the hypevisor and payload.
This is done by the payload containing sections `.livepatch.xen_depends`
and `.livepatch.depends` which follow the format of an ELF Note.
The contents of these (name, and description) are specific to the linker
utilized to build the hypevisor and payload.
If GNU linker is used then the name is `GNU` and the description
is a NT_GNU_BUILD_ID type ID. The description can be an SHA1
@@ -400,6 +553,13 @@ checksum, MD5 checksum or any unique value.
The size of these structures varies with the `--build-id` linker option.
There are two kinds of build-id dependencies:
* Xen build-id dependency (.livepatch.xen_depends section)
* previous payload build-id dependency (.livepatch.depends section)
See "Live patch interdependencies" for more information.
## Hypercalls
We will employ the sub operations of the system management hypercall (sysctl).
@@ -547,8 +707,8 @@ The structure is as follow:
### XEN_SYSCTL_LIVEPATCH_LIST (2)
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.
The caller provides:
@@ -557,27 +717,41 @@ The caller provides:
* `idx` Index iterator. The index into the hypervisor's payload count. It is
recommended that on first invocation zero be used so that `nr` (which the
hypervisor will update with the remaining payload count) be provided.
Also the hypervisor will provide `version` with the most current value.
Also the hypervisor will provide `version` with the most current value,
calculated total size of all payloads' names and calculated total size of
all payload's metadata.
* `nr` The max number of entries to populate. Can be zero which will result
in the hypercall being a probing one and return the number of payloads
(and update the `version`).
* `pad` - *MUST* be zero.
* `status` Virtual address of where to write `struct xen_livepatch_status`
structures. Caller *MUST* allocate up to `nr` of them.
* `name` - Virtual address of where to write the unique name of the payload.
Caller *MUST* allocate up to `nr` of them. Each *MUST* be of
**XEN_LIVEPATCH_NAME_SIZE** size. Note that **XEN_LIVEPATCH_NAME_SIZE** includes
the NUL terminator.
* `name` - Virtual address of where to write the unique name of the payloads.
Caller *MUST* allocate enough space to be able to store all received data
(i.e. total allocated space *MUST* match the `name_total_size` value
provided by the hypervisor). Individual payload name cannot be longer than
**XEN_LIVEPATCH_NAME_SIZE** bytes. Note that **XEN_LIVEPATCH_NAME_SIZE**
includes the NUL terminator.
* `len` - Virtual address of where to write the length of each unique name
of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST* be
of sizeof(uint32_t) (4 bytes).
* `metadata` - Virtual address of where to write the metadata of the payloads.
Caller *MUST* allocate enough space to be able to store all received data
(i.e. total allocated space *MUST* match the `metadata_total_size` value
provided by the hypervisor). Individual payload metadata string can be of
arbitrary length. The metadata string format is: key=value\0...key=value\0.
* `metadata_len` - Virtual address of where to write the length of each metadata
string of the payload. Caller *MUST* allocate up to `nr` of them. Each *MUST*
be of sizeof(uint32_t) (4 bytes).
If the hypercall returns an positive number, it is the number (upto `nr`
provided to the hypercall) 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.
fail), `name_total_size` and `metadata_total_size` containing total sizes of
transferred 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 -XEN_E2BIG the `nr` is too big and should be
lowered.
@@ -615,13 +789,22 @@ The structure is as follow:
amount of payloads and version.
OUT: How many payloads left. */
uint32_t pad; /* IN: Must be zero. */
uint32_t name_total_size; /* OUT: Total size of all transfer names */
uint32_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) id; /* OUT: Array of names. Each member
MUST XEN_LIVEPATCH_NAME_SIZE in size.
Must have nr of them. */
XEN_GUEST_HANDLE_64(char) name; /* OUT: Array of names. Each member
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. */
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. */
};
### XEN_SYSCTL_LIVEPATCH_ACTION (3)
@@ -650,6 +833,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.
@@ -667,6 +854,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. */
};
@@ -894,13 +1085,16 @@ but is more complex to implement.
The second option which requires an build-id of the hypervisor
is implemented in the Xen hypervisor.
Specifically each payload has two build-id ELF notes:
Specifically each payload has three build-id ELF notes:
* The build-id of the payload itself (generated via --build-id).
* The build-id of the Xen hypervisor it depends on (extracted from the
hypervisor during build time).
* The build-id of the payload it depends on (extracted from the
the previous payload or hypervisor during build time).
This means that the very first payload depends on the hypervisor
build-id.
This means that every payload depends on the hypervisor build-id and on
the build-id of the previous payload in the stack.
The very first payload depends on the hypervisor build-id only.
# Not Yet Done
+49 -19
View File
@@ -2558,7 +2558,28 @@ 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 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.
*
* 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,
uint32_t *name_total_size,
uint32_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
@@ -2569,23 +2590,27 @@ 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
* 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', 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', '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.
*
* 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.
*
* 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'.
@@ -2595,21 +2620,26 @@ 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 uint32_t name_total_size,
char *metadata, uint32_t *metadata_len,
const uint32_t metadata_total_size,
unsigned int *done, unsigned int *left);
/*
* The operations are asynchronous and the hypervisor may take a while
* 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
+130 -33
View File
@@ -662,7 +662,52 @@ 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 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.
*
* 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,
uint32_t *name_total_size,
uint32_t *metadata_total_size)
{
DECLARE_SYSCTL;
int rc;
if ( !nr || !name_total_size || !metadata_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;
*metadata_total_size = sysctl.u.livepatch.u.list.metadata_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
* - 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
@@ -673,23 +718,27 @@ 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
* 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', 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', '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.
*
* 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.
*
* 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'.
@@ -699,11 +748,14 @@ 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 uint32_t name_total_size,
char *metadata, uint32_t *metadata_len,
const uint32_t metadata_total_size,
unsigned int *done, unsigned int *left)
{
int rc;
DECLARE_SYSCTL;
@@ -711,30 +763,40 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start,
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;
ssize_t sz;
uint32_t name_off = 0, metadata_off = 0;
uint32_t name_sz, metadata_sz;
if ( !max || !info || !name || !len )
if ( !max || !info || !name || !len ||
!metadata || !metadata_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;
metadata_sz = metadata_total_size;
*done = 0;
*left = 0;
do {
uint32_t _name_sz, _metadata_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,12 +816,16 @@ 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));
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 + (sz * *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 )
@@ -773,9 +839,19 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start,
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);
/*
@@ -792,6 +868,8 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start,
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. */
@@ -816,6 +894,8 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start,
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;
}
@@ -827,14 +907,26 @@ 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. */
_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, (rc * sz));
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;
/* Update idx. */
@@ -846,6 +938,8 @@ int xc_livepatch_list(xc_interface *xch, unsigned int max, unsigned int start,
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;
@@ -854,7 +948,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 +975,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 +988,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);
}
/*
+185 -70
View File
@@ -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);
}
@@ -59,14 +64,15 @@ 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;
char *metadata = NULL;
uint32_t *len = NULL;
uint32_t *metadata_len = NULL;
uint32_t name_total_size, metadata_total_size, name_off, metadata_off;
int rc = ENOMEM;
if ( argc )
@@ -74,65 +80,96 @@ static int list_func(int argc, char *argv[])
show_help();
return -1;
}
idx = left = 0;
info = malloc(sizeof(*info) * MAX_LEN);
done = left = 0;
rc = xc_livepatch_list_get_sizes(xch, &nr, &name_total_size, &metadata_total_size);
if ( rc )
{
rc = errno;
fprintf(stderr, "Failed to get list sizes.\n"
"Error %d: %s\n",
rc, strerror(rc));
return rc;
}
if ( nr == 0 )
{
fprintf(stdout, "Nothing to list\n");
return 0;
}
info = malloc(nr * sizeof(*info));
if ( !info )
return rc;
name = malloc(sizeof(*name) * XEN_LIVEPATCH_NAME_SIZE * MAX_LEN);
name = malloc(name_total_size * sizeof(*name));
if ( !name )
goto error_name;
len = malloc(nr * sizeof(*len));
if ( !len )
goto error_len;
metadata = malloc(metadata_total_size * sizeof(*metadata) + 1);
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));
memset(metadata, 'D', metadata_total_size * sizeof(*metadata) + 1);
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,
metadata, metadata_len, metadata_total_size, &done, &left);
if ( rc || done != nr || left > 0)
{
free(info);
return rc;
}
len = malloc(sizeof(*len) * MAX_LEN);
if ( !len ) {
free(name);
free(info);
return rc;
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 | metadata\n"
"----------------------------------------+------------+---------------\n");
for ( i = 0; i < done; i++ )
{
unsigned int j;
uint32_t sz;
char *str;
for ( i = 0; i < done; i++ )
{
unsigned int j;
char *name_str = name + name_off;
char *metadata_str = metadata + metadata_off;
sz = len[i];
str = name + (i * XEN_LIVEPATCH_NAME_SIZE);
for ( j = sz; j < XEN_LIVEPATCH_NAME_SIZE; j++ )
str[j] = '\0';
printf("%-40.*s| %s", len[i], name_str, state2str(info[i].state));
if ( info[i].rc )
printf(" (%d, %s) | ", -info[i].rc, strerror(-info[i].rc));
else
printf(" | ");
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 );
/* Replace all '\0' with semi-colons. */
for ( j = 0; metadata_len[i] && j < metadata_len[i] - 1; j++ )
metadata_str[j] = (metadata_str[j] ?: ';');
printf("%.*s\n", metadata_len[i], metadata_str);
free(name);
free(info);
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);
error_name:
free(info);
return rc;
}
#undef MAX_LEN
@@ -225,12 +262,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 +276,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 +304,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 +389,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 +400,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 +434,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 +496,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 +521,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;
}
+560 -114
View File
@@ -28,6 +28,8 @@
#include <asm/alternative.h>
#include <asm/event.h>
#define is_hook_enabled(hook) ({ (hook) && *(hook); })
/*
* Protects against payload_list operations and also allows only one
* caller in schedule_work.
@@ -45,42 +47,6 @@ static LIST_HEAD(applied_list);
static unsigned int payload_cnt;
static unsigned int payload_version = 1;
/* To contain the ELF Note header. */
struct livepatch_build_id {
const void *p;
unsigned int len;
};
struct payload {
uint32_t state; /* One of the LIVEPATCH_STATE_*. */
int32_t rc; /* 0 or -XEN_EXX. */
bool reverted; /* Whether it was reverted. */
bool safe_to_reapply; /* Can apply safely after revert. */
struct list_head list; /* Linked to 'payload_list'. */
const void *text_addr; /* Virtual address of .text. */
size_t text_size; /* .. and its size. */
const void *rw_addr; /* Virtual address of .data. */
size_t rw_size; /* .. and its size (if any). */
const void *ro_addr; /* Virtual address of .rodata. */
size_t ro_size; /* .. and its size (if any). */
unsigned int pages; /* Total pages for [text,rw,ro]_addr */
struct list_head applied_list; /* Linked to 'applied_list'. */
struct livepatch_func *funcs; /* The array of functions to patch. */
unsigned int nfuncs; /* Nr of functions to patch. */
const struct livepatch_symbol *symtab; /* All symbols. */
const char *strtab; /* Pointer to .strtab. */
struct virtual_region region; /* symbol, bug.frame patching and
exception table (x86). */
unsigned int nsyms; /* Nr of entries in .strtab and symbols. */
struct livepatch_build_id id; /* ELFNOTE_DESC(.note.gnu.build-id) of the payload. */
struct livepatch_build_id dep; /* ELFNOTE_DESC(.livepatch.depends). */
livepatch_loadcall_t *const *load_funcs; /* The array of funcs to call after */
livepatch_unloadcall_t *const *unload_funcs;/* load and unload of the 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. */
};
/* Defines an outstanding patching action. */
struct livepatch_work
{
@@ -476,11 +442,33 @@ static bool section_ok(const struct livepatch_elf *elf,
return true;
}
static int xen_build_id_dep(const struct payload *payload)
{
const void *id = NULL;
unsigned int len = 0;
int rc;
ASSERT(payload->xen_dep.len);
ASSERT(payload->xen_dep.p);
rc = xen_build_id(&id, &len);
if ( rc )
return rc;
if ( payload->xen_dep.len != len || memcmp(id, payload->xen_dep.p, len) ) {
printk(XENLOG_ERR LIVEPATCH "%s: check against hypervisor build-id failed\n",
payload->name);
return -EINVAL;
}
return 0;
}
static int check_special_sections(const struct livepatch_elf *elf)
{
unsigned int i;
static const char *const names[] = { ELF_LIVEPATCH_FUNC,
ELF_LIVEPATCH_DEPENDS,
static const char *const names[] = { ELF_LIVEPATCH_DEPENDS,
ELF_LIVEPATCH_XEN_DEPENDS,
ELF_BUILD_ID_NOTE};
DECLARE_BITMAP(found, ARRAY_SIZE(names)) = { 0 };
@@ -514,6 +502,148 @@ static int check_special_sections(const struct livepatch_elf *elf)
return 0;
}
static int check_patching_sections(const struct livepatch_elf *elf)
{
unsigned int i;
static const char *const names[] = { ELF_LIVEPATCH_FUNC,
ELF_LIVEPATCH_LOAD_HOOKS,
ELF_LIVEPATCH_UNLOAD_HOOKS,
ELF_LIVEPATCH_PREAPPLY_HOOK,
ELF_LIVEPATCH_APPLY_HOOK,
ELF_LIVEPATCH_POSTAPPLY_HOOK,
ELF_LIVEPATCH_PREREVERT_HOOK,
ELF_LIVEPATCH_REVERT_HOOK,
ELF_LIVEPATCH_POSTREVERT_HOOK};
DECLARE_BITMAP(found, ARRAY_SIZE(names)) = { 0 };
/*
* The patching sections are optional, but at least one
* must be present. Otherwise, there is nothing to do.
* All the existing sections must not be empty and must
* be present at most once.
*/
for ( i = 0; i < ARRAY_SIZE(names); i++ )
{
const struct livepatch_elf_sec *sec;
sec = livepatch_elf_sec_by_name(elf, names[i]);
if ( !sec )
{
dprintk(XENLOG_DEBUG, LIVEPATCH "%s: %s is missing\n",
elf->name, names[i]);
continue; /* This section is optional */
}
if ( !sec->sec->sh_size )
{
printk(XENLOG_ERR LIVEPATCH "%s: %s is empty\n",
elf->name, names[i]);
return -EINVAL;
}
if ( test_and_set_bit(i, found) )
{
printk(XENLOG_ERR LIVEPATCH "%s: %s was seen more than once\n",
elf->name, names[i]);
return -EINVAL;
}
}
/* Checking if at least one section is present. */
if ( bitmap_empty(found, ARRAY_SIZE(names)) )
{
printk(XENLOG_ERR LIVEPATCH "%s: Nothing to patch. Aborting...\n",
elf->name);
return -EINVAL;
}
return 0;
}
static inline int livepatch_verify_expectation_fn(const struct livepatch_func *func)
{
const livepatch_expectation_t *exp = &func->expect;
/* Ignore disabled expectations. */
if ( !exp->enabled )
return 0;
/* There is nothing to expect */
if ( !func->old_addr )
return -EFAULT;
if ( exp->len > sizeof(exp->data))
return -EOVERFLOW;
if ( exp->rsv )
return -EINVAL;
/* Incorrect expectation */
if ( func->old_size < exp->len )
return -ERANGE;
if ( memcmp(func->old_addr, exp->data, exp->len) )
{
printk(XENLOG_ERR LIVEPATCH "%s: expectation failed: expected:%*phN, actual:%*phN\n",
func->name, exp->len, exp->data, exp->len, func->old_addr);
return -EINVAL;
}
return 0;
}
static inline int livepatch_check_expectations(const struct payload *payload)
{
int i, rc;
printk(XENLOG_INFO LIVEPATCH "%s: Verifying enabled expectations for all functions\n",
payload->name);
for ( i = 0; i < payload->nfuncs; i++ )
{
const struct livepatch_func *func = &(payload->funcs[i]);
rc = livepatch_verify_expectation_fn(func);
if ( rc )
{
printk(XENLOG_ERR LIVEPATCH "%s: expectations of %s failed (rc=%d), aborting!\n",
payload->name, func->name ?: "unknown", rc);
return rc;
}
}
return 0;
}
/*
* Lookup specified section and when exists assign its address to a specified hook.
* Perform section pointer and size validation: single hook sections must contain a
* single pointer only.
*/
#define LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, hook, section_name) do { \
const struct livepatch_elf_sec *__sec = livepatch_elf_sec_by_name(elf, section_name); \
if ( !__sec ) \
break; \
if ( !section_ok(elf, __sec, sizeof(*hook)) || __sec->sec->sh_size != sizeof(*hook) ) \
return -EINVAL; \
hook = __sec->load_addr; \
} while (0)
/*
* Lookup specified section and when exists assign its address to a specified hook.
* Perform section pointer and size validation: multi hook sections must contain an
* array whose size must be a multiple of the array's items size.
*/
#define LIVEPATCH_ASSIGN_MULTI_HOOK(elf, hook, nhooks, section_name) do { \
const struct livepatch_elf_sec *__sec = livepatch_elf_sec_by_name(elf, section_name); \
if ( !__sec ) \
break; \
if ( !section_ok(elf, __sec, sizeof(*hook)) ) \
return -EINVAL; \
hook = __sec->load_addr; \
nhooks = __sec->sec->sh_size / sizeof(*hook); \
} while (0)
static int prepare_payload(struct payload *payload,
struct livepatch_elf *elf)
{
@@ -524,66 +654,60 @@ static int prepare_payload(struct payload *payload,
const Elf_Note *n;
sec = livepatch_elf_sec_by_name(elf, ELF_LIVEPATCH_FUNC);
ASSERT(sec);
if ( !section_ok(elf, sec, sizeof(*payload->funcs)) )
return -EINVAL;
payload->funcs = sec->load_addr;
payload->nfuncs = sec->sec->sh_size / sizeof(*payload->funcs);
for ( i = 0; i < payload->nfuncs; i++ )
{
int rc;
f = &(payload->funcs[i]);
if ( f->version != LIVEPATCH_PAYLOAD_VERSION )
{
printk(XENLOG_ERR LIVEPATCH "%s: Wrong version (%u). Expected %d\n",
elf->name, f->version, LIVEPATCH_PAYLOAD_VERSION);
return -EOPNOTSUPP;
}
/* 'old_addr', 'new_addr', 'new_size' can all be zero. */
if ( !f->old_size )
{
printk(XENLOG_ERR LIVEPATCH "%s: Address or size fields are zero\n",
elf->name);
return -EINVAL;
}
rc = arch_livepatch_verify_func(f);
if ( rc )
return rc;
rc = resolve_old_address(f, elf);
if ( rc )
return rc;
rc = livepatch_verify_distance(f);
if ( rc )
return rc;
}
sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.load");
if ( sec )
{
if ( !section_ok(elf, sec, sizeof(*payload->load_funcs)) )
if ( !section_ok(elf, sec, sizeof(*payload->funcs)) )
return -EINVAL;
payload->load_funcs = sec->load_addr;
payload->n_load_funcs = sec->sec->sh_size / sizeof(*payload->load_funcs);
payload->funcs = sec->load_addr;
payload->nfuncs = sec->sec->sh_size / sizeof(*payload->funcs);
for ( i = 0; i < payload->nfuncs; i++ )
{
int rc;
f = &(payload->funcs[i]);
if ( f->version != LIVEPATCH_PAYLOAD_VERSION )
{
printk(XENLOG_ERR LIVEPATCH "%s: Wrong version (%u). Expected %d\n",
elf->name, f->version, LIVEPATCH_PAYLOAD_VERSION);
return -EOPNOTSUPP;
}
/* 'old_addr', 'new_addr', 'new_size' can all be zero. */
if ( !f->old_size )
{
printk(XENLOG_ERR LIVEPATCH "%s: Address or size fields are zero\n",
elf->name);
return -EINVAL;
}
rc = arch_livepatch_verify_func(f);
if ( rc )
return rc;
rc = resolve_old_address(f, elf);
if ( rc )
return rc;
rc = livepatch_verify_distance(f);
if ( rc )
return rc;
}
}
sec = livepatch_elf_sec_by_name(elf, ".livepatch.hooks.unload");
if ( sec )
{
if ( !section_ok(elf, sec, sizeof(*payload->unload_funcs)) )
return -EINVAL;
LIVEPATCH_ASSIGN_MULTI_HOOK(elf, payload->load_funcs, payload->n_load_funcs, ELF_LIVEPATCH_LOAD_HOOKS);
LIVEPATCH_ASSIGN_MULTI_HOOK(elf, payload->unload_funcs, payload->n_unload_funcs, ELF_LIVEPATCH_UNLOAD_HOOKS);
LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.pre, ELF_LIVEPATCH_PREAPPLY_HOOK);
LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.action, ELF_LIVEPATCH_APPLY_HOOK);
LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.apply.post, ELF_LIVEPATCH_POSTAPPLY_HOOK);
LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.pre, ELF_LIVEPATCH_PREREVERT_HOOK);
LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.action, ELF_LIVEPATCH_REVERT_HOOK);
LIVEPATCH_ASSIGN_SINGLE_HOOK(elf, payload->hooks.revert.post, ELF_LIVEPATCH_POSTREVERT_HOOK);
payload->unload_funcs = sec->load_addr;
payload->n_unload_funcs = sec->sec->sh_size / sizeof(*payload->unload_funcs);
}
sec = livepatch_elf_sec_by_name(elf, ELF_BUILD_ID_NOTE);
if ( sec )
{
@@ -632,6 +756,22 @@ static int prepare_payload(struct payload *payload,
return -EINVAL;
}
sec = livepatch_elf_sec_by_name(elf, ELF_LIVEPATCH_XEN_DEPENDS);
if ( sec )
{
n = sec->load_addr;
if ( sec->sec->sh_size <= sizeof(*n) )
return -EINVAL;
if ( xen_build_id_check(n, sec->sec->sh_size,
&payload->xen_dep.p, &payload->xen_dep.len) )
return -EINVAL;
if ( !payload->xen_dep.len || !payload->xen_dep.p )
return -EINVAL;
}
/* Setup the virtual region with proper data. */
region = &payload->region;
@@ -713,6 +853,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;
}
@@ -760,8 +917,6 @@ static int build_symbol_table(struct payload *payload,
struct livepatch_symbol *symtab;
char *strtab;
ASSERT(payload->nfuncs);
/* Recall that section @0 is always NULL. */
for ( i = 1; i < elf->nsym; i++ )
{
@@ -878,10 +1033,18 @@ static int load_payload_data(struct payload *payload, void *raw, size_t len)
if ( rc )
goto out;
rc = check_patching_sections(&elf);
if ( rc )
goto out;
rc = prepare_payload(payload, &elf);
if ( rc )
goto out;
rc = xen_build_id_dep(payload);
if ( rc )
goto out;
rc = build_symbol_table(payload, &elf);
if ( rc )
goto out;
@@ -1001,8 +1164,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->name, XEN_LIVEPATCH_NAME_SIZE * 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);
@@ -1012,35 +1175,66 @@ static int livepatch_list(struct xen_sysctl_livepatch_list *list)
return -EINVAL;
}
list->name_total_size = 0;
list->metadata_total_size = 0;
if ( list->nr )
{
uint64_t name_offset = 0, metadata_offset = 0;
list_for_each_entry( data, &payload_list, list )
{
uint32_t len;
uint32_t name_len, metadata_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;
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) ||
!guest_handle_subrange_okay(list->metadata, metadata_offset,
metadata_offset + metadata_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) ||
__copy_to_guest_offset(list->status, idx, &status, 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) ||
__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;
}
idx++;
name_offset += name_len;
metadata_offset += metadata_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->metadata_total_size += data->metadata.len;
}
}
list->nr = payload_cnt - i; /* Remaining amount. */
list->version = payload_version;
spin_unlock(&payload_lock);
@@ -1055,6 +1249,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;
@@ -1091,10 +1298,17 @@ static int apply_payload(struct payload *data)
ASSERT(!local_irq_is_enabled());
for ( i = 0; i < data->nfuncs; i++ )
arch_livepatch_apply(&data->funcs[i]);
common_livepatch_apply(&data->funcs[i]);
arch_livepatch_revive();
livepatch_display_metadata(&data->metadata);
return 0;
}
static inline void apply_payload_tail(struct payload *data)
{
/*
* We need RCU variant (which has barriers) in case we crash here.
* The applied_list is iterated by the trap code.
@@ -1102,7 +1316,7 @@ static int apply_payload(struct payload *data)
list_add_tail_rcu(&data->applied_list, &applied_list);
register_virtual_region(&data->region);
return 0;
data->state = LIVEPATCH_STATE_APPLIED;
}
static int revert_payload(struct payload *data)
@@ -1120,7 +1334,7 @@ static int revert_payload(struct payload *data)
}
for ( i = 0; i < data->nfuncs; i++ )
arch_livepatch_revert(&data->funcs[i]);
common_livepatch_revert(&data->funcs[i]);
/*
* Since we are running with IRQs disabled and the hooks may call common
@@ -1135,6 +1349,11 @@ static int revert_payload(struct payload *data)
ASSERT(!local_irq_is_enabled());
arch_livepatch_revive();
return 0;
}
static inline void revert_payload_tail(struct payload *data)
{
/*
* We need RCU variant (which has barriers) in case we crash here.
@@ -1144,7 +1363,30 @@ static int revert_payload(struct payload *data)
unregister_virtual_region(&data->region);
data->reverted = true;
return 0;
data->state = LIVEPATCH_STATE_CHECKED;
}
/*
* Check if an action has applied the same state to all payload's functions consistently.
*/
static inline bool was_action_consistent(const struct payload *data, livepatch_func_state_t expected_state)
{
int i;
for ( i = 0; i < data->nfuncs; i++ )
{
struct livepatch_func *f = &(data->funcs[i]);
if ( f->applied != expected_state )
{
printk(XENLOG_ERR LIVEPATCH "%s: Payload has a function: '%s' with inconsistent applied state.\n",
data->name, f->name ?: "noname");
return false;
}
}
return true;
}
/*
@@ -1164,15 +1406,37 @@ static void livepatch_do_action(void)
switch ( livepatch_work.cmd )
{
case LIVEPATCH_ACTION_APPLY:
rc = apply_payload(data);
if ( is_hook_enabled(data->hooks.apply.action) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling apply action hook function\n", data->name);
rc = (*data->hooks.apply.action)(data);
}
else
rc = apply_payload(data);
if ( !was_action_consistent(data, rc ? LIVEPATCH_FUNC_NOT_APPLIED : LIVEPATCH_FUNC_APPLIED) )
panic("livepatch: partially applied payload '%s'!\n", data->name);
if ( rc == 0 )
data->state = LIVEPATCH_STATE_APPLIED;
apply_payload_tail(data);
break;
case LIVEPATCH_ACTION_REVERT:
rc = revert_payload(data);
if ( is_hook_enabled(data->hooks.revert.action) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling revert action hook function\n", data->name);
rc = (*data->hooks.revert.action)(data);
}
else
rc = revert_payload(data);
if ( !was_action_consistent(data, rc ? LIVEPATCH_FUNC_APPLIED : LIVEPATCH_FUNC_NOT_APPLIED) )
panic("livepatch: partially reverted payload '%s'!\n", data->name);
if ( rc == 0 )
data->state = LIVEPATCH_STATE_CHECKED;
revert_payload_tail(data);
break;
case LIVEPATCH_ACTION_REPLACE:
@@ -1183,9 +1447,20 @@ static void livepatch_do_action(void)
*/
list_for_each_entry_safe_reverse ( other, tmp, &applied_list, applied_list )
{
other->rc = revert_payload(other);
if ( is_hook_enabled(other->hooks.revert.action) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling revert action hook function\n", other->name);
other->rc = (*other->hooks.revert.action)(other);
}
else
other->rc = revert_payload(other);
if ( !was_action_consistent(other, rc ? LIVEPATCH_FUNC_APPLIED : LIVEPATCH_FUNC_NOT_APPLIED) )
panic("livepatch: partially reverted payload '%s'!\n", other->name);
if ( other->rc == 0 )
other->state = LIVEPATCH_STATE_CHECKED;
revert_payload_tail(other);
else
{
rc = -EINVAL;
@@ -1195,9 +1470,34 @@ static void livepatch_do_action(void)
if ( rc == 0 )
{
rc = apply_payload(data);
/*
* Make sure all expectation requirements are met.
* Beware all the payloads are reverted at this point.
* If expectations are not met the system is left in a
* completely UNPATCHED state!
*/
rc = livepatch_check_expectations(data);
if ( rc )
{
printk(XENLOG_ERR LIVEPATCH "%s: SYSTEM MIGHT BE INSECURE: "
"Replace action has been aborted after reverting ALL payloads!\n", data->name);
break;
}
if ( is_hook_enabled(data->hooks.apply.action) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling apply action hook function\n", data->name);
rc = (*data->hooks.apply.action)(data);
}
else
rc = apply_payload(data);
if ( !was_action_consistent(data, rc ? LIVEPATCH_FUNC_NOT_APPLIED : LIVEPATCH_FUNC_APPLIED) )
panic("livepatch: partially applied payload '%s'!\n", data->name);
if ( rc == 0 )
data->state = LIVEPATCH_STATE_APPLIED;
apply_payload_tail(data);
}
break;
@@ -1218,6 +1518,39 @@ static bool_t is_work_scheduled(const struct payload *data)
return livepatch_work.do_work && livepatch_work.data == data;
}
/*
* Check if payload has any of the vetoing, non-atomic hooks assigned.
* A vetoing, non-atmic hook may perform an operation that changes the
* hypervisor state and may not be guaranteed to succeed. Result of
* such operation may be returned and may change the livepatch workflow.
* Such hooks may require additional cleanup actions performed by other
* hooks. Thus they are not suitable for replace action.
*/
static inline bool has_payload_any_vetoing_hooks(const struct payload *payload)
{
return is_hook_enabled(payload->hooks.apply.pre) ||
is_hook_enabled(payload->hooks.apply.post) ||
is_hook_enabled(payload->hooks.revert.pre) ||
is_hook_enabled(payload->hooks.revert.post);
}
/*
* Checks if any of the already applied livepatches has any vetoing,
* non-atomic hooks assigned.
*/
static inline bool livepatch_applied_have_vetoing_hooks(void)
{
struct payload *p;
list_for_each_entry ( p, &applied_list, applied_list )
{
if ( has_payload_any_vetoing_hooks(p) )
return true;
}
return false;
}
static int schedule_work(struct payload *data, uint32_t cmd, uint32_t timeout)
{
ASSERT(spin_is_locked(&payload_lock));
@@ -1318,6 +1651,7 @@ void check_for_livepatch_work(void)
{
struct payload *p;
unsigned int cpus;
bool action_done = false;
p = livepatch_work.data;
if ( !get_cpu_maps() )
@@ -1370,6 +1704,7 @@ void check_for_livepatch_work(void)
livepatch_do_action();
/* Serialize and flush out the CPU via CPUID instruction (on x86). */
arch_livepatch_post_action();
action_done = true;
local_irq_restore(flags);
}
@@ -1382,6 +1717,43 @@ void check_for_livepatch_work(void)
/* put_cpu_maps has an barrier(). */
put_cpu_maps();
if ( action_done )
{
switch ( livepatch_work.cmd )
{
case LIVEPATCH_ACTION_REVERT:
if ( is_hook_enabled(p->hooks.revert.post) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling post-revert hook function with rc=%d\n",
p->name, p->rc);
(*p->hooks.revert.post)(p);
}
break;
case LIVEPATCH_ACTION_APPLY:
if ( is_hook_enabled(p->hooks.apply.post) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling post-apply hook function with rc=%d\n",
p->name, p->rc);
(*p->hooks.apply.post)(p);
}
break;
case LIVEPATCH_ACTION_REPLACE:
if ( has_payload_any_vetoing_hooks(p) )
{
/* It should be impossible to get here since livepatch_action() guards against that. */
panic(LIVEPATCH "%s: REPLACE action is not supported on livepatches with vetoing hooks!\n",
p->name);
ASSERT_UNREACHABLE();
}
default:
break;
}
}
printk(XENLOG_INFO LIVEPATCH "%s finished %s with rc=%d\n",
p->name, names[livepatch_work.cmd], p->rc);
}
@@ -1466,6 +1838,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;
@@ -1517,6 +1892,21 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action)
rc = -EBUSY;
break;
}
if ( is_hook_enabled(data->hooks.revert.pre) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling pre-revert hook function\n", data->name);
rc = (*data->hooks.revert.pre)(data);
if ( rc )
{
printk(XENLOG_ERR LIVEPATCH "%s: pre-revert hook failed (rc=%d), aborting!\n",
data->name, rc);
data->rc = rc;
break;
}
}
data->rc = -EAGAIN;
rc = schedule_work(data, action->cmd, action->timeout);
}
@@ -1539,9 +1929,36 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action)
break;
}
rc = build_id_dep(data, !!list_empty(&applied_list));
/*
* 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;
}
/* Make sure all expectation requirements are met. */
rc = livepatch_check_expectations(data);
if ( rc )
break;
if ( is_hook_enabled(data->hooks.apply.pre) )
{
printk(XENLOG_INFO LIVEPATCH "%s: Calling pre-apply hook function\n", data->name);
rc = (*data->hooks.apply.pre)(data);
if ( rc )
{
printk(XENLOG_ERR LIVEPATCH "%s: pre-apply hook failed (rc=%d), aborting!\n",
data->name, rc);
data->rc = rc;
break;
}
}
data->rc = -EAGAIN;
rc = schedule_work(data, action->cmd, action->timeout);
}
@@ -1553,6 +1970,30 @@ static int livepatch_action(struct xen_sysctl_livepatch_action *action)
rc = build_id_dep(data, 1 /* against hypervisor. */);
if ( rc )
break;
/*
* REPLACE action is not supported on livepatches with vetoing hooks.
* Vetoing hooks usually perform mutating actions on the system and
* typically exist in pairs (pre- hook doing an action and post- hook
* undoing the action). Coalescing all hooks from all applied modules
* cannot be performed without inspecting potential dependencies between
* the mutating hooks and hence cannot be performed automatically by
* the replace action. Also, the replace action cannot safely assume a
* successful revert of all the module with vetoing hooks. When one
* of the hooks fails due to not meeting certain conditions the whole
* replace operation must have been reverted with all previous pre- and
* post- hooks re-executed (which cannot be guaranteed to succeed).
* The simplest response to this complication is disallow replace
* action on modules with vetoing hooks.
*/
if ( has_payload_any_vetoing_hooks(data) || livepatch_applied_have_vetoing_hooks() )
{
printk(XENLOG_ERR LIVEPATCH "%s: REPLACE action is not supported on livepatches with vetoing hooks!\n",
data->name);
rc = -EOPNOTSUPP;
break;
}
data->rc = -EAGAIN;
rc = schedule_work(data, action->cmd, action->timeout);
}
@@ -1641,6 +2082,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]);
@@ -1663,6 +2106,9 @@ static void livepatch_printall(unsigned char key)
if ( data->dep.len )
printk("depend-on=%*phN\n", data->dep.len, data->dep.p);
if ( data->xen_dep.len )
printk("depend-on-xen=%*phN\n", data->xen_dep.len, data->xen_dep.p);
}
spin_unlock(&payload_lock);
+52 -11
View File
@@ -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.
@@ -832,7 +832,7 @@ struct xen_sysctl_cpu_featureset {
* If zero exit with success.
*/
#define LIVEPATCH_PAYLOAD_VERSION 1
#define LIVEPATCH_PAYLOAD_VERSION 2
/*
* .livepatch.funcs structure layout defined in the `Payload format`
* section in the Live Patch design document.
@@ -840,6 +840,24 @@ struct xen_sysctl_cpu_featureset {
* We guard this with __XEN__ as toolstacks SHOULD not use it.
*/
#ifdef __XEN__
#define LIVEPATCH_OPAQUE_SIZE 31
struct livepatch_expectation {
uint8_t enabled : 1;
uint8_t len : 5; /* Length of data up to LIVEPATCH_OPAQUE_SIZE
(5 bits is enough for now) */
uint8_t rsv : 2; /* Reserved. Zero value */
uint8_t data[LIVEPATCH_OPAQUE_SIZE]; /* Same size as opaque[] buffer of
struct livepatch_func. This is the
max number of bytes to be patched */
};
typedef struct livepatch_expectation livepatch_expectation_t;
typedef enum livepatch_func_state {
LIVEPATCH_FUNC_NOT_APPLIED,
LIVEPATCH_FUNC_APPLIED
} livepatch_func_state_t;
struct livepatch_func {
const char *name; /* Name of function to be patched. */
void *new_addr;
@@ -847,7 +865,10 @@ struct livepatch_func {
uint32_t new_size;
uint32_t old_size;
uint8_t version; /* MUST be LIVEPATCH_PAYLOAD_VERSION. */
uint8_t opaque[31];
uint8_t opaque[LIVEPATCH_OPAQUE_SIZE];
uint8_t applied;
uint8_t _pad[7];
livepatch_expectation_t expect;
};
typedef struct livepatch_func livepatch_func_t;
#endif
@@ -913,15 +934,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). 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), `name_total_size` and
* `metadata_total_size` containing total sizes of transferred 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.
@@ -944,13 +967,21 @@ struct xen_sysctl_livepatch_list {
amount of payloads and version.
OUT: How many payloads left. */
uint32_t pad; /* IN: Must be zero. */
uint32_t name_total_size; /* OUT: Total size of all transfer names */
uint32_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
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. */
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. */
};
/*
@@ -970,6 +1001,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 {
+40 -3
View File
@@ -29,9 +29,18 @@ struct xen_sysctl_livepatch_op;
/* Convenience define for printk. */
#define LIVEPATCH "livepatch: "
/* ELF payload special section names. */
#define ELF_LIVEPATCH_FUNC ".livepatch.funcs"
#define ELF_LIVEPATCH_DEPENDS ".livepatch.depends"
#define ELF_BUILD_ID_NOTE ".note.gnu.build-id"
#define ELF_LIVEPATCH_FUNC ".livepatch.funcs"
#define ELF_LIVEPATCH_DEPENDS ".livepatch.depends"
#define ELF_LIVEPATCH_XEN_DEPENDS ".livepatch.xen_depends"
#define ELF_BUILD_ID_NOTE ".note.gnu.build-id"
#define ELF_LIVEPATCH_LOAD_HOOKS ".livepatch.hooks.load"
#define ELF_LIVEPATCH_UNLOAD_HOOKS ".livepatch.hooks.unload"
#define ELF_LIVEPATCH_PREAPPLY_HOOK ".livepatch.hooks.preapply"
#define ELF_LIVEPATCH_APPLY_HOOK ".livepatch.hooks.apply"
#define ELF_LIVEPATCH_POSTAPPLY_HOOK ".livepatch.hooks.postapply"
#define ELF_LIVEPATCH_PREREVERT_HOOK ".livepatch.hooks.prerevert"
#define ELF_LIVEPATCH_REVERT_HOOK ".livepatch.hooks.revert"
#define ELF_LIVEPATCH_POSTREVERT_HOOK ".livepatch.hooks.postrevert"
/* Arbitrary limit for payload size and .bss section size. */
#define LIVEPATCH_MAX_SIZE MB(2)
@@ -114,6 +123,34 @@ void arch_livepatch_post_action(void);
void arch_livepatch_mask(void);
void arch_livepatch_unmask(void);
static inline void common_livepatch_apply(struct livepatch_func *func)
{
/* If the action has been already executed on this function, do nothing. */
if ( func->applied == LIVEPATCH_FUNC_APPLIED )
{
printk(XENLOG_WARNING LIVEPATCH "%s: %s has been already applied before\n",
__func__, func->name);
return;
}
arch_livepatch_apply(func);
func->applied = LIVEPATCH_FUNC_APPLIED;
}
static inline void common_livepatch_revert(struct livepatch_func *func)
{
/* If the apply action hasn't been executed on this function, do nothing. */
if ( !func->old_addr || func->applied == LIVEPATCH_FUNC_NOT_APPLIED )
{
printk(XENLOG_WARNING LIVEPATCH "%s: %s has not been applied before\n",
__func__, func->name);
return;
}
arch_livepatch_revert(func);
func->applied = LIVEPATCH_FUNC_NOT_APPLIED;
}
#else
/*
+83
View File
@@ -4,6 +4,15 @@
#ifndef __XEN_LIVEPATCH_PAYLOAD_H__
#define __XEN_LIVEPATCH_PAYLOAD_H__
#include <xen/virtual_region.h>
/* To contain the ELF Note header. */
struct livepatch_build_id {
const void *p;
unsigned int len;
};
typedef struct payload livepatch_payload_t;
/*
* The following definitions are to be used in patches. They are taken
@@ -12,6 +21,56 @@
typedef void livepatch_loadcall_t(void);
typedef void livepatch_unloadcall_t(void);
typedef int livepatch_precall_t(livepatch_payload_t *arg);
typedef int livepatch_actioncall_t(livepatch_payload_t *arg);
typedef void livepatch_postcall_t(livepatch_payload_t *arg);
struct livepatch_hooks {
struct {
livepatch_precall_t *const *pre;
livepatch_actioncall_t *const *action;
livepatch_postcall_t *const *post;
} 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. */
bool reverted; /* Whether it was reverted. */
bool safe_to_reapply; /* Can apply safely after revert. */
struct list_head list; /* Linked to 'payload_list'. */
const void *text_addr; /* Virtual address of .text. */
size_t text_size; /* .. and its size. */
const void *rw_addr; /* Virtual address of .data. */
size_t rw_size; /* .. and its size (if any). */
const void *ro_addr; /* Virtual address of .rodata. */
size_t ro_size; /* .. and its size (if any). */
unsigned int pages; /* Total pages for [text,rw,ro]_addr */
struct list_head applied_list; /* Linked to 'applied_list'. */
struct livepatch_func *funcs; /* The array of functions to patch. */
unsigned int nfuncs; /* Nr of functions to patch. */
const struct livepatch_symbol *symtab; /* All symbols. */
const char *strtab; /* Pointer to .strtab. */
struct virtual_region region; /* symbol, bug.frame patching and
exception table (x86). */
unsigned int nsyms; /* Nr of entries in .strtab and symbols. */
struct livepatch_build_id id; /* ELFNOTE_DESC(.note.gnu.build-id) of the payload. */
struct livepatch_build_id dep; /* ELFNOTE_DESC(.livepatch.depends). */
struct livepatch_build_id xen_dep; /* ELFNOTE_DESC(.livepatch.xen_depends). */
livepatch_loadcall_t *const *load_funcs; /* The array of funcs to call after */
livepatch_unloadcall_t *const *unload_funcs;/* load and unload of the payload. */
struct livepatch_hooks hooks; /* Pre and post hooks for apply and revert */
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 */
};
/*
* LIVEPATCH_LOAD_HOOK macro
*
@@ -36,6 +95,30 @@ typedef void livepatch_unloadcall_t(void);
livepatch_unloadcall_t *__weak \
const livepatch_unload_data_##_fn __section(".livepatch.hooks.unload") = _fn;
#define LIVEPATCH_PREAPPLY_HOOK(_fn) \
livepatch_precall_t *__attribute__((weak, used)) \
const livepatch_preapply_data_##_fn __section(".livepatch.hooks.preapply") = _fn;
#define LIVEPATCH_APPLY_HOOK(_fn) \
livepatch_actioncall_t *__attribute__((weak, used)) \
const livepatch_apply_data_##_fn __section(".livepatch.hooks.apply") = _fn;
#define LIVEPATCH_POSTAPPLY_HOOK(_fn) \
livepatch_postcall_t *__attribute__((weak, used)) \
const livepatch_postapply_data_##_fn __section(".livepatch.hooks.postapply") = _fn;
#define LIVEPATCH_PREREVERT_HOOK(_fn) \
livepatch_precall_t *__attribute__((weak, used)) \
const livepatch_prerevert_data_##_fn __section(".livepatch.hooks.prerevert") = _fn;
#define LIVEPATCH_REVERT_HOOK(_fn) \
livepatch_actioncall_t *__attribute__((weak, used)) \
const livepatch_revert_data_##_fn __section(".livepatch.hooks.revert") = _fn;
#define LIVEPATCH_POSTREVERT_HOOK(_fn) \
livepatch_postcall_t *__attribute__((weak, used)) \
const livepatch_postrevert_data_##_fn __section(".livepatch.hooks.postrevert") = _fn;
#endif /* __XEN_LIVEPATCH_PAYLOAD_H__ */
/*
+115 -6
View File
@@ -19,11 +19,31 @@ LIVEPATCH := xen_hello_world.livepatch
LIVEPATCH_BYE := xen_bye_world.livepatch
LIVEPATCH_REPLACE := xen_replace_world.livepatch
LIVEPATCH_NOP := xen_nop.livepatch
LIVEPATCH_NO_XEN_BUILDID := xen_no_xen_buildid.livepatch
LIVEPATCH_PREPOST_HOOKS := xen_prepost_hooks.livepatch
LIVEPATCH_PREPOST_HOOKS_FAIL := xen_prepost_hooks_fail.livepatch
LIVEPATCH_ACTION_HOOKS := xen_action_hooks.livepatch
LIVEPATCH_ACTION_HOOKS_NOFUNC := xen_action_hooks_nofunc.livepatch
LIVEPATCH_ACTION_HOOKS_MARKER:= xen_action_hooks_marker.livepatch
LIVEPATCH_ACTION_HOOKS_NOAPPLY:= xen_action_hooks_noapply.livepatch
LIVEPATCH_ACTION_HOOKS_NOREVERT:= xen_action_hooks_norevert.livepatch
LIVEPATCH_EXPECTATIONS:= xen_expectations.livepatch
LIVEPATCH_EXPECTATIONS_FAIL:= xen_expectations_fail.livepatch
LIVEPATCHES += $(LIVEPATCH)
LIVEPATCHES += $(LIVEPATCH_BYE)
LIVEPATCHES += $(LIVEPATCH_REPLACE)
LIVEPATCHES += $(LIVEPATCH_NOP)
LIVEPATCHES += $(LIVEPATCH_NO_XEN_BUILDID)
LIVEPATCHES += $(LIVEPATCH_PREPOST_HOOKS)
LIVEPATCHES += $(LIVEPATCH_PREPOST_HOOKS_FAIL)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOFUNC)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_MARKER)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOAPPLY)
LIVEPATCHES += $(LIVEPATCH_ACTION_HOOKS_NOREVERT)
LIVEPATCHES += $(LIVEPATCH_EXPECTATIONS)
LIVEPATCHES += $(LIVEPATCH_EXPECTATIONS_FAIL)
LIVEPATCH_DEBUG_DIR ?= $(DEBUG_DIR)/xen-livepatch
@@ -38,7 +58,7 @@ uninstall:
.PHONY: clean
clean::
rm -f *.o .*.o.d *.livepatch config.h
rm -f *.o .*.o.d *.livepatch config.h expect_config.h
#
# To compute these values we need the binary files: xen-syms
@@ -59,9 +79,17 @@ config.h: xen_hello_world_func.o
xen_hello_world.o: config.h
.PHONY: $(LIVEPATCH)
$(LIVEPATCH): xen_hello_world_func.o xen_hello_world.o note.o
$(LIVEPATCH): xen_hello_world_func.o xen_hello_world.o note.o xen_note.o modinfo.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH) $^
.PHONY: modinfo.o
modinfo.o:
(set -e; \
printf "LIVEPATCH_RULEZ\0") > $@.bin
$(OBJCOPY) $(OBJCOPY_MAGIC) \
--rename-section=.data=.modinfo,alloc,load,readonly,data,contents -S $@.bin $@
#rm -f $@.bin
#
# This target is only accessible if CONFIG_LIVEPATCH is defined, which
# depends on $(build_id_linker) being available. Hence we do not
@@ -78,6 +106,17 @@ note.o:
--rename-section=.data=.livepatch.depends,alloc,load,readonly,data,contents -S $@.bin $@
rm -f $@.bin
#
# Append .livepatch.xen_depends section
# with Xen build-id derived from xen-syms.
#
.PHONY: xen_note.o
xen_note.o:
$(OBJCOPY) -O binary --only-section=.note.gnu.build-id $(BASEDIR)/xen-syms $@.bin
$(OBJCOPY) $(OBJCOPY_MAGIC) \
--rename-section=.data=.livepatch.xen_depends,alloc,load,readonly,data,contents -S $@.bin $@
rm -f $@.bin
#
# Extract the build-id of the xen_hello_world.livepatch
# (which xen_bye_world will depend on).
@@ -92,20 +131,90 @@ hello_world_note.o: $(LIVEPATCH)
xen_bye_world.o: config.h
.PHONY: $(LIVEPATCH_BYE)
$(LIVEPATCH_BYE): xen_bye_world_func.o xen_bye_world.o hello_world_note.o
$(LIVEPATCH_BYE): xen_bye_world_func.o xen_bye_world.o hello_world_note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_BYE) $^
xen_replace_world.o: config.h
.PHONY: $(LIVEPATCH_REPLACE)
$(LIVEPATCH_REPLACE): xen_replace_world_func.o xen_replace_world.o note.o
$(LIVEPATCH_REPLACE): xen_replace_world_func.o xen_replace_world.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_REPLACE) $^
xen_nop.o: config.h
.PHONY: $(LIVEPATCH_NOP)
$(LIVEPATCH_NOP): xen_nop.o note.o
$(LIVEPATCH_NOP): xen_nop.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_NOP) $^
# This one always fails upon upload, because it deliberately
# does not have a .livepatch.xen_depends (xen_note.o) section.
xen_no_xen_buildid.o: config.h
.PHONY: $(LIVEPATCH_NO_XEN_BUILDID)
$(LIVEPATCH_NO_XEN_BUILDID): xen_nop.o note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_NO_XEN_BUILDID) $^
xen_prepost_hooks.o: config.h
.PHONY: $(LIVEPATCH_PREPOST_HOOKS)
$(LIVEPATCH_PREPOST_HOOKS): xen_prepost_hooks.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_PREPOST_HOOKS) $^
xen_prepost_hooks_fail.o: config.h
.PHONY: $(LIVEPATCH_PREPOST_HOOKS_FAIL)
$(LIVEPATCH_PREPOST_HOOKS_FAIL): xen_prepost_hooks_fail.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_PREPOST_HOOKS_FAIL) $^
xen_actions_hooks.o: config.h
.PHONY: $(LIVEPATCH_ACTION_HOOKS)
$(LIVEPATCH_ACTION_HOOKS): xen_action_hooks.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS) $^
.PHONY: $(LIVEPATCH_ACTION_HOOKS_NOFUNC)
$(LIVEPATCH_ACTION_HOOKS_NOFUNC): xen_action_hooks_nofunc.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOFUNC) $^
xen_actions_hooks_marker.o: config.h
.PHONY: $(LIVEPATCH_ACTION_HOOKS_MARKER)
$(LIVEPATCH_ACTION_HOOKS_MARKER): xen_action_hooks_marker.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_MARKER) $^
xen_actions_hooks_noapply.o: config.h
.PHONY: $(LIVEPATCH_ACTION_HOOKS_NOAPPLY)
$(LIVEPATCH_ACTION_HOOKS_NOAPPLY): xen_action_hooks_marker.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOAPPLY) $^
xen_actions_hooks_norevert.o: config.h
.PHONY: $(LIVEPATCH_ACTION_HOOKS_NOREVERT)
$(LIVEPATCH_ACTION_HOOKS_NOREVERT): xen_action_hooks_marker.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_ACTION_HOOKS_NOREVERT) $^
EXPECT_BYTES_COUNT := 8
CODE_GET_EXPECT=$(shell $(OBJDUMP) -d --insn-width=1 $(1) | sed -n -e '/<'$(2)'>:$$/,/^$$/ p' | tail -n +2 | head -n $(EXPECT_BYTES_COUNT) | awk '{$$0=$$2; printf "%s", substr($$0,length-1)}' | sed 's/.\{2\}/0x&,/g' | sed 's/^/{/;s/,$$/}/g')
.PHONY: expect_config.h
expect_config.h: EXPECT_BYTES=$(call CODE_GET_EXPECT,$(BASEDIR)/xen-syms,xen_extra_version)
expect_config.h: xen_expectations.o
(set -e; \
echo "#define EXPECT_BYTES $(EXPECT_BYTES)"; \
echo "#define EXPECT_BYTES_COUNT $(EXPECT_BYTES_COUNT)") > $@
xen_expectations.o: expect_config.h
.PHONY: $(LIVEPATCH_EXPECTATIONS)
$(LIVEPATCH_EXPECTATIONS): xen_expectations.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_EXPECTATIONS) $^
.PHONY: $(LIVEPATCH_EXPECTATIONS_FAIL)
$(LIVEPATCH_EXPECTATIONS_FAIL): xen_expectations_fail.o xen_hello_world_func.o note.o xen_note.o
$(LD) $(LDFLAGS) $(build_id_linker) -r -o $(LIVEPATCH_EXPECTATIONS_FAIL) $^
.PHONY: livepatch
livepatch: $(LIVEPATCH) $(LIVEPATCH_BYE) $(LIVEPATCH_REPLACE) $(LIVEPATCH_NOP)
livepatch: $(LIVEPATCH) $(LIVEPATCH_BYE) $(LIVEPATCH_REPLACE) $(LIVEPATCH_NOP) $(LIVEPATCH_NO_XEN_BUILDID) \
$(LIVEPATCH_PREPOST_HOOKS) $(LIVEPATCH_PREPOST_HOOKS_FAIL) $(LIVEPATCH_ACTION_HOOKS) \
$(LIVEPATCH_ACTION_HOOKS_NOFUNC) $(LIVEPATCH_ACTION_HOOKS_MARKER) $(LIVEPATCH_ACTION_HOOKS_NOAPPLY) \
$(LIVEPATCH_ACTION_HOOKS_NOREVERT) $(LIVEPATCH_EXPECTATIONS) $(LIVEPATCH_EXPECTATIONS_FAIL)
+102
View File
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char hello_world_patch_this_fnc[] = "xen_extra_version";
extern const char *xen_hello_world(void);
static unsigned int apply_cnt;
static unsigned int revert_cnt;
static int apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
func->applied = LIVEPATCH_FUNC_APPLIED;
apply_cnt++;
printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static int revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
func->applied = LIVEPATCH_FUNC_NOT_APPLIED;
revert_cnt++;
printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
printk(KERN_DEBUG "%s: reverted: %s\n", __func__, func->name);
}
BUG_ON(apply_cnt != 1 || revert_cnt != 1);
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_APPLY_HOOK(apply_hook);
LIVEPATCH_REVERT_HOOK(revert_hook);
LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = hello_world_patch_this_fnc,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = NEW_CODE_SZ,
.old_size = OLD_CODE_SZ,
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char hello_world_patch_this_fnc[] = "xen_extra_version";
extern const char *xen_hello_world(void);
static int pre_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: pre applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: post applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
static int pre_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: pre reverted: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: post reverted: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = hello_world_patch_this_fnc,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = NEW_CODE_SZ,
.old_size = OLD_CODE_SZ,
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char hello_world_patch_this_fnc[] = "xen_extra_version";
extern const char *xen_hello_world(void);
static unsigned int apply_cnt;
static int pre_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: pre applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static int apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
apply_cnt++;
printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return -EINVAL; /* Mark action as inconsistent */
}
static void post_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(apply_cnt != 1);
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: post applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
static int pre_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: pre reverted: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: post reverted: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_APPLY_HOOK(apply_hook);
LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = hello_world_patch_this_fnc,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = NEW_CODE_SZ,
.old_size = OLD_CODE_SZ,
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static unsigned int apply_cnt;
static unsigned int revert_cnt;
static int apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
apply_cnt++;
printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static int revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
revert_cnt++;
printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
printk(KERN_DEBUG "%s: reverted: %s\n", __func__, func->name);
}
BUG_ON(apply_cnt > 0 || revert_cnt > 0);
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_APPLY_HOOK(apply_hook);
LIVEPATCH_REVERT_HOOK(revert_hook);
LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
@@ -0,0 +1,143 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char hello_world_patch_this_fnc[] = "xen_extra_version";
extern const char *xen_hello_world(void);
static unsigned int revert_cnt;
static int pre_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: pre applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: post applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
static int pre_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: pre reverted: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static int revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
revert_cnt++;
printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return -EINVAL; /* Mark action as inconsistent */
}
static void post_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
BUG_ON(revert_cnt != 1);
BUG_ON(func->applied != LIVEPATCH_FUNC_APPLIED);
/* Outside of quiesce zone: MAY TRIGGER HOST CRASH/UNDEFINED BEHAVIOR */
arch_livepatch_quiesce();
common_livepatch_revert(payload);
arch_livepatch_revive();
BUG_ON(func->applied == LIVEPATCH_FUNC_APPLIED);
printk(KERN_DEBUG "%s: post reverted: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_APPLY_HOOK(revert_hook);
LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = hello_world_patch_this_fnc,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = NEW_CODE_SZ,
.old_size = OLD_CODE_SZ,
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "expect_config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char livepatch_exceptions_str[] = "xen_extra_version";
extern const char *xen_hello_world(void);
struct livepatch_func __section(".livepatch.funcs") livepatch_exceptions = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = livepatch_exceptions_str,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = EXPECT_BYTES_COUNT,
.old_size = EXPECT_BYTES_COUNT,
.expect = {
.enabled = 1,
.len = EXPECT_BYTES_COUNT,
.data = EXPECT_BYTES
},
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char livepatch_exceptions_str[] = "xen_extra_version";
extern const char *xen_hello_world(void);
#define EXPECT_BYTES_COUNT 6
struct livepatch_func __section(".livepatch.funcs") livepatch_exceptions = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = livepatch_exceptions_str,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = EXPECT_BYTES_COUNT,
.old_size = EXPECT_BYTES_COUNT,
.expect = {
.enabled = 1,
.len = EXPECT_BYTES_COUNT,
.data = { 0xDE, 0xAD, 0xC0, 0xDE, 0xBA, 0xBE }
},
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char hello_world_patch_this_fnc[] = "xen_extra_version";
extern const char *xen_hello_world(void);
static unsigned int pre_apply_cnt;
static unsigned int post_apply_cnt;
static unsigned int pre_revert_cnt;
static unsigned int post_revert_cnt;
static unsigned int pre_revert_retry = 1;
static int pre_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
pre_apply_cnt++;
printk(KERN_DEBUG "%s: applying: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return 0;
}
static void post_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
post_apply_cnt++;
printk(KERN_DEBUG "%s: applied: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
static int pre_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
pre_revert_cnt++;
printk(KERN_DEBUG "%s: reverting: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
/* First revert attempt always fails. Second attempt succeeds. */
return -(pre_revert_retry--);
}
static void post_revert_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
post_revert_cnt++;
printk(KERN_DEBUG "%s: reverted: %s\n", __func__, func->name);
}
BUG_ON(pre_apply_cnt != 1 || post_apply_cnt != 1);
BUG_ON(pre_revert_cnt != 2 || post_revert_cnt != 1);
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
LIVEPATCH_POSTAPPLY_HOOK(post_apply_hook);
LIVEPATCH_PREREVERT_HOOK(pre_revert_hook);
LIVEPATCH_POSTREVERT_HOOK(post_revert_hook);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = hello_world_patch_this_fnc,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = NEW_CODE_SZ,
.old_size = OLD_CODE_SZ,
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2019 Amazon.com, Inc. or its affiliates. All rights reserved.
*
*/
#include "config.h"
#include <xen/lib.h>
#include <xen/types.h>
#include <xen/version.h>
#include <xen/livepatch.h>
#include <xen/livepatch_payload.h>
#include <public/sysctl.h>
static const char hello_world_patch_this_fnc[] = "xen_extra_version";
extern const char *xen_hello_world(void);
/* This hook always fail and should prevent from loading the livepatch. */
static int pre_apply_hook(livepatch_payload_t *payload)
{
int i;
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
for (i = 0; i < payload->nfuncs; i++)
{
struct livepatch_func *func = &payload->funcs[i];
printk(KERN_DEBUG "%s: pre applying: %s\n", __func__, func->name);
}
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return -EINVAL;
}
static int unreachable_pre_hook(livepatch_payload_t *payload)
{
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
BUG();
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
return -EINVAL;
}
static void unreachable_post_hook(livepatch_payload_t *payload)
{
printk(KERN_DEBUG "%s: Hook starting.\n", __func__);
BUG();
printk(KERN_DEBUG "%s: Hook done.\n", __func__);
}
LIVEPATCH_PREAPPLY_HOOK(pre_apply_hook);
LIVEPATCH_POSTAPPLY_HOOK(unreachable_post_hook);
LIVEPATCH_PREREVERT_HOOK(unreachable_pre_hook);
LIVEPATCH_POSTREVERT_HOOK(unreachable_post_hook);
struct livepatch_func __section(".livepatch.funcs") livepatch_xen_hello_world = {
.version = LIVEPATCH_PAYLOAD_VERSION,
.name = hello_world_patch_this_fnc,
.new_addr = xen_hello_world,
.old_addr = xen_extra_version,
.new_size = NEW_CODE_SZ,
.old_size = OLD_CODE_SZ,
};
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.