mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
This is actually what the caller acquire_resource() expects on any kind
of error (the comment on top of resource_max_frames() also suggests that).
Otherwise, the caller will treat -errno as a valid value and propagate incorrect
nr_frames to the VM. As a possible consequence, a VM trying to query a resource
size of an unknown type will get the success result from the hypercall and obtain
nr_frames 4294967201.
Also, add an ASSERT_UNREACHABLE() in the default case of _acquire_resource(),
normally we won't get to this point, as an unknown type will always be rejected
earlier in resource_max_frames().
Also, update test-resource app to verify that Xen can deal with invalid
(unknown) resource type properly.
Fixes: 9244528955 ("xen/memory: Fix acquire_resource size semantics")
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
293 lines
8.2 KiB
C
293 lines
8.2 KiB
C
#include <err.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include <xenctrl.h>
|
|
#include <xenforeignmemory.h>
|
|
#include <xengnttab.h>
|
|
#include <xen-tools/common-macros.h>
|
|
|
|
static unsigned int nr_failures;
|
|
#define fail(fmt, ...) \
|
|
({ \
|
|
nr_failures++; \
|
|
(void)printf(fmt, ##__VA_ARGS__); \
|
|
})
|
|
|
|
static xc_interface *xch;
|
|
static xenforeignmemory_handle *fh;
|
|
static xengnttab_handle *gh;
|
|
|
|
static xc_physinfo_t physinfo;
|
|
|
|
static void test_gnttab(uint32_t domid, unsigned int nr_frames,
|
|
unsigned long gfn)
|
|
{
|
|
xenforeignmemory_resource_handle *res;
|
|
grant_entry_v1_t *gnttab = NULL;
|
|
size_t size;
|
|
int rc;
|
|
uint32_t refs[nr_frames], domids[nr_frames];
|
|
void *grants;
|
|
|
|
printf(" Test grant table\n");
|
|
|
|
/* Obtain the grant table resource size. */
|
|
rc = xenforeignmemory_resource_size(
|
|
fh, domid, XENMEM_resource_grant_table,
|
|
XENMEM_resource_grant_table_id_shared, &size);
|
|
|
|
/*
|
|
* A failure of this call indicates missing kernel support for size
|
|
* ioctl(), or missing Xen acquire_resource support.
|
|
*/
|
|
if ( rc )
|
|
return fail(" Fail: Get size: %d - %s\n", errno, strerror(errno));
|
|
|
|
/*
|
|
* Getting 32 frames back instead of nr_frames indicates Xen is missing
|
|
* the bugfix to make size requests actually return real data.
|
|
*/
|
|
if ( (size >> XC_PAGE_SHIFT) != nr_frames )
|
|
return fail(" Fail: Get size: expected %u frames, got %zu\n",
|
|
nr_frames, size >> XC_PAGE_SHIFT);
|
|
|
|
/* Map the entire grant table. */
|
|
res = xenforeignmemory_map_resource(
|
|
fh, domid, XENMEM_resource_grant_table,
|
|
XENMEM_resource_grant_table_id_shared, 0, size >> XC_PAGE_SHIFT,
|
|
(void **)&gnttab, PROT_READ | PROT_WRITE, 0);
|
|
|
|
/*
|
|
* Failure here with E2BIG indicates Xen is missing the bugfix to map
|
|
* resources larger than 32 frames.
|
|
*/
|
|
if ( !res )
|
|
return fail(" Fail: Map grant table %d - %s\n",
|
|
errno, strerror(errno));
|
|
|
|
/* Put each gref at a unique offset in its frame. */
|
|
for ( unsigned int i = 0; i < nr_frames; i++ )
|
|
{
|
|
unsigned int gref = i * (XC_PAGE_SIZE / sizeof(*gnttab)) + i;
|
|
|
|
refs[i] = gref;
|
|
domids[i] = domid;
|
|
|
|
gnttab[gref].domid = 0;
|
|
gnttab[gref].frame = gfn;
|
|
gnttab[gref].flags = GTF_permit_access;
|
|
}
|
|
|
|
/* Map grants. */
|
|
grants = xengnttab_map_grant_refs(gh, nr_frames, domids, refs,
|
|
PROT_READ | PROT_WRITE);
|
|
|
|
/*
|
|
* Failure here indicates either that the frames were not mapped
|
|
* in the correct order or xenforeignmemory_map_resource() didn't
|
|
* give us the frames we asked for to begin with.
|
|
*/
|
|
if ( grants == NULL )
|
|
{
|
|
fail(" Fail: Map grants %d - %s\n", errno, strerror(errno));
|
|
goto out;
|
|
}
|
|
|
|
/* Unmap grants. */
|
|
rc = xengnttab_unmap(gh, grants, nr_frames);
|
|
|
|
if ( rc )
|
|
fail(" Fail: Unmap grants %d - %s\n", errno, strerror(errno));
|
|
|
|
/* Unmap grant table. */
|
|
out:
|
|
rc = xenforeignmemory_unmap_resource(fh, res);
|
|
if ( rc )
|
|
return fail(" Fail: Unmap grant table %d - %s\n",
|
|
errno, strerror(errno));
|
|
|
|
/*
|
|
* Verify that an attempt to map the status frames fails, as the domain is
|
|
* in gnttab v1 mode.
|
|
*/
|
|
res = xenforeignmemory_map_resource(
|
|
fh, domid, XENMEM_resource_grant_table,
|
|
XENMEM_resource_grant_table_id_status, 0, 1,
|
|
(void **)&gnttab, PROT_READ | PROT_WRITE, 0);
|
|
|
|
if ( res )
|
|
{
|
|
fail(" Fail: Managed to map gnttab v2 status frames in v1 mode\n");
|
|
xenforeignmemory_unmap_resource(fh, res);
|
|
}
|
|
|
|
/*
|
|
* If this check starts failing, you've found the right place to test your
|
|
* addition to the Acquire Resource infrastructure.
|
|
*/
|
|
rc = xenforeignmemory_resource_size(fh, domid, 3, 0, &size);
|
|
|
|
/* Check that Xen rejected the resource type. */
|
|
if ( !rc )
|
|
fail(" Fail: Expected error on an invalid resource type, got success\n");
|
|
}
|
|
|
|
static void test_domain_configurations(void)
|
|
{
|
|
static struct test {
|
|
const char *name;
|
|
struct xen_domctl_createdomain create;
|
|
} tests[] = {
|
|
#if defined(__x86_64__) || defined(__i386__)
|
|
{
|
|
.name = "x86 PV",
|
|
.create = {
|
|
.max_vcpus = 2,
|
|
.max_grant_frames = 40,
|
|
.grant_opts = XEN_DOMCTL_GRANT_version(1),
|
|
},
|
|
},
|
|
{
|
|
.name = "x86 PVH",
|
|
.create = {
|
|
.flags = XEN_DOMCTL_CDF_hvm,
|
|
.max_vcpus = 2,
|
|
.max_grant_frames = 40,
|
|
.grant_opts = XEN_DOMCTL_GRANT_version(1),
|
|
.arch = {
|
|
.emulation_flags = XEN_X86_EMU_LAPIC,
|
|
},
|
|
},
|
|
},
|
|
#elif defined(__aarch64__) || defined(__arm__)
|
|
{
|
|
.name = "ARM",
|
|
.create = {
|
|
.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
|
|
.max_vcpus = 2,
|
|
.max_grant_frames = 40,
|
|
.grant_opts = XEN_DOMCTL_GRANT_version(1),
|
|
},
|
|
},
|
|
#endif
|
|
};
|
|
|
|
for ( unsigned int i = 0; i < ARRAY_SIZE(tests); ++i )
|
|
{
|
|
struct test *t = &tests[i];
|
|
uint32_t domid = 0;
|
|
int rc;
|
|
xen_pfn_t ram[1] = { 0 };
|
|
|
|
printf("Test %s\n", t->name);
|
|
|
|
#if defined(__x86_64__) || defined(__i386__)
|
|
if ( t->create.flags & XEN_DOMCTL_CDF_hvm )
|
|
{
|
|
if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hvm) )
|
|
{
|
|
printf(" Skip: HVM not available\n");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* On x86, use HAP guests if possible, but skip if neither HAP nor
|
|
* SHADOW is available.
|
|
*/
|
|
if ( physinfo.capabilities & XEN_SYSCTL_PHYSCAP_hap )
|
|
t->create.flags |= XEN_DOMCTL_CDF_hap;
|
|
else if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_shadow) )
|
|
{
|
|
printf(" Skip: Neither HAP or SHADOW available\n");
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !(physinfo.capabilities & XEN_SYSCTL_PHYSCAP_pv) )
|
|
{
|
|
printf(" Skip: PV not available\n");
|
|
continue;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
rc = xc_domain_create(xch, &domid, &t->create);
|
|
if ( rc )
|
|
{
|
|
if ( errno == EINVAL || errno == EOPNOTSUPP )
|
|
printf(" Skip: %d - %s\n", errno, strerror(errno));
|
|
else
|
|
fail(" Domain create failure: %d - %s\n",
|
|
errno, strerror(errno));
|
|
continue;
|
|
}
|
|
|
|
printf(" Created d%u\n", domid);
|
|
|
|
rc = xc_domain_setmaxmem(xch, domid, -1);
|
|
if ( rc )
|
|
{
|
|
fail(" Failed to set max memory for domain: %d - %s\n",
|
|
errno, strerror(errno));
|
|
goto test_done;
|
|
}
|
|
|
|
rc = xc_domain_populate_physmap_exact(
|
|
xch, domid, ARRAY_SIZE(ram), 0, 0, ram);
|
|
if ( rc )
|
|
{
|
|
fail(" Failed to populate physmap domain: %d - %s\n",
|
|
errno, strerror(errno));
|
|
goto test_done;
|
|
}
|
|
|
|
test_gnttab(domid, t->create.max_grant_frames, ram[0]);
|
|
|
|
test_done:
|
|
rc = xc_domain_destroy(xch, domid);
|
|
if ( rc )
|
|
fail(" Failed to destroy domain: %d - %s\n",
|
|
errno, strerror(errno));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int rc;
|
|
|
|
printf("XENMEM_acquire_resource tests\n");
|
|
|
|
xch = xc_interface_open(NULL, NULL, 0);
|
|
fh = xenforeignmemory_open(NULL, 0);
|
|
gh = xengnttab_open(NULL, 0);
|
|
|
|
if ( !xch )
|
|
err(1, "xc_interface_open");
|
|
if ( !fh )
|
|
err(1, "xenforeignmemory_open");
|
|
if ( !gh )
|
|
err(1, "xengnttab_open");
|
|
|
|
rc = xc_physinfo(xch, &physinfo);
|
|
if ( rc )
|
|
err(1, "Failed to obtain physinfo");
|
|
|
|
test_domain_configurations();
|
|
|
|
return !!nr_failures;
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|