KVM: arm64: Add build-time sanity checks for flags
authorMarc Zyngier <maz@kernel.org>
Sat, 28 May 2022 11:38:26 +0000 (12:38 +0100)
committerMarc Zyngier <maz@kernel.org>
Wed, 29 Jun 2022 09:23:41 +0000 (10:23 +0100)
Flags are great, but flags can also be dangerous: it is easy
to encode a flag that is bigger than its container (unless the
container is a u64), and it is easy to construct a flag value
that doesn't fit in the mask that is associated with it.

Add a couple of build-time sanity checks that ensure we catch
these two cases.

Reviewed-by: Fuad Tabba <tabba@google.com>
Reviewed-by: Reiji Watanabe <reijiw@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_host.h

index ffbeb5f..6a37018 100644 (file)
@@ -433,8 +433,20 @@ struct kvm_vcpu_arch {
 #define __unpack_flag(_set, _f, _m)    _f
 #define unpack_vcpu_flag(...)          __unpack_flag(__VA_ARGS__)
 
+#define __build_check_flag(v, flagset, f, m)                   \
+       do {                                                    \
+               typeof(v->arch.flagset) *_fset;                 \
+                                                               \
+               /* Check that the flags fit in the mask */      \
+               BUILD_BUG_ON(HWEIGHT(m) != HWEIGHT((f) | (m))); \
+               /* Check that the flags fit in the type */      \
+               BUILD_BUG_ON((sizeof(*_fset) * 8) <= __fls(m)); \
+       } while (0)
+
 #define __vcpu_get_flag(v, flagset, f, m)                      \
        ({                                                      \
+               __build_check_flag(v, flagset, f, m);           \
+                                                               \
                v->arch.flagset & (m);                          \
        })
 
@@ -442,6 +454,8 @@ struct kvm_vcpu_arch {
        do {                                                    \
                typeof(v->arch.flagset) *fset;                  \
                                                                \
+               __build_check_flag(v, flagset, f, m);           \
+                                                               \
                fset = &v->arch.flagset;                        \
                if (HWEIGHT(m) > 1)                             \
                        *fset &= ~(m);                          \
@@ -452,6 +466,8 @@ struct kvm_vcpu_arch {
        do {                                                    \
                typeof(v->arch.flagset) *fset;                  \
                                                                \
+               __build_check_flag(v, flagset, f, m);           \
+                                                               \
                fset = &v->arch.flagset;                        \
                *fset &= ~(m);                                  \
        } while (0)