[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [XTF PATCH v2] Add a Live Patch privilege check test
On Fri, Nov 18, 2016 at 09:36:06AM +0000, Ross Lagerwall wrote: > Add a test to check that Live Patch operations cannot be called from an > unprivileged domain. > > Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx> > --- > > In v2: > * Fixed review issues. > * Rebased and added a test_title string. > > common/lib.c | 15 +++ > docs/all-tests.dox | 2 + > include/xen/sysctl.h | 218 > ++++++++++++++++++++++++++++++++++++ > include/xtf/hypercall.h | 6 + > include/xtf/lib.h | 2 + > tests/livepatch-priv-check/Makefile | 9 ++ > tests/livepatch-priv-check/main.c | 153 +++++++++++++++++++++++++ > 7 files changed, 405 insertions(+) > create mode 100755 include/xen/sysctl.h > create mode 100644 tests/livepatch-priv-check/Makefile > create mode 100644 tests/livepatch-priv-check/main.c > > diff --git a/common/lib.c b/common/lib.c > index 9dca3e3..cc847ab 100644 > --- a/common/lib.c > +++ b/common/lib.c > @@ -19,6 +19,21 @@ void __noreturn panic(const char *fmt, ...) > arch_crash_hard(); > } > > +int probe_sysctl_interface_version(void) /me chuckles. > +{ > + int i; > + xen_sysctl_t op = {0}; > + > + for ( i = 0; i < 128; i++ ) > + { > + op.interface_version = i; > + if ( hypercall_sysctl(&op) != -EACCES ) > + return i; > + } > + > + return -1; > +} > + > /* > * Local variables: > * mode: C > diff --git a/docs/all-tests.dox b/docs/all-tests.dox > index 4f86182..2909b85 100644 > --- a/docs/all-tests.dox > +++ b/docs/all-tests.dox > @@ -22,6 +22,8 @@ and functionality. > > @subpage test-invlpg - `invlpg` instruction behaviour. > > +@subpage test-livepatch-priv-check - Live Patch Privilege Check > + > @subpage test-pv-iopl - IOPL emulation for PV guests. > > @subpage test-swint-emulation - Software interrupt emulation for HVM guests. > diff --git a/include/xen/sysctl.h b/include/xen/sysctl.h > new file mode 100755 > index 0000000..f4006fb > --- /dev/null > +++ b/include/xen/sysctl.h > @@ -0,0 +1,218 @@ > +/****************************************************************************** > + * sysctl.h > + * > + * System management operations. For use by node control stack. > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > copy > + * of this software and associated documentation files (the "Software"), to > + * deal in the Software without restriction, including without limitation the > + * rights to use, copy, modify, merge, publish, distribute, sublicense, > and/or > + * sell copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + * > + * Copyright (c) 2002-2006, K Fraser > + */ > + > +#ifndef __XEN_PUBLIC_SYSCTL_H__ > +#define __XEN_PUBLIC_SYSCTL_H__ > + > +#include "xen.h" > +#include "physdev.h" > + > +typedef struct { > + union { > + void *p; > + uint64_t __attribute__((aligned(8))) q; > + }; > +} guest_handle_64; > + > +/* > + * XEN_SYSCTL_LIVEPATCH_op > + * > + * Refer to the docs/unstable/misc/livepatch.markdown > + * for the design details of this hypercall. > + * > + * There are four sub-ops: > + * XEN_SYSCTL_LIVEPATCH_UPLOAD (0) > + * XEN_SYSCTL_LIVEPATCH_GET (1) > + * XEN_SYSCTL_LIVEPATCH_LIST (2) > + * XEN_SYSCTL_LIVEPATCH_ACTION (3) > + * > + * The normal sequence of sub-ops is to: > + * 1) XEN_SYSCTL_LIVEPATCH_UPLOAD to upload the payload. If errors STOP. > + * 2) XEN_SYSCTL_LIVEPATCH_GET to check the `->rc`. If -XEN_EAGAIN spin. > + * If zero go to next step. > + * 3) XEN_SYSCTL_LIVEPATCH_ACTION with LIVEPATCH_ACTION_APPLY to apply the > patch. > + * 4) XEN_SYSCTL_LIVEPATCH_GET to check the `->rc`. If in -XEN_EAGAIN spin. > + * If zero exit with success. > + */ > + > +#define LIVEPATCH_PAYLOAD_VERSION 1 > +/* > + * Structure describing an ELF payload. Uniquely identifies the > + * payload. Should be human readable. > + * Recommended length is upto XEN_LIVEPATCH_NAME_SIZE. > + * Includes the NUL terminator. > + */ > +#define XEN_LIVEPATCH_NAME_SIZE 128 > +struct xen_livepatch_name { > + guest_handle_64 name; /* IN: pointer to name. */ > + uint16_t size; /* IN: size of name. May be upto > + XEN_LIVEPATCH_NAME_SIZE. */ > + uint16_t pad[3]; /* IN: MUST be zero. */ > +}; > +typedef struct xen_livepatch_name xen_livepatch_name_t; > + > +/* > + * Upload a payload to the hypervisor. The payload is verified > + * against basic checks and if there are any issues the proper return code > + * will be returned. The payload is not applied at this time - that is > + * controlled by XEN_SYSCTL_LIVEPATCH_ACTION. > + * > + * The return value is zero if the payload was succesfully uploaded. > + * Otherwise an EXX return value is provided. Duplicate `name` are not > + * supported. > + * > + * The payload at this point is verified against basic checks. > + * > + * The `payload` is the ELF payload as mentioned in the `Payload format` > + * section in the Live Patch design document. > + */ > +#define XEN_SYSCTL_LIVEPATCH_UPLOAD 0 > +struct xen_sysctl_livepatch_upload { > + xen_livepatch_name_t name; /* IN, name of the patch. */ > + uint64_t size; /* IN, size of the ELF file. */ > + guest_handle_64 payload; /* IN, the ELF file. */ > +}; > +typedef struct xen_sysctl_livepatch_upload xen_sysctl_livepatch_upload_t; > + > +/* > + * Retrieve an status of an specific payload. > + * > + * Upon completion the `struct xen_livepatch_status` is updated. > + * > + * The return value is zero on success and XEN_EXX on failure. This operation > + * is synchronous and does not require preemption. > + */ > +#define XEN_SYSCTL_LIVEPATCH_GET 1 > + > +struct xen_livepatch_status { > +#define LIVEPATCH_STATE_CHECKED 1 > +#define LIVEPATCH_STATE_APPLIED 2 > + uint32_t state; /* OUT: LIVEPATCH_STATE_*. */ > + int32_t rc; /* OUT: 0 if no error, otherwise > -XEN_EXX. */ > +}; > +typedef struct xen_livepatch_status xen_livepatch_status_t; > + > +struct xen_sysctl_livepatch_get { > + xen_livepatch_name_t name; /* IN, name of the payload. */ > + xen_livepatch_status_t status; /* IN/OUT, state of it. */ > +}; > +typedef struct xen_sysctl_livepatch_get xen_sysctl_livepatch_get_t; > + > +/* > + * Retrieve an array of abbreviated status and names 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. > + * > + * If the hypercall returns E2BIG the `nr` is too big and should be > + * lowered. The upper limit of `nr` is left to the implemention. > + * > + * Note that due to the asynchronous nature of hypercalls the domain might > have > + * added or removed the number of payloads making this information stale. It > is > + * the responsibility of the toolstack to use the `version` field to check > + * between each invocation. if the version differs it should discard the > stale > + * data and start from scratch. It is OK for the toolstack to use the new > + * `version` field. > + */ > +#define XEN_SYSCTL_LIVEPATCH_LIST 2 > +struct xen_sysctl_livepatch_list { > + uint32_t version; /* OUT: Hypervisor stamps value. > + If varies between calls, we > are > + * getting stale data. */ > + uint32_t idx; /* IN: Index into hypervisor > list. */ > + uint32_t nr; /* IN: How many status, name, > and len > + should fill out. Can be zero > to get > + amount of payloads and > version. > + OUT: How many payloads left. > */ > + uint32_t pad; /* IN: Must be zero. */ > + guest_handle_64 status; /* OUT. Must have enough > + space allocate for nr of > them. */ > + guest_handle_64 name; /* OUT: Array of names. Each > member > + MUST XEN_LIVEPATCH_NAME_SIZE > in size. > + Must have nr of them. */ > + guest_handle_64 len; /* OUT: Array of lengths of > name's. > + Must have nr of them. */ > +}; > +typedef struct xen_sysctl_livepatch_list xen_sysctl_livepatch_list_t; > + > +/* > + * Perform an operation on the payload structure referenced by the `name` > field. > + * The operation request is asynchronous and the status should be retrieved > + * by using either XEN_SYSCTL_LIVEPATCH_GET or XEN_SYSCTL_LIVEPATCH_LIST > hypercall. > + */ > +#define XEN_SYSCTL_LIVEPATCH_ACTION 3 > +struct xen_sysctl_livepatch_action { > + xen_livepatch_name_t name; /* IN, name of the patch. */ > +#define LIVEPATCH_ACTION_UNLOAD 1 > +#define LIVEPATCH_ACTION_REVERT 2 > +#define LIVEPATCH_ACTION_APPLY 3 > +#define LIVEPATCH_ACTION_REPLACE 4 > + uint32_t cmd; /* IN: LIVEPATCH_ACTION_*. */ > + uint32_t timeout; /* IN: Zero if no timeout. */ > + /* Or upper bound of time (ms) */ > + /* for operation to take. */ > +}; > +typedef struct xen_sysctl_livepatch_action xen_sysctl_livepatch_action_t; > + > +struct xen_sysctl_livepatch_op { > + uint32_t cmd; /* IN: XEN_SYSCTL_LIVEPATCH_*. */ > + uint32_t pad; /* IN: Always zero. */ > + union { > + xen_sysctl_livepatch_upload_t upload; > + xen_sysctl_livepatch_list_t list; > + xen_sysctl_livepatch_get_t get; > + xen_sysctl_livepatch_action_t action; > + } u; > +}; > +typedef struct xen_sysctl_livepatch_op xen_sysctl_livepatch_op_t; > + > +struct xen_sysctl { > + uint32_t cmd; > +#define XEN_SYSCTL_livepatch_op 27 > + uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */ > + union { > + struct xen_sysctl_livepatch_op livepatch; > + uint8_t pad[128]; > + } u; > +}; > +typedef struct xen_sysctl xen_sysctl_t; > + > +#endif /* __XEN_PUBLIC_SYSCTL_H__ */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/include/xtf/hypercall.h b/include/xtf/hypercall.h > index a37ebc2..ab4986f 100644 > --- a/include/xtf/hypercall.h > +++ b/include/xtf/hypercall.h > @@ -34,6 +34,7 @@ extern uint8_t hypercall_page[PAGE_SIZE]; > #include <xen/physdev.h> > #include <xen/memory.h> > #include <xen/version.h> > +#include <xen/sysctl.h> > #include <xen/hvm/hvm_op.h> > #include <xen/hvm/params.h> > > @@ -114,6 +115,11 @@ static inline long hypercall_hvm_op(unsigned int cmd, > void *arg) > return HYPERCALL2(long, __HYPERVISOR_hvm_op, cmd, arg); > } > > +static inline long hypercall_sysctl(xen_sysctl_t *arg) > +{ > + return HYPERCALL1(long, __HYPERVISOR_sysctl, arg); > +} > + > /* > * Higher level hypercall helpers > */ > diff --git a/include/xtf/lib.h b/include/xtf/lib.h > index b0ae39d..8fb490a 100644 > --- a/include/xtf/lib.h > +++ b/include/xtf/lib.h > @@ -65,6 +65,8 @@ static inline void exec_user_void(void (*fn)(void)) > exec_user((void *)fn); > } > > +int probe_sysctl_interface_version(void); > + > #endif /* XTF_LIB_H */ > > /* > diff --git a/tests/livepatch-priv-check/Makefile > b/tests/livepatch-priv-check/Makefile > new file mode 100644 > index 0000000..e27b9da > --- /dev/null > +++ b/tests/livepatch-priv-check/Makefile > @@ -0,0 +1,9 @@ > +include $(ROOT)/build/common.mk > + > +NAME := livepatch-priv-check > +CATEGORY := functional > +TEST-ENVS := $(ALL_ENVIRONMENTS) > + > +obj-perenv += main.o > + > +include $(ROOT)/build/gen.mk > diff --git a/tests/livepatch-priv-check/main.c > b/tests/livepatch-priv-check/main.c > new file mode 100644 > index 0000000..4d64d58 > --- /dev/null > +++ b/tests/livepatch-priv-check/main.c > @@ -0,0 +1,153 @@ > +/** > + * @file tests/livepatch-priv-check/main.c > + * @ref test-livepatch-priv-check > + * > + * @page test-livepatch-priv-check Live Patch Privilege Check > + * > + * Checks that Xen prevents using all live patching operations and > + * sub-operations from an unprivileged guest. > + * > + * @see tests/livepatch-check-priv/main.c > + */ > +#include <xtf.h> > + > +const char test_title[] = "Live Patch Privilege Check"; > + > +static int interface_version; > + > +static void check_ret(int rc) Would it make it easier (to troubleshoot if somebody did enable the XSM checks for specifc sub-obs - if that was ever done), to extend the funtion to have 'const char *msg' > +{ > + switch ( rc ) > + { > + case -EPERM: > + printk("Xen correctly denied Live Patch calls\n"); And in all of those printk and xtf_* use the '%s: ... ", msg. > + break; > + > + case -ENOSYS: > + xtf_skip("Live Patch support not detected\n"); > + break; > + > + default: > + xtf_failure("Fail: Unexpected return code %d\n", rc); > + break; > + } > +} > + > +#define TEST_NAME "foo" > + > +static void test_upload(void) > +{ > + uint8_t payload[PAGE_SIZE]; > + xen_sysctl_t op = > + { > + .cmd = XEN_SYSCTL_livepatch_op, > + .interface_version = interface_version, > + .u.livepatch = { > + .cmd = XEN_SYSCTL_LIVEPATCH_UPLOAD, > + .u.upload = { > + .name = { > + .name.p = TEST_NAME, > + .size = sizeof(TEST_NAME), > + }, > + .size = PAGE_SIZE, > + .payload.p = payload, > + }, > + }, > + }; > + > + check_ret(hypercall_sysctl(&op)); And here in you could just do check_ret(__func__, hypercall_sysctl?) Thanks for making a nice test-case for this!! _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |