lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 13 Jun 2022 14:38:21 +0000
From:   Sean Christopherson <seanjc@...gle.com>
To:     Andrew Jones <drjones@...hat.com>
Cc:     Paolo Bonzini <pbonzini@...hat.com>, kvm@...r.kernel.org,
        Vitaly Kuznetsov <vkuznets@...hat.com>,
        David Matlack <dmatlack@...gle.com>,
        Ben Gardon <bgardon@...gle.com>,
        Oliver Upton <oupton@...gle.com>, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2 144/144] KVM: selftests: Sanity check input to
 ioctls() at build time

On Fri, Jun 10, 2022, Andrew Jones wrote:
> On Fri, Jun 03, 2022 at 12:43:31AM +0000, Sean Christopherson wrote:
> > Add a static assert to the KVM/VM/vCPU ioctl() helpers to verify that the
> > size of the argument provided matches the expected size of the IOCTL.
> > Because ioctl() ultimately takes a "void *", it's all too easy to pass in
> > garbage and not detect the error until runtime.  E.g. while working on a
> > CPUID rework, selftests happily compiled when vcpu_set_cpuid()
> > unintentionally passed the cpuid() function as the parameter to ioctl()
> > (a local "cpuid" parameter was removed, but its use was not replaced with
> > "vcpu->cpuid" as intended).
> > 
> > Tweak a variety of benign issues that aren't compatible with the sanity
> > check, e.g. passing a non-pointer for ioctls().
> > 
> > Note, static_assert() requires a string on older versions of GCC.  Feed
> > it an empty string to make the compiler happy.
> > 
> > Signed-off-by: Sean Christopherson <seanjc@...gle.com>
> > ---
> >  .../selftests/kvm/include/kvm_util_base.h     | 61 +++++++++++++------
> >  .../selftests/kvm/lib/aarch64/processor.c     |  2 +-
> >  tools/testing/selftests/kvm/lib/guest_modes.c |  2 +-
> >  tools/testing/selftests/kvm/lib/kvm_util.c    | 29 +--------
> >  tools/testing/selftests/kvm/s390x/resets.c    |  6 +-
> >  .../selftests/kvm/x86_64/mmio_warning_test.c  |  2 +-
> >  .../kvm/x86_64/pmu_event_filter_test.c        |  2 +-
> >  .../selftests/kvm/x86_64/xen_shinfo_test.c    |  6 +-
> >  8 files changed, 56 insertions(+), 54 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h
> > index 04ddab322b6b..0eaf0c9b7612 100644
> > --- a/tools/testing/selftests/kvm/include/kvm_util_base.h
> > +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h
> > @@ -180,29 +180,56 @@ static inline bool kvm_has_cap(long cap)
> >  #define __KVM_IOCTL_ERROR(_name, _ret)	__KVM_SYSCALL_ERROR(_name, _ret)
> >  #define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret)
> >  
> > -#define __kvm_ioctl(kvm_fd, cmd, arg) \
> > -	ioctl(kvm_fd, cmd, arg)
> > +#define kvm_do_ioctl(fd, cmd, arg)						\
> > +({										\
> > +	static_assert(!_IOC_SIZE(cmd) || sizeof(*arg) == _IOC_SIZE(cmd), "");	\
> > +	ioctl(fd, cmd, arg);							\
> > +})
> >  
> > -static inline void _kvm_ioctl(int kvm_fd, unsigned long cmd, const char *name,
> > -			      void *arg)
> > -{
> > -	int ret = __kvm_ioctl(kvm_fd, cmd, arg);
> > +#define __kvm_ioctl(kvm_fd, cmd, arg)						\
> > +	kvm_do_ioctl(kvm_fd, cmd, arg)
> >  
> > -	TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret));
> > -}
> > +
> 
> While we've gained the static asserts we've also lost the type checking
> that the inline functions provided. Is there anyway we can bring them back
> with more macro tricks?

Gah, I overthought this.  It doesn't even require macros, just a dummy helper.
I wasn't trying to use static_assert() to enforce the type check, which is how I
ended up with the sizeof() ugliness (not the one above).  But it's far easier to
let the compiler do the checking.

I'll send a small fixup series to address this and your other feedback.

static __always_inline void static_assert_is_vm(struct kvm_vm *vm) { }

#define __vm_ioctl(vm, cmd, arg)				\
({								\
	static_assert_is_vm(vm);				\
	kvm_do_ioctl((vm)->fd, cmd, arg);			\
})

static __always_inline void static_assert_is_vcpu(struct kvm_vcpu *vcpu) { }

#define __vcpu_ioctl(vcpu, cmd, arg)				\
({								\
	static_assert_is_vcpu(vcpu);				\
	kvm_do_ioctl((vcpu)->fd, cmd, arg);			\
})


In file included from include/kvm_util.h:10,
                 from lib/x86_64/processor.c:9:
lib/x86_64/processor.c: In function ‘_vcpu_set_msr’:
lib/x86_64/processor.c:831:33: error: passing argument 1 of ‘static_assert_is_vcpu’ from incompatible pointer type [-Werror=incompatible-pointer-types]
  831 |         return __vcpu_ioctl(vcpu->vm, KVM_SET_MSRS, &buffer.header);
      |                             ~~~~^~~~
      |                                 |
      |                                 struct kvm_vm *
include/kvm_util_base.h:232:31: note: in definition of macro ‘__vcpu_ioctl’
  232 |         static_assert_is_vcpu(vcpu);                            \
      |                               ^~~~
include/kvm_util_base.h:225:68: note: expected ‘struct kvm_vcpu *’ but argument is of type ‘struct kvm_vm *’
  225 | static __always_inline void static_assert_is_vcpu(struct kvm_vcpu *vcpu)
      |                                                   ~~~~~~~~~~~~~~~~~^~~~
cc1: all warnings being treated as errors

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ