From nobody Sat Apr 27 00:43:35 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org ARC-Seal: i=1; a=rsa-sha256; t=1559678003; cv=none; d=zoho.com; s=zohoarc; b=Uj6MH0Hrz7FeuBd+SHF/84+woWUcQ5FGXyTTI1FQryPK62N4/usrg30jJ4jqjmjCmG1B2qnuqZhIj81cMY46RKAVs2XUprYIXan1Y3Mv0J0EBpQlINGu8GBJFGM5tGm+9IO0YHEr5yB5yIzlh9LLB85RaSYXOjQ7tkw8nlKcGZg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1559678003; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=WnhX61T1YZ42t2ELn1iebvU3rwCjpA+z28CkeYc4L0g=; b=jum/+Tu8costjxDanYETZNxwBv3LR7NKwyM3ljlkNfyNmh0jY8owWJGQx5QW156F7TSU6Pn8St4jnJfHuicLTg/J6Y6dq401gIAeiMhAMk347sjj3ayonLf9WFiLTvga7ocVhcdnD7+7Fpgy8dhV9GYU1N2P6zVUk500fg7Mv8E= ARC-Authentication-Results: i=1; mx.zoho.com; spf=none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1559678003971450.6016359538703; Tue, 4 Jun 2019 12:53:23 -0700 (PDT) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hYFTT-0006kY-1b; Tue, 04 Jun 2019 19:51:59 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hYFTR-0006k4-Hf for xen-devel@lists.xenproject.org; Tue, 04 Jun 2019 19:51:57 +0000 Received: from esa5.hc3370-68.iphmx.com (unknown [216.71.155.168]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 33de37d8-8702-11e9-913b-1fb33d3e2428; Tue, 04 Jun 2019 19:51:54 +0000 (UTC) X-Inumbo-ID: 33de37d8-8702-11e9-913b-1fb33d3e2428 Authentication-Results: esa5.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=andrew.cooper3@citrix.com; spf=Pass smtp.mailfrom=Andrew.Cooper3@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Received-SPF: None (esa5.hc3370-68.iphmx.com: no sender authenticity information available from domain of andrew.cooper3@citrix.com) identity=pra; client-ip=23.29.105.83; receiver=esa5.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="andrew.cooper3@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa5.hc3370-68.iphmx.com: domain of Andrew.Cooper3@citrix.com designates 23.29.105.83 as permitted sender) identity=mailfrom; client-ip=23.29.105.83; receiver=esa5.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="Andrew.Cooper3@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:23.29.105.83 ip4:162.221.156.50 ~all" Received-SPF: None (esa5.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=23.29.105.83; receiver=esa5.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: ppFeynwwXUIqDKx5MmykrOh8vwINqtko7XvZqUXpenmhemuPZX1/Clv6UDC0dUMTLPf03UOc+P neqprpkfLRP9saMD4Oj8IUnkM1MnEkUfq8Y+lPJWcamKcBm2rgJbkeWWA50EE3gZS7ocdUMVfe CFiGQJin8ct/tFdfM20aLCyT6ncoKOIil5U/Jrl8UOaxBwTW3GQSrgN5kjmuKNOeRA2vJqfoJN 2IcFVvimO9vBZcAzwDFD9TNnkI8CL+aWfMhhHPy7snwbJY5ked/gO4/5971Q6ohGVz3DliSklC I/A= X-SBRS: 2.7 X-MesageID: 1292919 X-Ironport-Server: esa5.hc3370-68.iphmx.com X-Remote-IP: 23.29.105.83 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.60,550,1549947600"; d="scan'208";a="1292919" From: Andrew Cooper To: Xen-devel Date: Tue, 4 Jun 2019 20:51:24 +0100 Message-ID: <1559677885-10731-2-git-send-email-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1559677885-10731-1-git-send-email-andrew.cooper3@citrix.com> References: <1559677885-10731-1-git-send-email-andrew.cooper3@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH 1/2] libx86: Helper for clearing out-of-range CPUID leaves X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Andrew Cooper , Sergey Dyasli , Wei Liu , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" When merging a levelled policy, stale out-of-range leaves may remain. Introduce a helper to clear them, and test a number of the subtle corner cases. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- CC: Jan Beulich CC: Wei Liu CC: Roger Pau Monn=C3=A9 CC: Sergey Dyasli --- tools/tests/cpu-policy/test-cpu-policy.c | 161 +++++++++++++++++++++++++++= +++- xen/include/xen/lib/x86/cpuid.h | 11 +++ xen/lib/x86/cpuid.c | 59 +++++++++++ xen/lib/x86/private.h | 1 + 4 files changed, 230 insertions(+), 2 deletions(-) diff --git a/tools/tests/cpu-policy/test-cpu-policy.c b/tools/tests/cpu-pol= icy/test-cpu-policy.c index fd96c0b..ca2d8d3 100644 --- a/tools/tests/cpu-policy/test-cpu-policy.c +++ b/tools/tests/cpu-policy/test-cpu-policy.c @@ -20,6 +20,17 @@ static unsigned int nr_failures; printf(fmt, ##__VA_ARGS__); \ }) =20 +#define memdup(ptr) \ +({ \ + typeof(*(ptr)) *p_ =3D (ptr); \ + void *n_ =3D malloc(sizeof(*p_)); \ + \ + if ( !n_ ) \ + err(1, "%s malloc failure", __func__); \ + \ + memcpy(n_, p_, sizeof(*p_)); \ +}) + static void test_vendor_identification(void) { static const struct test { @@ -345,6 +356,151 @@ static void test_msr_deserialise_failure(void) } } =20 +static void test_cpuid_out_of_range_clearing(void) +{ + static const struct test { + const char *name; + unsigned int nr_markers; + struct cpuid_policy p; + } tests[] =3D { + { + .name =3D "basic", + .nr_markers =3D 1, + .p =3D { + /* Retains marker in leaf 0. Clears others. */ + .basic.max_leaf =3D 0, + .basic.vendor_ebx =3D 0xc2, + + .basic.raw_fms =3D 0xc2, + .cache.raw[0].a =3D 0xc2, + .feat.raw[0].a =3D 0xc2, + .topo.raw[0].a =3D 0xc2, + .xstate.raw[0].a =3D 0xc2, + .xstate.raw[1].a =3D 0xc2, + }, + }, + { + .name =3D "cache", + .nr_markers =3D 1, + .p =3D { + /* Retains marker in subleaf 0. Clears others. */ + .basic.max_leaf =3D 4, + .cache.raw[0].b =3D 0xc2, + + .cache.raw[1].b =3D 0xc2, + .feat.raw[0].a =3D 0xc2, + .topo.raw[0].a =3D 0xc2, + .xstate.raw[0].a =3D 0xc2, + .xstate.raw[1].a =3D 0xc2, + }, + }, + { + .name =3D "feat", + .nr_markers =3D 1, + .p =3D { + /* Retains marker in subleaf 0. Clears others. */ + .basic.max_leaf =3D 7, + .feat.raw[0].b =3D 0xc2, + + .feat.raw[1].b =3D 0xc2, + .topo.raw[0].a =3D 0xc2, + .xstate.raw[0].a =3D 0xc2, + .xstate.raw[1].a =3D 0xc2, + }, + }, + { + .name =3D "topo", + .nr_markers =3D 1, + .p =3D { + /* Retains marker in subleaf 0. Clears others. */ + .basic.max_leaf =3D 0xb, + .topo.raw[0].b =3D 0xc2, + + .topo.raw[1].b =3D 0xc2, + .xstate.raw[0].a =3D 0xc2, + .xstate.raw[1].a =3D 0xc2, + }, + }, + { + .name =3D "xstate x87", + .nr_markers =3D 2, + .p =3D { + /* First two subleaves always valid. Others cleared. */ + .basic.max_leaf =3D 0xd, + .xstate.raw[0].a =3D 1, + .xstate.raw[0].b =3D 0xc2, + .xstate.raw[1].b =3D 0xc2, + + .xstate.raw[2].b =3D 0xc2, + .xstate.raw[3].b =3D 0xc2, + }, + }, + { + .name =3D "xstate sse", + .nr_markers =3D 2, + .p =3D { + /* First two subleaves always valid. Others cleared. */ + .basic.max_leaf =3D 0xd, + .xstate.raw[0].a =3D 2, + .xstate.raw[0].b =3D 0xc2, + .xstate.raw[1].b =3D 0xc2, + + .xstate.raw[2].b =3D 0xc2, + .xstate.raw[3].b =3D 0xc2, + }, + }, + { + .name =3D "xstate avx", + .nr_markers =3D 3, + .p =3D { + /* Third subleaf also valid. Others cleared. */ + .basic.max_leaf =3D 0xd, + .xstate.raw[0].a =3D 7, + .xstate.raw[0].b =3D 0xc2, + .xstate.raw[1].b =3D 0xc2, + .xstate.raw[2].b =3D 0xc2, + + .xstate.raw[3].b =3D 0xc2, + }, + }, + { + .name =3D "extd", + .nr_markers =3D 1, + .p =3D { + /* Retains marker in leaf 0. Clears others. */ + .extd.max_leaf =3D 0, + .extd.vendor_ebx =3D 0xc2, + + .extd.raw_fms =3D 0xc2, + }, + }, + }; + + printf("Testing CPUID out-of-range clearing:\n"); + + for ( size_t i =3D 0; i < ARRAY_SIZE(tests); ++i ) + { + const struct test *t =3D &tests[i]; + struct cpuid_policy *p =3D memdup(&t->p); + void *ptr; + unsigned int nr_markers; + + x86_cpuid_policy_clear_out_of_range_leaves(p); + + /* Count the number of 0xc2's still remaining. */ + for ( ptr =3D p, nr_markers =3D 0; + (ptr =3D memchr(ptr, 0xc2, (void *)p + sizeof(*p) - ptr)); + ptr++, nr_markers++ ) + ; + + if ( nr_markers !=3D t->nr_markers ) + fail(" Test %s fail - expected %u markers, got %u\n", + t->name, t->nr_markers, nr_markers); + + free(p); + } +} + int main(int argc, char **argv) { printf("CPU Policy unit tests\n"); @@ -352,9 +508,10 @@ int main(int argc, char **argv) test_vendor_identification(); =20 test_cpuid_serialise_success(); - test_msr_serialise_success(); - test_cpuid_deserialise_failure(); + test_cpuid_out_of_range_clearing(); + + test_msr_serialise_success(); test_msr_deserialise_failure(); =20 if ( nr_failures ) diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpui= d.h index ed7d7b4..2618598 100644 --- a/xen/include/xen/lib/x86/cpuid.h +++ b/xen/include/xen/lib/x86/cpuid.h @@ -331,6 +331,17 @@ const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t fe= ature); */ void x86_cpuid_policy_fill_native(struct cpuid_policy *p); =20 +/** + * Clear leaf data beyond the policies max leaf/subleaf settings. + * + * Policy serialisation purposefully omits out-of-range leaves, because th= ere + * are a large number of them due to vendor differences. However, when + * constructing new policies (e.g. levelling down), it is possible to end = up + * with out-of-range leaves with stale content in them. This helper clears + * them. + */ +void x86_cpuid_policy_clear_out_of_range_leaves(struct cpuid_policy *p); + #ifdef __XEN__ #include typedef XEN_GUEST_HANDLE_64(xen_cpuid_leaf_t) cpuid_leaf_buffer_t; diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c index a82cdb2..0f99fcb 100644 --- a/xen/lib/x86/cpuid.c +++ b/xen/lib/x86/cpuid.c @@ -2,6 +2,13 @@ =20 #include =20 +static void zero_leaves(struct cpuid_leaf *l, + unsigned int first, unsigned int last) +{ + if ( first <=3D last ) + memset(&l[first], 0, sizeof(*l) * (last - first + 1)); +} + unsigned int x86_cpuid_lookup_vendor(uint32_t ebx, uint32_t ecx, uint32_t = edx) { switch ( ebx ) @@ -163,6 +170,58 @@ void x86_cpuid_policy_fill_native(struct cpuid_policy = *p) recalculate_synth(p); } =20 +void x86_cpuid_policy_clear_out_of_range_leaves(struct cpuid_policy *p) +{ + unsigned int i; + + zero_leaves(p->basic.raw, p->basic.max_leaf + 1, + ARRAY_SIZE(p->basic.raw) - 1); + + if ( p->basic.max_leaf < 4 ) + memset(p->cache.raw, 0, sizeof(p->cache.raw)); + else + { + for ( i =3D 0; (i < ARRAY_SIZE(p->cache.raw) && + p->cache.subleaf[i].type); ++i ) + ; + + zero_leaves(p->cache.raw, i + 1, + ARRAY_SIZE(p->cache.raw) - 1); + } + + if ( p->basic.max_leaf < 7 ) + memset(p->feat.raw, 0, sizeof(p->feat.raw)); + else + zero_leaves(p->feat.raw, p->feat.max_subleaf + 1, + ARRAY_SIZE(p->feat.raw) - 1); + + if ( p->basic.max_leaf < 0xb ) + memset(p->topo.raw, 0, sizeof(p->topo.raw)); + else + { + for ( i =3D 0; (i < ARRAY_SIZE(p->topo.raw) && + p->topo.subleaf[i].type); ++i ) + ; + + zero_leaves(p->topo.raw, i + 1, + ARRAY_SIZE(p->topo.raw) - 1); + } + + if ( p->basic.max_leaf < 0xd || !cpuid_policy_xstates(p) ) + memset(p->xstate.raw, 0, sizeof(p->xstate.raw)); + else + { + /* First two leaves always valid. Rest depend on xstates. */ + i =3D max(2, 64 - __builtin_clzll(cpuid_policy_xstates(p))); + + zero_leaves(p->xstate.raw, i, + ARRAY_SIZE(p->xstate.raw) - 1); + } + + zero_leaves(p->extd.raw, (p->extd.max_leaf & 0xffff) + 1, + ARRAY_SIZE(p->extd.raw) - 1); +} + const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t feature) { static const uint32_t deep_features[] =3D INIT_DEEP_FEATURES; diff --git a/xen/lib/x86/private.h b/xen/lib/x86/private.h index f5b195e..b793181 100644 --- a/xen/lib/x86/private.h +++ b/xen/lib/x86/private.h @@ -21,6 +21,7 @@ #include #include #include +#include =20 #include #include --=20 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel From nobody Sat Apr 27 00:43:35 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org ARC-Seal: i=1; a=rsa-sha256; t=1559677990; cv=none; d=zoho.com; s=zohoarc; b=m8PjlWFiJX6CowM5w0FlbDUHpfH25ocTL8aM+ZfES05vHBokd79sSxNKRJJTz8MQ5nxFHcp0TEgwbeNcrWD3A6FfUyFOzm4BnNYP9CQU+8hWyI+vhzTjHZpv5aL7dD7RuWbxA7iDbIOR+5hKxk+7be5eVm6JvUxIzSYE46XRalU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1559677990; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=BFcqEdf5ZglSCikyEUhA+HA8BtrTmjq1eGKlwDucBAo=; b=A3+DZEj637lvj48Cq9mMAYy+UyWnagAlv6sUVBzuU0Spab55HtNdzwCbp7PxOUY9BUmy0clBSeagzaKTrs6VDBYRWWJvXU35FZ4iwdlHCnkp0nJDFQQvWnhyW5K3TL0nqtpuWbr+ktFCsU6c2xkg4mRPNhFYkyOjJdZq5vS+4Yw= ARC-Authentication-Results: i=1; mx.zoho.com; spf=none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1559677990790432.40121721996627; Tue, 4 Jun 2019 12:53:10 -0700 (PDT) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hYFTQ-0006jo-Nm; Tue, 04 Jun 2019 19:51:56 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1hYFTP-0006jd-7L for xen-devel@lists.xenproject.org; Tue, 04 Jun 2019 19:51:55 +0000 Received: from esa5.hc3370-68.iphmx.com (unknown [216.71.155.168]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 32481a38-8702-11e9-8f52-c35970b4a334; Tue, 04 Jun 2019 19:51:52 +0000 (UTC) X-Inumbo-ID: 32481a38-8702-11e9-8f52-c35970b4a334 Authentication-Results: esa5.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none; spf=None smtp.pra=andrew.cooper3@citrix.com; spf=Pass smtp.mailfrom=Andrew.Cooper3@citrix.com; spf=None smtp.helo=postmaster@mail.citrix.com Received-SPF: none (zoho.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Received-SPF: None (esa5.hc3370-68.iphmx.com: no sender authenticity information available from domain of andrew.cooper3@citrix.com) identity=pra; client-ip=23.29.105.83; receiver=esa5.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="andrew.cooper3@citrix.com"; x-conformance=sidf_compatible Received-SPF: Pass (esa5.hc3370-68.iphmx.com: domain of Andrew.Cooper3@citrix.com designates 23.29.105.83 as permitted sender) identity=mailfrom; client-ip=23.29.105.83; receiver=esa5.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="Andrew.Cooper3@citrix.com"; x-conformance=sidf_compatible; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:209.167.231.154 ip4:178.63.86.133 ip4:195.66.111.40/30 ip4:85.115.9.32/28 ip4:199.102.83.4 ip4:192.28.146.160 ip4:192.28.146.107 ip4:216.52.6.88 ip4:216.52.6.188 ip4:23.29.105.83 ip4:162.221.156.50 ~all" Received-SPF: None (esa5.hc3370-68.iphmx.com: no sender authenticity information available from domain of postmaster@mail.citrix.com) identity=helo; client-ip=23.29.105.83; receiver=esa5.hc3370-68.iphmx.com; envelope-from="Andrew.Cooper3@citrix.com"; x-sender="postmaster@mail.citrix.com"; x-conformance=sidf_compatible IronPort-SDR: lieeOL98o9zQmSIBOyIrWPGW9fHf9AVjBGU+K34XjVdU6rzqgTN8nNjPrlRVTA9BKwGGaqMcVF OU8dEQA4/1PK9vC1z0LK5zdpQNlf6M+XjHFqFzzyiLx6QAyy5GT0KzpNCnmVs+RVh6AlfHZX2W iVehHIBwgqkn9kpCr8d5DZ16F+01kdqiGtG3MxCpZKoc8ASj6W4f+tCPvUCxOJ6p6DNWYuWpzR mLfskRje/cNzRD05yawAvw3dlA0arokKhstrJ9MtbNF4+jI5PX9cjv51DZWI+bn58uTm0+IW85 eeU= X-SBRS: 2.7 X-MesageID: 1292917 X-Ironport-Server: esa5.hc3370-68.iphmx.com X-Remote-IP: 23.29.105.83 X-Policy: $RELAYED X-IronPort-AV: E=Sophos;i="5.60,550,1549947600"; d="scan'208";a="1292917" From: Andrew Cooper To: Xen-devel Date: Tue, 4 Jun 2019 20:51:25 +0100 Message-ID: <1559677885-10731-3-git-send-email-andrew.cooper3@citrix.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1559677885-10731-1-git-send-email-andrew.cooper3@citrix.com> References: <1559677885-10731-1-git-send-email-andrew.cooper3@citrix.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH 2/2] tools/fuzz: Add a cpu-policy fuzzing harness X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Andrew Cooper , Sergey Dyasli , Wei Liu , Jan Beulich , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" There is now enough complexity that a fuzzing harness is a good idea, and enough supporting logic to implement one which AFL seems happy with. Take the existing recalculate_synth() helper and export it as x86_cpuid_policy_recalc_synth(), as it is needed by the fuzzing harness. Signed-off-by: Andrew Cooper Acked-by: Jan Beulich --- CC: Jan Beulich CC: Wei Liu CC: Roger Pau Monn=C3=A9 CC: Sergey Dyasli --- tools/fuzz/cpu-policy/.gitignore | 1 + tools/fuzz/cpu-policy/Makefile | 28 +++++ tools/fuzz/cpu-policy/afl-policy-fuzzer.c | 187 ++++++++++++++++++++++++++= ++++ xen/include/xen/lib/x86/cpuid.h | 5 + xen/lib/x86/cpuid.c | 7 +- 5 files changed, 224 insertions(+), 4 deletions(-) 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 diff --git a/tools/fuzz/cpu-policy/.gitignore b/tools/fuzz/cpu-policy/.giti= gnore 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..41a2230 --- /dev/null +++ b/tools/fuzz/cpu-policy/Makefile @@ -0,0 +1,28 @@ +XEN_ROOT =3D $(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 +=3D -Werror $(CFLAGS_xeninclude) -D__XEN_TOOLS__ +CFLAGS +=3D $(APPEND_CFLAGS) -Og + +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-pol= icy/afl-policy-fuzzer.c new file mode 100644 index 0000000..bc0cecd --- /dev/null +++ b/tools/fuzz/cpu-policy/afl-policy-fuzzer.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +static bool debug; + +#define EMPTY_LEAF ((struct cpuid_leaf){}) + +static void check_cpuid(struct cpuid_policy *cp) +{ + struct cpuid_policy new =3D {}; + size_t data_end; + xen_cpuid_leaf_t *leaves =3D malloc(CPUID_MAX_SERIALISED_LEAVES * + sizeof(xen_cpuid_leaf_t)); + unsigned int nr =3D CPUID_MAX_SERIALISED_LEAVES; + int rc; + + if ( !leaves ) + return; + + /* + * Clean unusable leaves. These can't be accessed via architectural + * means, but may be filled by the fread() across the entire structure. + * Also zero the trailing padding (if any). + */ + cp->basic.raw[4] =3D EMPTY_LEAF; + cp->basic.raw[7] =3D EMPTY_LEAF; + cp->basic.raw[0xb] =3D EMPTY_LEAF; + cp->basic.raw[0xd] =3D EMPTY_LEAF; + data_end =3D offsetof(typeof(*cp), x86_vendor) + sizeof(cp->x86_vendor= ); + if ( data_end < sizeof(*cp) ) + memset((void *)cp + data_end, 0, sizeof(*cp) - data_end); + + /* + * Fix up the data in the source policy which isn't expected to survive + * serialisation. + */ + x86_cpuid_policy_clear_out_of_range_leaves(cp); + x86_cpuid_policy_recalc_synth(cp); + + /* Serialise... */ + rc =3D x86_cpuid_copy_to_buffer(cp, leaves, &nr); + assert(rc =3D=3D 0); + assert(nr <=3D CPUID_MAX_SERIALISED_LEAVES); + + /* ... and deserialise. */ + rc =3D x86_cpuid_copy_from_buffer(&new, leaves, nr, NULL, NULL); + assert(rc =3D=3D 0); + + /* The result after serialisation/deserialisaion should be identical..= . */ + if ( memcmp(cp, &new, sizeof(*cp)) !=3D 0 ) + { + if ( debug ) + { + unsigned char *l =3D (void *)cp, *r =3D (void *)&new; + + for ( size_t i =3D 0; i < sizeof(*cp); ++i ) + if ( l[i] !=3D r[i] ) + printf("Differ at offset %zu: %u vs %u\n", + i, l[i], r[i]); + } + + abort(); + } + + free(leaves); +} + +static void check_msr(struct msr_policy *mp) +{ + struct msr_policy new =3D {}; + xen_msr_entry_t *msrs =3D malloc(MSR_MAX_SERIALISED_ENTRIES * + sizeof(xen_msr_entry_t)); + unsigned int nr =3D MSR_MAX_SERIALISED_ENTRIES; + int rc; + + if ( !msrs ) + return; + + rc =3D x86_msr_copy_to_buffer(mp, msrs, &nr); + assert(rc =3D=3D 0); + assert(nr <=3D MSR_MAX_SERIALISED_ENTRIES); + + rc =3D x86_msr_copy_from_buffer(&new, msrs, nr, NULL); + assert(rc =3D=3D 0); + assert(memcmp(mp, &new, sizeof(*mp)) =3D=3D 0); + + free(msrs); +} + +int main(int argc, char **argv) +{ + FILE *fp =3D NULL; + + setbuf(stdin, NULL); + setbuf(stdout, NULL); + + while ( true ) + { + static const struct option opts[] =3D { + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + {}, + }; + int c =3D getopt_long(argc, argv, "hd", opts, NULL); + + if ( c =3D=3D -1 ) + break; + + switch ( c ) + { + case 'd': + printf("Enabling debug\n"); + debug =3D true; + break; + + default: + printf("Bad option %d (%c)\n", c, c); + exit(-1); + break; + } + } + + if ( optind =3D=3D argc ) /* No positional parameters. Use stdin. */ + { + printf("Using stdin\n"); + fp =3D stdin; + } + +#ifdef __AFL_HAVE_MANUAL_CONTROL + __AFL_INIT(); + while ( __AFL_LOOP(1000) ) +#endif + { + struct cpuid_policy *cp =3D NULL; + struct msr_policy *mp =3D NULL; + + if ( fp !=3D stdin ) + { + printf("Opening file '%s'\n", argv[optind]); + fp =3D fopen(argv[optind], "rb"); + + if ( !fp ) + { + perror("fopen"); + exit(-1); + } + } + + cp =3D calloc(1, sizeof(*cp)); + mp =3D 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); + free(mp); + + if ( fp !=3D stdin ) + { + fclose(fp); + fp =3D NULL; + } + } + + return 0; +} diff --git a/xen/include/xen/lib/x86/cpuid.h b/xen/include/xen/lib/x86/cpui= d.h index 2618598..df5946b 100644 --- a/xen/include/xen/lib/x86/cpuid.h +++ b/xen/include/xen/lib/x86/cpuid.h @@ -323,6 +323,11 @@ static inline uint64_t cpuid_policy_xstates(const stru= ct cpuid_policy *p) const uint32_t *x86_cpuid_lookup_deep_deps(uint32_t feature); =20 /** + * Recalculate the content in a CPUID policy which is derived from raw dat= a. + */ +void x86_cpuid_policy_recalc_synth(struct cpuid_policy *p); + +/** * Fill a CPUID policy using the native CPUID instruction. * * No sanitisation is performed, but synthesised values are calculated. diff --git a/xen/lib/x86/cpuid.c b/xen/lib/x86/cpuid.c index 0f99fcb..2404fa3 100644 --- a/xen/lib/x86/cpuid.c +++ b/xen/lib/x86/cpuid.c @@ -53,8 +53,7 @@ const char *x86_cpuid_vendor_to_str(unsigned int vendor) } } =20 -/* Recalculate the content in a CPUID policy which is derived from raw dat= a. */ -static void recalculate_synth(struct cpuid_policy *p) +void x86_cpuid_policy_recalc_synth(struct cpuid_policy *p) { p->x86_vendor =3D x86_cpuid_lookup_vendor( p->basic.vendor_ebx, p->basic.vendor_ecx, p->basic.vendor_edx); @@ -167,7 +166,7 @@ void x86_cpuid_policy_fill_native(struct cpuid_policy *= p) p->extd.max_leaf + 1 - 0x80000000); ++i ) cpuid_leaf(0x80000000 + i, &p->extd.raw[i]); =20 - recalculate_synth(p); + x86_cpuid_policy_recalc_synth(p); } =20 void x86_cpuid_policy_clear_out_of_range_leaves(struct cpuid_policy *p) @@ -461,7 +460,7 @@ int x86_cpuid_copy_from_buffer(struct cpuid_policy *p, } } =20 - recalculate_synth(p); + x86_cpuid_policy_recalc_synth(p); =20 return 0; =20 --=20 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel