All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] libx86: Remaining serialisation logic
@ 2019-01-04 15:33 Andrew Cooper
  2019-01-04 15:33 ` [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects Andrew Cooper
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Andrew Cooper @ 2019-01-04 15:33 UTC (permalink / raw)
  To: Xen-devel
  Cc: Andrew Cooper, Sergey Dyasli, Wei Liu, Jan Beulich, Roger Pau Monné

I've lost count of exactly which version this is, due to multiple postings of
various sub series, and several substantial rebases.

I think I've addressed all outstanding review content, so lets start from v1
again.

Andrew Cooper (2):
  libx86: Introduce a helper to deserialise cpuid_policy objects
  tools/cpu-policy: Add unit tests and a fuzzing harness

Roger Pau Monné (1):
  libx86: introduce a helper to deserialise msr_policy objects

 tools/fuzz/cpu-policy/.gitignore          |   1 +
 tools/fuzz/cpu-policy/Makefile            |  27 ++++
 tools/fuzz/cpu-policy/afl-policy-fuzzer.c | 117 ++++++++++++++
 tools/tests/Makefile                      |   1 +
 tools/tests/cpu-policy/.gitignore         |   1 +
 tools/tests/cpu-policy/Makefile           |  27 ++++
 tools/tests/cpu-policy/test-cpu-policy.c  | 247 ++++++++++++++++++++++++++++++
 xen/include/xen/lib/x86/cpuid.h           |  23 ++-
 xen/include/xen/lib/x86/msr.h             |  21 +++
 xen/lib/x86/cpuid.c                       | 106 +++++++++++++
 xen/lib/x86/msr.c                         |  67 ++++++++
 xen/lib/x86/private.h                     |  14 ++
 12 files changed, 651 insertions(+), 1 deletion(-)
 create mode 100644 tools/fuzz/cpu-policy/.gitignore
 create mode 100644 tools/fuzz/cpu-policy/Makefile
 create mode 100644 tools/fuzz/cpu-policy/afl-policy-fuzzer.c
 create mode 100644 tools/tests/cpu-policy/.gitignore
 create mode 100644 tools/tests/cpu-policy/Makefile
 create mode 100644 tools/tests/cpu-policy/test-cpu-policy.c

-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects
  2019-01-04 15:33 [PATCH 0/3] libx86: Remaining serialisation logic Andrew Cooper
@ 2019-01-04 15:33 ` Andrew Cooper
  2019-01-07 10:52   ` Jan Beulich
  2019-01-04 15:33 ` [PATCH 2/3] libx86: introduce a helper to deserialise msr_policy objects Andrew Cooper
  2019-01-04 15:33 ` [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness Andrew Cooper
  2 siblings, 1 reply; 10+ messages in thread
From: Andrew Cooper @ 2019-01-04 15:33 UTC (permalink / raw)
  To: Xen-devel
  Cc: Andrew Cooper, Roger Pau Monné, Wei Liu, Jan Beulich, Sergey Dyasli

As with the serialise side, Xen's copy_from_guest API is used, with a
compatibility wrapper for the userspace build.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 xen/include/xen/lib/x86/cpuid.h |  21 ++++++++
 xen/lib/x86/cpuid.c             | 106 ++++++++++++++++++++++++++++++++++++++++
 xen/lib/x86/private.h           |  14 ++++++
 3 files changed, 141 insertions(+)

diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpuid.h
index 22d43ef..767a33b 100644
--- a/xen/include/xen/lib/x86/cpuid.h
+++ b/xen/include/xen/lib/x86/cpuid.h
@@ -319,6 +319,27 @@ typedef xen_cpuid_leaf_t cpuid_leaf_buffer_t[];
 int x86_cpuid_copy_to_buffer(const struct cpuid_policy *policy,
                              cpuid_leaf_buffer_t leaves, uint32_t *nr_entries);
 
+/**
+ * Unserialise a cpuid_policy object from an array of cpuid leaves.
+ *
+ * @param policy      The cpuid_policy to unserialise into.
+ * @param leaves      The array of leaves to unserialise from.
+ * @param nr_entries  The number of entries in 'leaves'.
+ * @param err_leaf    Optional hint filled on error.
+ * @param err_subleaf Optional hint filled on error.
+ * @returns -errno
+ *
+ * Reads at most CPUID_MAX_SERIALISED_LEAVES.  May return -ERANGE if an
+ * incoming leaf is out of range of cpuid_policy, in which case the optional
+ * err_* pointers are filled to aid diagnostics.
+ *
+ * No content validation of in-range leaves is performed.
+ */
+int x86_cpuid_copy_from_buffer(struct cpuid_policy *policy,
+                               const cpuid_leaf_buffer_t leaves,
+                               uint32_t nr_entries, uint32_t *err_leaf,
+                               uint32_t *err_subleaf);
+
 #endif /* !XEN_LIB_X86_CPUID_H */
 
 /*
diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c
index 5a3159b..7fc4148 100644
--- a/xen/lib/x86/cpuid.c
+++ b/xen/lib/x86/cpuid.c
@@ -233,6 +233,112 @@ int x86_cpuid_copy_to_buffer(const struct cpuid_policy *p,
     return 0;
 }
 
+int x86_cpuid_copy_from_buffer(struct cpuid_policy *p,
+                               const cpuid_leaf_buffer_t leaves,
+                               uint32_t nr_entries, uint32_t *err_leaf,
+                               uint32_t *err_subleaf)
+{
+    unsigned int i;
+    xen_cpuid_leaf_t data;
+    struct cpuid_leaf *l = (void *)&data.a;
+
+    /*
+     * A well formed caller is expected pass an array with leaves in order,
+     * and without any repetitions.  However, due to per-vendor differences,
+     * and in the case of upgrade or levelled scenarios, we typically expect
+     * fewer than MAX leaves to be passed.
+     *
+     * Detecting repeated entries is prohibitively complicated, so we don't
+     * bother.  That said, one way or another if more than MAX leaves are
+     * passed, something is wrong.
+     */
+    if ( nr_entries > CPUID_MAX_SERIALISED_LEAVES )
+        return -E2BIG;
+
+    for ( i = 0; i < nr_entries; ++i )
+    {
+        if ( copy_from_buffer_offset(&data, leaves, i, 1) )
+            return -EFAULT;
+
+        switch ( data.leaf )
+        {
+        case 0 ... ARRAY_SIZE(p->basic.raw) - 1:
+            switch ( data.leaf )
+            {
+            case 0x4:
+                if ( data.subleaf >= ARRAY_SIZE(p->cache.raw) )
+                    goto out_of_range;
+
+                p->cache.raw[data.subleaf] = *l;
+                break;
+
+            case 0x7:
+                if ( data.subleaf >= ARRAY_SIZE(p->feat.raw) )
+                    goto out_of_range;
+
+                p->feat.raw[data.subleaf] = *l;
+                break;
+
+            case 0xb:
+                if ( data.subleaf >= ARRAY_SIZE(p->topo.raw) )
+                    goto out_of_range;
+
+                p->topo.raw[data.subleaf] = *l;
+                break;
+
+            case 0xd:
+                if ( data.subleaf >= ARRAY_SIZE(p->xstate.raw) )
+                    goto out_of_range;
+
+                p->xstate.raw[data.subleaf] = *l;
+                break;
+
+            default:
+                if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
+                    goto out_of_range;
+
+                p->basic.raw[data.leaf] = *l;
+                break;
+            }
+            break;
+
+        case 0x40000000:
+            if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
+                goto out_of_range;
+
+            p->hv_limit = l->a;
+            break;
+
+        case 0x40000100:
+            if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
+                goto out_of_range;
+
+            p->hv2_limit = l->a;
+            break;
+
+        case 0x80000000 ... 0x80000000 + ARRAY_SIZE(p->extd.raw) - 1:
+            if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
+                goto out_of_range;
+
+            p->extd.raw[data.leaf & 0xffff] = *l;
+            break;
+
+        default:
+            goto out_of_range;
+        }
+    }
+
+    return 0;
+
+ out_of_range:
+    if ( err_leaf )
+        *err_leaf = data.leaf;
+    if ( err_subleaf )
+        *err_subleaf = data.subleaf;
+
+    return -ERANGE;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/lib/x86/private.h b/xen/lib/x86/private.h
index 3ee99aa..e0ff2da 100644
--- a/xen/lib/x86/private.h
+++ b/xen/lib/x86/private.h
@@ -12,6 +12,7 @@
 #include <asm/msr-index.h>
 
 #define copy_to_buffer_offset copy_to_guest_offset
+#define copy_from_buffer_offset copy_from_guest_offset
 
 #else
 
@@ -44,6 +45,19 @@ static inline bool test_bit(unsigned int bit, const void *vaddr)
     0;                                                  \
 })
 
+/* memcpy(), but with copy_from_guest_offset()'s API. */
+#define copy_from_buffer_offset(dst, src, index, nr)    \
+({                                                      \
+    const typeof(*(src)) *src_ = (src);                 \
+    typeof(*(dst)) *dst_ = (dst);                       \
+    typeof(index) index_ = (index);                     \
+    typeof(nr) nr_ = (nr), i_;                          \
+                                                        \
+    for ( i_ = 0; i_ < nr_; i_++ )                      \
+        dst_[i_] = src_[index_ + i_];                   \
+    0;                                                  \
+})
+
 #endif /* __XEN__ */
 
 #endif /* XEN_LIB_X86_PRIVATE_H */
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] libx86: introduce a helper to deserialise msr_policy objects
  2019-01-04 15:33 [PATCH 0/3] libx86: Remaining serialisation logic Andrew Cooper
  2019-01-04 15:33 ` [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects Andrew Cooper
@ 2019-01-04 15:33 ` Andrew Cooper
  2019-01-07 10:55   ` Jan Beulich
  2019-01-04 15:33 ` [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness Andrew Cooper
  2 siblings, 1 reply; 10+ messages in thread
From: Andrew Cooper @ 2019-01-04 15:33 UTC (permalink / raw)
  To: Xen-devel
  Cc: Sergey Dyasli, Andrew Cooper, Wei Liu, Jan Beulich, Roger Pau Monné

From: Roger Pau Monné <roger.pau@citrix.com>

Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 xen/include/xen/lib/x86/msr.h | 21 ++++++++++++++
 xen/lib/x86/msr.c             | 67 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 88 insertions(+)

diff --git a/xen/include/xen/lib/x86/msr.h b/xen/include/xen/lib/x86/msr.h
index e2cfbb1..6236622 100644
--- a/xen/include/xen/lib/x86/msr.h
+++ b/xen/include/xen/lib/x86/msr.h
@@ -48,6 +48,27 @@ typedef xen_msr_entry_t msr_entry_buffer_t[];
 int x86_msr_copy_to_buffer(const struct msr_policy *policy,
                            msr_entry_buffer_t msrs, uint32_t *nr_entries);
 
+/**
+ * Unserialise an msr_policy object from an array of msrs.
+ *
+ * @param policy     The msr_policy object to unserialise into.
+ * @param msrs       The array of msrs to unserialise from.
+ * @param nr_entries The number of entries in 'msrs'.
+ * @param err_msr    Optional hint filled on error.
+ * @returns -errno
+ *
+ * Reads at most MSR_MAX_SERIALISED_ENTRIES.  May fail for a number of reasons
+ * based on the content in an individual 'msrs' entry, including the MSR index
+ * not being valid in the policy, the flags field being nonzero, or if the
+ * value provided would truncate when stored in the policy.  In such cases,
+ * the optional err_* pointer is filled in to aid diagnostics.
+ *
+ * No content validation is performed on the data stored in the policy object.
+ */
+int x86_msr_copy_from_buffer(struct msr_policy *policy,
+                             const msr_entry_buffer_t msrs, uint32_t nr_entries,
+                             uint32_t *err_msr);
+
 #endif /* !XEN_LIB_X86_MSR_H */
 
 /*
diff --git a/xen/lib/x86/msr.c b/xen/lib/x86/msr.c
index 60fb567..e498124 100644
--- a/xen/lib/x86/msr.c
+++ b/xen/lib/x86/msr.c
@@ -47,6 +47,73 @@ int x86_msr_copy_to_buffer(const struct msr_policy *p,
     return 0;
 }
 
+int x86_msr_copy_from_buffer(struct msr_policy *p,
+                             const msr_entry_buffer_t msrs, uint32_t nr_entries,
+                             uint32_t *err_msr)
+{
+    unsigned int i;
+    xen_msr_entry_t data;
+    int rc;
+
+    /*
+     * A well formed caller is expected pass an array with entries in order,
+     * and without any repetitions.  However, due to per-vendor differences,
+     * and in the case of upgrade or levelled scenarios, we typically expect
+     * fewer than MAX entries to be passed.
+     *
+     * Detecting repeated entries is prohibitively complicated, so we don't
+     * bother.  That said, one way or another if more than MAX entries are
+     * passed, something is wrong.
+     */
+    if ( nr_entries > MSR_MAX_SERIALISED_ENTRIES )
+        return -E2BIG;
+
+    for ( i = 0; i < nr_entries; i++ )
+    {
+        if ( copy_from_buffer_offset(&data, msrs, i, 1) )
+            return -EFAULT;
+
+        if ( data.flags ) /* .flags MBZ */
+        {
+            rc = -EINVAL;
+            goto err;
+        }
+
+        switch ( data.idx )
+        {
+            /*
+             * Assign data.val to 'field', checking for truncation if the
+             * backing storage for 'field' is smaller than uint64_t
+             */
+#define ASSIGN(field)                           \
+({                                              \
+    if ( (typeof(field))data.val != data.val )  \
+    {                                           \
+        rc = -EOVERFLOW;                        \
+        goto err;                               \
+    }                                           \
+    field = data.val;                           \
+})
+
+        case MSR_INTEL_PLATFORM_INFO: ASSIGN(p->plaform_info.raw); break;
+
+#undef ASSIGN
+
+        default:
+            rc = -ERANGE;
+            goto err;
+        }
+    }
+
+    return 0;
+
+ err:
+    if ( err_msr )
+        *err_msr = data.idx;
+
+    return rc;
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness
  2019-01-04 15:33 [PATCH 0/3] libx86: Remaining serialisation logic Andrew Cooper
  2019-01-04 15:33 ` [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects Andrew Cooper
  2019-01-04 15:33 ` [PATCH 2/3] libx86: introduce a helper to deserialise msr_policy objects Andrew Cooper
@ 2019-01-04 15:33 ` Andrew Cooper
  2019-01-07 11:19   ` Jan Beulich
  2 siblings, 1 reply; 10+ messages in thread
From: Andrew Cooper @ 2019-01-04 15:33 UTC (permalink / raw)
  To: Xen-devel
  Cc: Andrew Cooper, Sergey Dyasli, Wei Liu, Jan Beulich, Roger Pau Monné

The AFL harness currently notices that there are cases where we optimse the
serialised stream by omitting data beyond the various maximum leaves.

Both sets of tests will be extended with further libx86 work.

Fix the sorting of the CPUID_GUEST_NR_* constants, noticed while writing the
unit tests.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 tools/fuzz/cpu-policy/.gitignore          |   1 +
 tools/fuzz/cpu-policy/Makefile            |  27 ++++
 tools/fuzz/cpu-policy/afl-policy-fuzzer.c | 117 ++++++++++++++
 tools/tests/Makefile                      |   1 +
 tools/tests/cpu-policy/.gitignore         |   1 +
 tools/tests/cpu-policy/Makefile           |  27 ++++
 tools/tests/cpu-policy/test-cpu-policy.c  | 247 ++++++++++++++++++++++++++++++
 xen/include/xen/lib/x86/cpuid.h           |   2 +-
 8 files changed, 422 insertions(+), 1 deletion(-)
 create mode 100644 tools/fuzz/cpu-policy/.gitignore
 create mode 100644 tools/fuzz/cpu-policy/Makefile
 create mode 100644 tools/fuzz/cpu-policy/afl-policy-fuzzer.c
 create mode 100644 tools/tests/cpu-policy/.gitignore
 create mode 100644 tools/tests/cpu-policy/Makefile
 create mode 100644 tools/tests/cpu-policy/test-cpu-policy.c

diff --git a/tools/fuzz/cpu-policy/.gitignore b/tools/fuzz/cpu-policy/.gitignore
new file mode 100644
index 0000000..b0e0bdf
--- /dev/null
+++ b/tools/fuzz/cpu-policy/.gitignore
@@ -0,0 +1 @@
+afl-policy-fuzzer
diff --git a/tools/fuzz/cpu-policy/Makefile b/tools/fuzz/cpu-policy/Makefile
new file mode 100644
index 0000000..a25778b
--- /dev/null
+++ b/tools/fuzz/cpu-policy/Makefile
@@ -0,0 +1,27 @@
+XEN_ROOT = $(CURDIR)/../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+.PHONY: all
+all: afl-policy-fuzzer
+
+.PHONY: clean
+clean:
+	$(RM) -f -- *.o .*.d .*.d2 afl-policy-fuzzer
+
+.PHONY: distclean
+distclean: clean
+	$(RM) -f -- *~
+
+.PHONY: install
+install: all
+
+.PHONY: uninstall
+
+CFLAGS += -Werror $(CFLAGS_xeninclude) -D__XEN_TOOLS__
+
+vpath %.c ../../../xen/lib/x86
+
+afl-policy-fuzzer: afl-policy-fuzzer.o msr.o cpuid.o
+	$(CC) $(CFLAGS) $^ -o $@
+
+-include $(DEPS_INCLUDE)
diff --git a/tools/fuzz/cpu-policy/afl-policy-fuzzer.c b/tools/fuzz/cpu-policy/afl-policy-fuzzer.c
new file mode 100644
index 0000000..557df81
--- /dev/null
+++ b/tools/fuzz/cpu-policy/afl-policy-fuzzer.c
@@ -0,0 +1,117 @@
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xen-tools/libs.h>
+#include <xen/lib/x86/cpuid.h>
+#include <xen/lib/x86/msr.h>
+#include <xen/domctl.h>
+
+void check_cpuid(const struct cpuid_policy *cp)
+{
+    struct cpuid_policy new = {};
+    xen_cpuid_leaf_t *leaves = malloc(CPUID_MAX_SERIALISED_LEAVES *
+                                      sizeof(xen_cpuid_leaf_t));
+    unsigned int nr = CPUID_MAX_SERIALISED_LEAVES;
+    int rc;
+
+    if ( !leaves )
+        return;
+
+    rc = x86_cpuid_copy_to_buffer(cp, leaves, &nr);
+    assert(rc == 0);
+    assert(nr <= CPUID_MAX_SERIALISED_LEAVES);
+
+    rc = x86_cpuid_copy_from_buffer(&new, leaves, nr, NULL, NULL);
+    assert(rc == 0);
+    assert(memcmp(cp, &new, sizeof(*cp)) == 0);
+
+    free(leaves);
+}
+
+void check_msr(const struct msr_policy *mp)
+{
+    struct msr_policy new = {};
+    xen_msr_entry_t *msrs = malloc(MSR_MAX_SERIALISED_ENTRIES *
+                                   sizeof(xen_msr_entry_t));
+    unsigned int nr = MSR_MAX_SERIALISED_ENTRIES;
+    int rc;
+
+    if ( !msrs )
+        return;
+
+    rc = x86_msr_copy_to_buffer(mp, msrs, &nr);
+    assert(rc == 0);
+    assert(nr <= MSR_MAX_SERIALISED_ENTRIES);
+
+    rc = x86_msr_copy_from_buffer(&new, msrs, nr, NULL);
+    assert(rc == 0);
+    assert(memcmp(mp, &new, sizeof(*mp)) == 0);
+
+    free(msrs);
+}
+
+int main(int argc, char **argv)
+{
+    FILE *fp = NULL;
+    struct cpuid_policy *cp = NULL;
+    struct msr_policy *mp = NULL;
+
+    setbuf(stdin, NULL);
+    setbuf(stdout, NULL);
+
+    if ( argc == 1 )
+    {
+        printf("Using stdin\n");
+        fp = stdin;
+    }
+
+#ifdef __AFL_HAVE_MANUAL_CONTROL
+    __AFL_INIT();
+    while ( __AFL_LOOP(1000) )
+#endif
+    {
+        if ( fp != stdin )
+        {
+            printf("Opening file '%s'\n", argv[1]);
+            fp = fopen(argv[1], "rb");
+
+            if ( !fp )
+            {
+                perror("fopen");
+                exit(-1);
+            }
+        }
+
+        cp = calloc(1, sizeof(*cp));
+        mp = calloc(1, sizeof(*mp));
+        if ( !cp || !mp )
+            goto skip;
+
+        fread(cp, sizeof(*cp), 1, fp);
+        fread(mp, sizeof(*mp), 1, fp);
+
+        if ( !feof(fp) )
+            goto skip;
+
+        check_cpuid(cp);
+        check_msr(mp);
+
+    skip:
+        free(cp);
+        cp = NULL;
+        free(mp);
+        mp = NULL;
+
+        if ( fp != stdin )
+        {
+            fclose(fp);
+            fp = NULL;
+        }
+    }
+
+    return 0;
+}
diff --git a/tools/tests/Makefile b/tools/tests/Makefile
index a9fc50d..067a380 100644
--- a/tools/tests/Makefile
+++ b/tools/tests/Makefile
@@ -5,6 +5,7 @@ CFLAGS  += $(CFLAGS_libxenctrl)
 LDLIBS += $(LDLIBS_libxenctrl)
 
 SUBDIRS-y :=
+SUBDIRS-$(CONFIG_X86) += cpu-policy
 SUBDIRS-$(CONFIG_X86) += mce-test
 SUBDIRS-y += mem-sharing
 ifeq ($(XEN_TARGET_ARCH),__fixme__)
diff --git a/tools/tests/cpu-policy/.gitignore b/tools/tests/cpu-policy/.gitignore
new file mode 100644
index 0000000..83bdb6b
--- /dev/null
+++ b/tools/tests/cpu-policy/.gitignore
@@ -0,0 +1 @@
+test-cpu-policy
diff --git a/tools/tests/cpu-policy/Makefile b/tools/tests/cpu-policy/Makefile
new file mode 100644
index 0000000..a029165
--- /dev/null
+++ b/tools/tests/cpu-policy/Makefile
@@ -0,0 +1,27 @@
+XEN_ROOT = $(CURDIR)/../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+.PHONY: all
+all: test-cpu-policy
+
+.PHONY: clean
+clean:
+	$(RM) -f -- *.o .*.d .*.d2 test-cpu-policy
+
+.PHONY: distclean
+distclean: clean
+	$(RM) -f -- *~
+
+.PHONY: install
+install: all
+
+.PHONY: uninstall
+
+CFLAGS += -Werror $(CFLAGS_xeninclude) -D__XEN_TOOLS__ -O3
+
+vpath %.c ../../../xen/lib/x86
+
+test-cpu-policy: test-cpu-policy.o msr.o cpuid.o
+	$(CC) $(CFLAGS) $^ -o $@
+
+-include $(DEPS_INCLUDE)
diff --git a/tools/tests/cpu-policy/test-cpu-policy.c b/tools/tests/cpu-policy/test-cpu-policy.c
new file mode 100644
index 0000000..7414ac7
--- /dev/null
+++ b/tools/tests/cpu-policy/test-cpu-policy.c
@@ -0,0 +1,247 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xen-tools/libs.h>
+#include <xen/lib/x86/cpuid.h>
+#include <xen/lib/x86/msr.h>
+#include <xen/domctl.h>
+
+static void test_cpuid_serialise_success(void)
+{
+    static const struct test {
+        struct cpuid_policy p;
+        const char *name;
+        unsigned int nr_leaves;
+    } tests[] = {
+        {
+            .name = "empty policy",
+            .nr_leaves = 4,
+        },
+    };
+    unsigned int i;
+
+    printf("Testing CPUID serialise success:\n");
+
+    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
+    {
+        const struct test *t = &tests[i];
+        unsigned int nr = t->nr_leaves;
+        xen_cpuid_leaf_t *leaves = malloc(nr * sizeof(*leaves));
+        int rc;
+
+        if ( !leaves )
+            goto test_done;
+
+        rc = x86_cpuid_copy_to_buffer(&t->p, leaves, &nr);
+
+        if ( rc != 0 )
+        {
+            printf("  Test %s, expected rc 0, got %d\n",
+                   t->name, rc);
+            goto test_done;
+        }
+
+        if ( nr != t->nr_leaves )
+        {
+            printf("  Test %s, expected %u leaves, got %u\n",
+                   t->name, t->nr_leaves, nr);
+            goto test_done;
+        }
+
+    test_done:
+        free(leaves);
+    }
+}
+
+static void test_msr_serialise_success(void)
+{
+    static const struct test {
+        struct msr_policy p;
+        const char *name;
+        unsigned int nr_msrs;
+    } tests[] = {
+        {
+            .name = "empty policy",
+            .nr_msrs = MSR_MAX_SERIALISED_ENTRIES,
+        },
+    };
+    unsigned int i;
+
+    printf("Testing MSR serialise success:\n");
+
+    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
+    {
+        const struct test *t = &tests[i];
+        unsigned int nr = t->nr_msrs;
+        xen_msr_entry_t *msrs = malloc(nr * sizeof(*msrs));
+        int rc;
+
+        if ( !msrs )
+            goto test_done;
+
+        rc = x86_msr_copy_to_buffer(&t->p, msrs, &nr);
+
+        if ( rc != 0 )
+        {
+            printf("  Test %s, expected rc 0, got %d\n",
+                   t->name, rc);
+            goto test_done;
+        }
+
+        if ( nr != t->nr_msrs )
+        {
+            printf("  Test %s, expected %u msrs, got %u\n",
+                   t->name, t->nr_msrs, nr);
+            goto test_done;
+        }
+
+    test_done:
+        free(msrs);
+    }
+}
+
+static void test_cpuid_deserialise_failure(void)
+{
+    static const struct test {
+        const char *name;
+        xen_cpuid_leaf_t leaf;
+    } tests[] = {
+        {
+            .name = "incorrect basic subleaf",
+            .leaf = { .leaf = 0, .subleaf = 0 },
+        },
+        {
+            .name = "incorrect hv1 subleaf",
+            .leaf = { .leaf = 0x40000000, .subleaf = 0 },
+        },
+        {
+            .name = "incorrect hv2 subleaf",
+            .leaf = { .leaf = 0x40000100, .subleaf = 0 },
+        },
+        {
+            .name = "incorrect extd subleaf",
+            .leaf = { .leaf = 0x80000000, .subleaf = 0 },
+        },
+        {
+            .name = "OoB basic leaf",
+            .leaf = { .leaf = CPUID_GUEST_NR_BASIC },
+        },
+        {
+            .name = "OoB cache leaf",
+            .leaf = { .leaf = 0x4, .subleaf = CPUID_GUEST_NR_CACHE },
+        },
+        {
+            .name = "OoB feat leaf",
+            .leaf = { .leaf = 0x7, .subleaf = CPUID_GUEST_NR_FEAT },
+        },
+        {
+            .name = "OoB topo leaf",
+            .leaf = { .leaf = 0xb, .subleaf = CPUID_GUEST_NR_TOPO },
+        },
+        {
+            .name = "OoB xstate leaf",
+            .leaf = { .leaf = 0xd, .subleaf = CPUID_GUEST_NR_XSTATE },
+        },
+        {
+            .name = "OoB extd leaf",
+            .leaf = { .leaf = 0x80000000 | CPUID_GUEST_NR_EXTD },
+        },
+    };
+    unsigned int i;
+
+    printf("Testing CPUID deserialise failure:\n");
+
+    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
+    {
+        const struct test *t = &tests[i];
+        uint32_t err_leaf = ~0u, err_subleaf = ~0u;
+        int rc;
+
+        rc = x86_cpuid_copy_from_buffer(NULL, &t->leaf, 1,
+                                        &err_leaf, &err_subleaf);
+
+        if ( rc != -ERANGE )
+        {
+            printf("  Test %s, expected rc %d, got %d\n",
+                   t->name, -ERANGE, rc);
+            continue;
+        }
+
+        if ( err_leaf != t->leaf.leaf || err_subleaf != t->leaf.subleaf )
+        {
+            printf("  Test %s, expected err %08x:%08x, got %08x:%08x\n",
+                   t->name, t->leaf.leaf, t->leaf.subleaf,
+                   err_leaf, err_subleaf);
+            continue;
+        }
+    }
+}
+
+static void test_msr_deserialise_failure(void)
+{
+    static const struct test {
+        const char *name;
+        xen_msr_entry_t msr;
+        int rc;
+    } tests[] = {
+        {
+            .name = "bad msr index",
+            .msr = { .idx = 0xdeadc0de },
+            .rc = -ERANGE,
+        },
+        {
+            .name = "nonzero flags",
+            .msr = { .idx = 0xce, .flags = 1 },
+            .rc = -EINVAL,
+        },
+        {
+            .name = "truncated val",
+            .msr = { .idx = 0xce, .val = ~0ull },
+            .rc = -EOVERFLOW,
+        },
+    };
+    unsigned int i;
+
+    printf("Testing MSR deserialise failure:\n");
+
+    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
+    {
+        const struct test *t = &tests[i];
+        uint32_t err_msr = ~0u;
+        int rc;
+
+        rc = x86_msr_copy_from_buffer(NULL, &t->msr, 1, &err_msr);
+
+        if ( rc != t->rc )
+        {
+            printf("  Test %s, expected rc %d, got %d\n",
+                   t->name, t->rc, rc);
+            continue;
+        }
+
+        if ( err_msr != t->msr.idx )
+        {
+            printf("  Test %s, expected err_msr %#x, got %#x\n",
+                   t->name, t->msr.idx, err_msr);
+            continue;
+        }
+    }
+}
+
+int main(int argc, char **argv)
+{
+    printf("CPU Policy unit tests\n");
+
+    test_cpuid_serialise_success();
+    test_msr_serialise_success();
+
+    test_cpuid_deserialise_failure();
+    test_msr_deserialise_failure();
+
+    return 0;
+}
diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpuid.h
index 767a33b..95b37b6 100644
--- a/xen/include/xen/lib/x86/cpuid.h
+++ b/xen/include/xen/lib/x86/cpuid.h
@@ -66,8 +66,8 @@ static inline void cpuid_count_leaf(
 #undef XCHG
 
 #define CPUID_GUEST_NR_BASIC      (0xdu + 1)
-#define CPUID_GUEST_NR_FEAT       (0u + 1)
 #define CPUID_GUEST_NR_CACHE      (5u + 1)
+#define CPUID_GUEST_NR_FEAT       (0u + 1)
 #define CPUID_GUEST_NR_TOPO       (1u + 1)
 #define CPUID_GUEST_NR_XSTATE     (62u + 1)
 #define CPUID_GUEST_NR_EXTD_INTEL (0x8u + 1)
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects
  2019-01-04 15:33 ` [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects Andrew Cooper
@ 2019-01-07 10:52   ` Jan Beulich
  2019-02-25 11:41     ` Andrew Cooper
  0 siblings, 1 reply; 10+ messages in thread
From: Jan Beulich @ 2019-01-07 10:52 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Sergey Dyasli, Xen-devel, Wei Liu, Roger Pau Monne

>>> On 04.01.19 at 16:33, <andrew.cooper3@citrix.com> wrote:
> --- a/xen/include/xen/lib/x86/cpuid.h
> +++ b/xen/include/xen/lib/x86/cpuid.h
> @@ -319,6 +319,27 @@ typedef xen_cpuid_leaf_t cpuid_leaf_buffer_t[];
>  int x86_cpuid_copy_to_buffer(const struct cpuid_policy *policy,
>                               cpuid_leaf_buffer_t leaves, uint32_t *nr_entries);
>  
> +/**
> + * Unserialise a cpuid_policy object from an array of cpuid leaves.
> + *
> + * @param policy      The cpuid_policy to unserialise into.
> + * @param leaves      The array of leaves to unserialise from.
> + * @param nr_entries  The number of entries in 'leaves'.
> + * @param err_leaf    Optional hint filled on error.
> + * @param err_subleaf Optional hint filled on error.
> + * @returns -errno
> + *
> + * Reads at most CPUID_MAX_SERIALISED_LEAVES.  May return -ERANGE if an
> + * incoming leaf is out of range of cpuid_policy, in which case the optional
> + * err_* pointers are filled to aid diagnostics.
> + *
> + * No content validation of in-range leaves is performed.
> + */
> +int x86_cpuid_copy_from_buffer(struct cpuid_policy *policy,
> +                               const cpuid_leaf_buffer_t leaves,
> +                               uint32_t nr_entries, uint32_t *err_leaf,
> +                               uint32_t *err_subleaf);
> +
>  #endif /* !XEN_LIB_X86_CPUID_H */
>  
>  /*
> diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c
> index 5a3159b..7fc4148 100644
> --- a/xen/lib/x86/cpuid.c
> +++ b/xen/lib/x86/cpuid.c
> @@ -233,6 +233,112 @@ int x86_cpuid_copy_to_buffer(const struct cpuid_policy 
> *p,
>      return 0;
>  }
>  
> +int x86_cpuid_copy_from_buffer(struct cpuid_policy *p,
> +                               const cpuid_leaf_buffer_t leaves,
> +                               uint32_t nr_entries, uint32_t *err_leaf,
> +                               uint32_t *err_subleaf)
> +{
> +    unsigned int i;
> +    xen_cpuid_leaf_t data;
> +    struct cpuid_leaf *l = (void *)&data.a;

I'd find this cast a little less worrying if you used container_of(). But
even then I dislike this well hidden assumption of similar layouts
of struct cpuid_leaf and the latter parts of struct xen_cpuid_leaf.

Also it looks as if this could be a pointer to const.

> +    /*
> +     * A well formed caller is expected pass an array with leaves in order,

... expected to pass ...

> +     * and without any repetitions.  However, due to per-vendor differences,
> +     * and in the case of upgrade or levelled scenarios, we typically expect
> +     * fewer than MAX leaves to be passed.
> +     *
> +     * Detecting repeated entries is prohibitively complicated, so we don't
> +     * bother.  That said, one way or another if more than MAX leaves are
> +     * passed, something is wrong.
> +     */
> +    if ( nr_entries > CPUID_MAX_SERIALISED_LEAVES )
> +        return -E2BIG;
> +
> +    for ( i = 0; i < nr_entries; ++i )
> +    {
> +        if ( copy_from_buffer_offset(&data, leaves, i, 1) )
> +            return -EFAULT;
> +
> +        switch ( data.leaf )
> +        {
> +        case 0 ... ARRAY_SIZE(p->basic.raw) - 1:
> +            switch ( data.leaf )
> +            {
> +            case 0x4:
> +                if ( data.subleaf >= ARRAY_SIZE(p->cache.raw) )
> +                    goto out_of_range;
> +
> +                p->cache.raw[data.subleaf] = *l;

Do you not want to use array_index_nospec() here and below?

> +                break;
> +
> +            case 0x7:
> +                if ( data.subleaf >= ARRAY_SIZE(p->feat.raw) )
> +                    goto out_of_range;
> +
> +                p->feat.raw[data.subleaf] = *l;
> +                break;
> +
> +            case 0xb:
> +                if ( data.subleaf >= ARRAY_SIZE(p->topo.raw) )
> +                    goto out_of_range;
> +
> +                p->topo.raw[data.subleaf] = *l;
> +                break;
> +
> +            case 0xd:
> +                if ( data.subleaf >= ARRAY_SIZE(p->xstate.raw) )
> +                    goto out_of_range;
> +
> +                p->xstate.raw[data.subleaf] = *l;
> +                break;
> +
> +            default:
> +                if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
> +                    goto out_of_range;
> +
> +                p->basic.raw[data.leaf] = *l;
> +                break;
> +            }
> +            break;
> +
> +        case 0x40000000:
> +            if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
> +                goto out_of_range;
> +
> +            p->hv_limit = l->a;
> +            break;
> +
> +        case 0x40000100:
> +            if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
> +                goto out_of_range;
> +
> +            p->hv2_limit = l->a;
> +            break;
> +
> +        case 0x80000000 ... 0x80000000 + ARRAY_SIZE(p->extd.raw) - 1:
> +            if ( data.subleaf != XEN_CPUID_NO_SUBLEAF )
> +                goto out_of_range;
> +
> +            p->extd.raw[data.leaf & 0xffff] = *l;
> +            break;
> +
> +        default:
> +            goto out_of_range;

Any chance I could talk you into moving the label right here,
eliminating the ugly (to me at least) error handling code after
the main return point of the function?

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] libx86: introduce a helper to deserialise msr_policy objects
  2019-01-04 15:33 ` [PATCH 2/3] libx86: introduce a helper to deserialise msr_policy objects Andrew Cooper
@ 2019-01-07 10:55   ` Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2019-01-07 10:55 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Sergey Dyasli, Xen-devel, Wei Liu, Roger Pau Monne

>>> On 04.01.19 at 16:33, <andrew.cooper3@citrix.com> wrote:
> From: Roger Pau Monné <roger.pau@citrix.com>
> 
> Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>

Where applicable, same comments here as for patch 1.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness
  2019-01-04 15:33 ` [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness Andrew Cooper
@ 2019-01-07 11:19   ` Jan Beulich
  2019-02-25 11:56     ` Andrew Cooper
  0 siblings, 1 reply; 10+ messages in thread
From: Jan Beulich @ 2019-01-07 11:19 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Sergey Dyasli, Xen-devel, Wei Liu, Roger Pau Monne

>>> On 04.01.19 at 16:33, <andrew.cooper3@citrix.com> wrote:
> The AFL harness currently notices that there are cases where we optimse the
> serialised stream by omitting data beyond the various maximum leaves.
> 
> Both sets of tests will be extended with further libx86 work.
> 
> Fix the sorting of the CPUID_GUEST_NR_* constants, noticed while writing the
> unit tests.
> 
> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
> ---
> CC: Jan Beulich <JBeulich@suse.com>
> CC: Wei Liu <wei.liu2@citrix.com>
> CC: Roger Pau Monné <roger.pau@citrix.com>
> CC: Sergey Dyasli <sergey.dyasli@citrix.com>
> ---
>  tools/fuzz/cpu-policy/.gitignore          |   1 +
>  tools/fuzz/cpu-policy/Makefile            |  27 ++++
>  tools/fuzz/cpu-policy/afl-policy-fuzzer.c | 117 ++++++++++++++
>  tools/tests/Makefile                      |   1 +
>  tools/tests/cpu-policy/.gitignore         |   1 +

Did we somehow come to the conclusion that the central .gitignore
at the root of the tree is not the way to go in the future?

> --- /dev/null
> +++ b/tools/tests/cpu-policy/test-cpu-policy.c
> @@ -0,0 +1,247 @@
> +#include <assert.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <xen-tools/libs.h>
> +#include <xen/lib/x86/cpuid.h>
> +#include <xen/lib/x86/msr.h>
> +#include <xen/domctl.h>
> +
> +static void test_cpuid_serialise_success(void)
> +{
> +    static const struct test {
> +        struct cpuid_policy p;
> +        const char *name;
> +        unsigned int nr_leaves;
> +    } tests[] = {
> +        {
> +            .name = "empty policy",
> +            .nr_leaves = 4,
> +        },
> +    };
> +    unsigned int i;
> +
> +    printf("Testing CPUID serialise success:\n");
> +
> +    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
> +    {
> +        const struct test *t = &tests[i];
> +        unsigned int nr = t->nr_leaves;
> +        xen_cpuid_leaf_t *leaves = malloc(nr * sizeof(*leaves));
> +        int rc;
> +
> +        if ( !leaves )
> +            goto test_done;

Shouldn't you leave some indication of the test not having got run?

> +static void test_cpuid_deserialise_failure(void)
> +{
> +    static const struct test {
> +        const char *name;
> +        xen_cpuid_leaf_t leaf;
> +    } tests[] = {
> +        {
> +            .name = "incorrect basic subleaf",
> +            .leaf = { .leaf = 0, .subleaf = 0 },
> +        },
> +        {
> +            .name = "incorrect hv1 subleaf",
> +            .leaf = { .leaf = 0x40000000, .subleaf = 0 },
> +        },
> +        {
> +            .name = "incorrect hv2 subleaf",
> +            .leaf = { .leaf = 0x40000100, .subleaf = 0 },
> +        },
> +        {
> +            .name = "incorrect extd subleaf",
> +            .leaf = { .leaf = 0x80000000, .subleaf = 0 },
> +        },
> +        {
> +            .name = "OoB basic leaf",
> +            .leaf = { .leaf = CPUID_GUEST_NR_BASIC },
> +        },
> +        {
> +            .name = "OoB cache leaf",
> +            .leaf = { .leaf = 0x4, .subleaf = CPUID_GUEST_NR_CACHE },
> +        },
> +        {
> +            .name = "OoB feat leaf",
> +            .leaf = { .leaf = 0x7, .subleaf = CPUID_GUEST_NR_FEAT },
> +        },
> +        {
> +            .name = "OoB topo leaf",
> +            .leaf = { .leaf = 0xb, .subleaf = CPUID_GUEST_NR_TOPO },
> +        },
> +        {
> +            .name = "OoB xstate leaf",
> +            .leaf = { .leaf = 0xd, .subleaf = CPUID_GUEST_NR_XSTATE },
> +        },
> +        {
> +            .name = "OoB extd leaf",
> +            .leaf = { .leaf = 0x80000000 | CPUID_GUEST_NR_EXTD },
> +        },
> +    };
> +    unsigned int i;
> +
> +    printf("Testing CPUID deserialise failure:\n");
> +
> +    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
> +    {
> +        const struct test *t = &tests[i];
> +        uint32_t err_leaf = ~0u, err_subleaf = ~0u;
> +        int rc;
> +
> +        rc = x86_cpuid_copy_from_buffer(NULL, &t->leaf, 1,
> +                                        &err_leaf, &err_subleaf);
> +
> +        if ( rc != -ERANGE )
> +        {
> +            printf("  Test %s, expected rc %d, got %d\n",
> +                   t->name, -ERANGE, rc);
> +            continue;

Perhaps drop this? The subsequent test ought to apply regardless
of error code.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects
  2019-01-07 10:52   ` Jan Beulich
@ 2019-02-25 11:41     ` Andrew Cooper
  0 siblings, 0 replies; 10+ messages in thread
From: Andrew Cooper @ 2019-02-25 11:41 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Sergey Dyasli, Xen-devel, Wei Liu, Roger Pau Monne

On 07/01/2019 10:52, Jan Beulich wrote:
>> diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c
>> index 5a3159b..7fc4148 100644
>> --- a/xen/lib/x86/cpuid.c
>> +++ b/xen/lib/x86/cpuid.c
>> @@ -233,6 +233,112 @@ int x86_cpuid_copy_to_buffer(const struct cpuid_policy 
>> *p,
>>      return 0;
>>  }
>>  
>> +int x86_cpuid_copy_from_buffer(struct cpuid_policy *p,
>> +                               const cpuid_leaf_buffer_t leaves,
>> +                               uint32_t nr_entries, uint32_t *err_leaf,
>> +                               uint32_t *err_subleaf)
>> +{
>> +    unsigned int i;
>> +    xen_cpuid_leaf_t data;
>> +    struct cpuid_leaf *l = (void *)&data.a;
> I'd find this cast a little less worrying if you used container_of(). But
> even then I dislike this well hidden assumption of similar layouts
> of struct cpuid_leaf and the latter parts of struct xen_cpuid_leaf.
>
> Also it looks as if this could be a pointer to const.

I've found a different way of doing this which actually compiles smaller
(contrary to expectation).

>> +    /*
>> +     * A well formed caller is expected pass an array with leaves in order,
> ... expected to pass ...

Fixed.

~Andrew

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness
  2019-01-07 11:19   ` Jan Beulich
@ 2019-02-25 11:56     ` Andrew Cooper
  2019-02-25 12:23       ` Jan Beulich
  0 siblings, 1 reply; 10+ messages in thread
From: Andrew Cooper @ 2019-02-25 11:56 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Sergey Dyasli, Xen-devel, Wei Liu, Roger Pau Monne


[-- Attachment #1.1: Type: text/plain, Size: 5184 bytes --]

On 07/01/2019 11:19, Jan Beulich wrote:
>>>> On 04.01.19 at 16:33, <andrew.cooper3@citrix.com> wrote:
>> The AFL harness currently notices that there are cases where we optimse the
>> serialised stream by omitting data beyond the various maximum leaves.
>>
>> Both sets of tests will be extended with further libx86 work.
>>
>> Fix the sorting of the CPUID_GUEST_NR_* constants, noticed while writing the
>> unit tests.
>>
>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>> ---
>> CC: Jan Beulich <JBeulich@suse.com>
>> CC: Wei Liu <wei.liu2@citrix.com>
>> CC: Roger Pau Monné <roger.pau@citrix.com>
>> CC: Sergey Dyasli <sergey.dyasli@citrix.com>
>> ---
>>  tools/fuzz/cpu-policy/.gitignore          |   1 +
>>  tools/fuzz/cpu-policy/Makefile            |  27 ++++
>>  tools/fuzz/cpu-policy/afl-policy-fuzzer.c | 117 ++++++++++++++
>>  tools/tests/Makefile                      |   1 +
>>  tools/tests/cpu-policy/.gitignore         |   1 +
> Did we somehow come to the conclusion that the central .gitignore
> at the root of the tree is not the way to go in the future?

We've already got several examples in the tree.

andrewcoop@andrewcoop:/local/xen.git$ git ls-files | grep gitignore
.gitignore
tools/tests/vhpet/.gitignore
xen/tools/kconfig/.gitignore
xen/tools/kconfig/lxdialog/.gitignore
xen/xsm/flask/.gitignore

As for the pro's of using split ignores, fewer collisions for backported
changes, and no forgetting to update the root .gitconfig when you move
directories.

>
>> --- /dev/null
>> +++ b/tools/tests/cpu-policy/test-cpu-policy.c
>> @@ -0,0 +1,247 @@
>> +#include <assert.h>
>> +#include <errno.h>
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +
>> +#include <xen-tools/libs.h>
>> +#include <xen/lib/x86/cpuid.h>
>> +#include <xen/lib/x86/msr.h>
>> +#include <xen/domctl.h>
>> +
>> +static void test_cpuid_serialise_success(void)
>> +{
>> +    static const struct test {
>> +        struct cpuid_policy p;
>> +        const char *name;
>> +        unsigned int nr_leaves;
>> +    } tests[] = {
>> +        {
>> +            .name = "empty policy",
>> +            .nr_leaves = 4,
>> +        },
>> +    };
>> +    unsigned int i;
>> +
>> +    printf("Testing CPUID serialise success:\n");
>> +
>> +    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
>> +    {
>> +        const struct test *t = &tests[i];
>> +        unsigned int nr = t->nr_leaves;
>> +        xen_cpuid_leaf_t *leaves = malloc(nr * sizeof(*leaves));
>> +        int rc;
>> +
>> +        if ( !leaves )
>> +            goto test_done;
> Shouldn't you leave some indication of the test not having got run?

I've swapped this for a hard error.  Its not going to fail in practice.

>
>> +static void test_cpuid_deserialise_failure(void)
>> +{
>> +    static const struct test {
>> +        const char *name;
>> +        xen_cpuid_leaf_t leaf;
>> +    } tests[] = {
>> +        {
>> +            .name = "incorrect basic subleaf",
>> +            .leaf = { .leaf = 0, .subleaf = 0 },
>> +        },
>> +        {
>> +            .name = "incorrect hv1 subleaf",
>> +            .leaf = { .leaf = 0x40000000, .subleaf = 0 },
>> +        },
>> +        {
>> +            .name = "incorrect hv2 subleaf",
>> +            .leaf = { .leaf = 0x40000100, .subleaf = 0 },
>> +        },
>> +        {
>> +            .name = "incorrect extd subleaf",
>> +            .leaf = { .leaf = 0x80000000, .subleaf = 0 },
>> +        },
>> +        {
>> +            .name = "OoB basic leaf",
>> +            .leaf = { .leaf = CPUID_GUEST_NR_BASIC },
>> +        },
>> +        {
>> +            .name = "OoB cache leaf",
>> +            .leaf = { .leaf = 0x4, .subleaf = CPUID_GUEST_NR_CACHE },
>> +        },
>> +        {
>> +            .name = "OoB feat leaf",
>> +            .leaf = { .leaf = 0x7, .subleaf = CPUID_GUEST_NR_FEAT },
>> +        },
>> +        {
>> +            .name = "OoB topo leaf",
>> +            .leaf = { .leaf = 0xb, .subleaf = CPUID_GUEST_NR_TOPO },
>> +        },
>> +        {
>> +            .name = "OoB xstate leaf",
>> +            .leaf = { .leaf = 0xd, .subleaf = CPUID_GUEST_NR_XSTATE },
>> +        },
>> +        {
>> +            .name = "OoB extd leaf",
>> +            .leaf = { .leaf = 0x80000000 | CPUID_GUEST_NR_EXTD },
>> +        },
>> +    };
>> +    unsigned int i;
>> +
>> +    printf("Testing CPUID deserialise failure:\n");
>> +
>> +    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
>> +    {
>> +        const struct test *t = &tests[i];
>> +        uint32_t err_leaf = ~0u, err_subleaf = ~0u;
>> +        int rc;
>> +
>> +        rc = x86_cpuid_copy_from_buffer(NULL, &t->leaf, 1,
>> +                                        &err_leaf, &err_subleaf);
>> +
>> +        if ( rc != -ERANGE )
>> +        {
>> +            printf("  Test %s, expected rc %d, got %d\n",
>> +                   t->name, -ERANGE, rc);
>> +            continue;
> Perhaps drop this? The subsequent test ought to apply regardless
> of error code.

The common case is no failures at all.  However, once something has gone
wrong, spewing cascade errors gets in the way, rather than being helpful.

~Andrew

[-- Attachment #1.2: Type: text/html, Size: 6856 bytes --]

[-- Attachment #2: Type: text/plain, Size: 157 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness
  2019-02-25 11:56     ` Andrew Cooper
@ 2019-02-25 12:23       ` Jan Beulich
  0 siblings, 0 replies; 10+ messages in thread
From: Jan Beulich @ 2019-02-25 12:23 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: Sergey Dyasli, Xen-devel, Wei Liu, Roger Pau Monne

>>> On 25.02.19 at 12:56, <andrew.cooper3@citrix.com> wrote:
> On 07/01/2019 11:19, Jan Beulich wrote:
>>>>> On 04.01.19 at 16:33, <andrew.cooper3@citrix.com> wrote:
>>> The AFL harness currently notices that there are cases where we optimse the
>>> serialised stream by omitting data beyond the various maximum leaves.
>>>
>>> Both sets of tests will be extended with further libx86 work.
>>>
>>> Fix the sorting of the CPUID_GUEST_NR_* constants, noticed while writing the
>>> unit tests.
>>>
>>> Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
>>> ---
>>> CC: Jan Beulich <JBeulich@suse.com>
>>> CC: Wei Liu <wei.liu2@citrix.com>
>>> CC: Roger Pau Monné <roger.pau@citrix.com>
>>> CC: Sergey Dyasli <sergey.dyasli@citrix.com>
>>> ---
>>>  tools/fuzz/cpu-policy/.gitignore          |   1 +
>>>  tools/fuzz/cpu-policy/Makefile            |  27 ++++
>>>  tools/fuzz/cpu-policy/afl-policy-fuzzer.c | 117 ++++++++++++++
>>>  tools/tests/Makefile                      |   1 +
>>>  tools/tests/cpu-policy/.gitignore         |   1 +
>> Did we somehow come to the conclusion that the central .gitignore
>> at the root of the tree is not the way to go in the future?
> 
> We've already got several examples in the tree.
> 
> andrewcoop@andrewcoop:/local/xen.git$ git ls-files | grep gitignore
> .gitignore
> tools/tests/vhpet/.gitignore
> xen/tools/kconfig/.gitignore
> xen/tools/kconfig/lxdialog/.gitignore
> xen/xsm/flask/.gitignore
> 
> As for the pro's of using split ignores, fewer collisions for backported
> changes, and no forgetting to update the root .gitconfig when you move
> directories.

Well, I certainly appreciate this, and my comment wasn't meant as
plain opposition. At the time I was simply wondering whether the few
instances we have already aren't more like an accident. And I didn't
recall any discussion towards moving away from the centralized model.

>>> +static void test_cpuid_deserialise_failure(void)
>>> +{
>>> +    static const struct test {
>>> +        const char *name;
>>> +        xen_cpuid_leaf_t leaf;
>>> +    } tests[] = {
>>> +        {
>>> +            .name = "incorrect basic subleaf",
>>> +            .leaf = { .leaf = 0, .subleaf = 0 },
>>> +        },
>>> +        {
>>> +            .name = "incorrect hv1 subleaf",
>>> +            .leaf = { .leaf = 0x40000000, .subleaf = 0 },
>>> +        },
>>> +        {
>>> +            .name = "incorrect hv2 subleaf",
>>> +            .leaf = { .leaf = 0x40000100, .subleaf = 0 },
>>> +        },
>>> +        {
>>> +            .name = "incorrect extd subleaf",
>>> +            .leaf = { .leaf = 0x80000000, .subleaf = 0 },
>>> +        },
>>> +        {
>>> +            .name = "OoB basic leaf",
>>> +            .leaf = { .leaf = CPUID_GUEST_NR_BASIC },
>>> +        },
>>> +        {
>>> +            .name = "OoB cache leaf",
>>> +            .leaf = { .leaf = 0x4, .subleaf = CPUID_GUEST_NR_CACHE },
>>> +        },
>>> +        {
>>> +            .name = "OoB feat leaf",
>>> +            .leaf = { .leaf = 0x7, .subleaf = CPUID_GUEST_NR_FEAT },
>>> +        },
>>> +        {
>>> +            .name = "OoB topo leaf",
>>> +            .leaf = { .leaf = 0xb, .subleaf = CPUID_GUEST_NR_TOPO },
>>> +        },
>>> +        {
>>> +            .name = "OoB xstate leaf",
>>> +            .leaf = { .leaf = 0xd, .subleaf = CPUID_GUEST_NR_XSTATE },
>>> +        },
>>> +        {
>>> +            .name = "OoB extd leaf",
>>> +            .leaf = { .leaf = 0x80000000 | CPUID_GUEST_NR_EXTD },
>>> +        },
>>> +    };
>>> +    unsigned int i;
>>> +
>>> +    printf("Testing CPUID deserialise failure:\n");
>>> +
>>> +    for ( i = 0; i < ARRAY_SIZE(tests); ++i )
>>> +    {
>>> +        const struct test *t = &tests[i];
>>> +        uint32_t err_leaf = ~0u, err_subleaf = ~0u;
>>> +        int rc;
>>> +
>>> +        rc = x86_cpuid_copy_from_buffer(NULL, &t->leaf, 1,
>>> +                                        &err_leaf, &err_subleaf);
>>> +
>>> +        if ( rc != -ERANGE )
>>> +        {
>>> +            printf("  Test %s, expected rc %d, got %d\n",
>>> +                   t->name, -ERANGE, rc);
>>> +            continue;
>> Perhaps drop this? The subsequent test ought to apply regardless
>> of error code.
> 
> The common case is no failures at all.  However, once something has gone
> wrong, spewing cascade errors gets in the way, rather than being helpful.

"Cascade failures" to me are ones where the latter is a result of
something earlier having gone wrong. Iirc this isn't the case with the
subsequent test(s) here, unless something's fundamentally wrong.
Seeing which particular case doesn't work plus all of the ones which
do can also be helpful. But as indicated by me using "perhaps" in the
original reply - I won't insist, as in the end something will need to be
done anyway until everything succeeds.

Jan


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-02-25 12:23 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-04 15:33 [PATCH 0/3] libx86: Remaining serialisation logic Andrew Cooper
2019-01-04 15:33 ` [PATCH 1/3] libx86: Introduce a helper to deserialise cpuid_policy objects Andrew Cooper
2019-01-07 10:52   ` Jan Beulich
2019-02-25 11:41     ` Andrew Cooper
2019-01-04 15:33 ` [PATCH 2/3] libx86: introduce a helper to deserialise msr_policy objects Andrew Cooper
2019-01-07 10:55   ` Jan Beulich
2019-01-04 15:33 ` [PATCH 3/3] tools/cpu-policy: Add unit tests and a fuzzing harness Andrew Cooper
2019-01-07 11:19   ` Jan Beulich
2019-02-25 11:56     ` Andrew Cooper
2019-02-25 12:23       ` Jan Beulich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.