@@ -258,6 +258,17 @@ alternative_endif
ldr \dst, [\dst, \tmp]
.endm
+ /*
+ * @sym: The name of the per-cpu variable
+ * @reg: value to store
+ * @tmp1: scratch register
+ * @tmp2: scratch register
+ */
+ .macro str_this_cpu sym, reg, tmp1, tmp2
+ adr_this_cpu \tmp1, \sym, \tmp2
+ str \reg, [\tmp1]
+ .endm
+
/*
* vma_vm_mm - get mm pointer from vma pointer (vma->vm_mm)
*/
new file mode 100644
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2020 Google LLC
+ * Author: George Popescu <georgepope@google.com>
+ */
+
+#include <linux/percpu-defs.h>
+
+
+#define KVM_DEBUG_BUFFER_SIZE 1000
+
+#ifdef __KVM_NVHE_HYPERVISOR__
+#define DEFINE_KVM_DEBUG_BUFFER(type_name, buffer_name, write_ind, size)\
+ DEFINE_PER_CPU(type_name, buffer_name)[size]; \
+ DEFINE_PER_CPU(unsigned long, write_ind) = 0;
+
+#define DECLARE_KVM_DEBUG_BUFFER(type_name, buffer_name, write_ind, size)\
+ DECLARE_PER_CPU(type_name, buffer_name)[size]; \
+ DECLARE_PER_CPU(unsigned long, write_ind);
+#else
+#define DECLARE_KVM_DEBUG_BUFFER(type_name, buffer_name, write_ind, size)\
+ DECLARE_KVM_NVHE_PER_CPU(type_name, buffer_name)[size]; \
+ DECLARE_KVM_NVHE_PER_CPU(unsigned long, write_ind);
+#endif //__KVM_NVHE_HYPERVISOR__
+
+#ifdef __ASSEMBLY__
+#include <asm/assembler.h>
+
+.macro clear_buffer tmp1, tmp2, tmp3
+ mov \tmp1, 0
+#ifdef CONFIG_UBSAN
+ str_this_cpu kvm_ubsan_buff_wr_ind, \tmp1, \tmp2, \tmp3
+#endif //CONFIG_UBSAN
+.endm
+
+#endif
\ No newline at end of file
@@ -569,6 +569,12 @@ int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
void kvm_arm_halt_guest(struct kvm *kvm);
void kvm_arm_resume_guest(struct kvm *kvm);
+
+#ifdef CONFIG_UBSAN
+extern void __kvm_check_ubsan_buffer(void);
+#else
+static inline void __kvm_check_ubsan_buffer(void) {}
+#endif /* CONFIG_UBSAN */
#define kvm_call_hyp_nvhe(f, ...) \
({ \
struct arm_smccc_res res; \
@@ -576,7 +582,7 @@ void kvm_arm_resume_guest(struct kvm *kvm);
arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f), \
##__VA_ARGS__, &res); \
WARN_ON(res.a0 != SMCCC_RET_SUCCESS); \
- \
+ __kvm_check_ubsan_buffer(); \
res.a1; \
})
new file mode 100644
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright 2020 Google LLC
+ * Author: George Popescu <georgepope@google.com>
+ */
+
+#include <ubsan.h>
+
+#define UBSAN_MAX_TYPE 6
+#define KVM_UBSAN_BUFFER_SIZE 1000
+
+struct kvm_ubsan_info {
+ int type;
+};
@@ -4,6 +4,7 @@
#
ccflags-y += -I $(srctree)/$(src)
+CFLAGS_kvm_ubsan_buffer.o += -I $(srctree)/lib/
KVM=../../../virt/kvm
@@ -24,4 +25,5 @@ kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
vgic/vgic-mmio-v3.o vgic/vgic-kvm-device.o \
vgic/vgic-its.o vgic/vgic-debug.o
+kvm-$(CONFIG_UBSAN) += kvm_ubsan_buffer.o
kvm-$(CONFIG_KVM_ARM_PMU) += pmu-emul.o
@@ -1780,6 +1780,15 @@ static int init_hyp_mode(void)
goto out_err;
}
}
+#ifdef CONFIG_UBSAN
+ /* required by ubsan to access the handlers structures fields */
+ err = create_hyp_mappings(kvm_ksym_ref(_data),
+ kvm_ksym_ref(__end_once), PAGE_HYP_RO);
+ if (err) {
+ kvm_err("Cannot map data section\n");
+ goto out_err;
+ }
+#endif
/*
* Map Hyp percpu pages
@@ -8,6 +8,7 @@
#include <asm/assembler.h>
#include <asm/kvm_asm.h>
+#include <asm/kvm_debug_buffer.h>
#include <asm/kvm_mmu.h>
.text
@@ -34,6 +35,9 @@ SYM_FUNC_START(__host_exit)
/* Store the host regs x18-x29, lr */
save_callee_saved_regs x0
+ /* when entering the host clear the buffers */
+ clear_buffer x4, x5, x6
+
/* Save the host context pointer in x29 across the function call */
mov x29, x0
bl handle_trap
@@ -3,10 +3,33 @@
* Copyright 2020 Google LLC
* Author: George Popescu <georgepope@google.com>
*/
+#include <linux/bitops.h>
#include <linux/ctype.h>
#include <linux/types.h>
+#include <linux/percpu-defs.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_ubsan.h>
+#include <asm/kvm_debug_buffer.h>
+#include <kvm/arm_pmu.h>
#include <ubsan.h>
+DEFINE_KVM_DEBUG_BUFFER(struct kvm_ubsan_info, kvm_ubsan_buffer,
+ kvm_ubsan_buff_wr_ind, KVM_UBSAN_BUFFER_SIZE);
+
+static inline struct kvm_ubsan_info *kvm_ubsan_buffer_next_slot(void)
+{
+ struct kvm_ubsan_info *res = NULL;
+ unsigned long write_ind = __this_cpu_read(kvm_ubsan_buff_wr_ind);
+ if (write_ind < KVM_UBSAN_BUFFER_SIZE) {
+ res = this_cpu_ptr(&kvm_ubsan_buffer[write_ind]);
+ ++write_ind;
+ __this_cpu_write(kvm_ubsan_buff_wr_ind, write_ind);
+ }
+ return res;
+}
+
void __ubsan_handle_add_overflow(void *_data, void *lhs, void *rhs) {}
void __ubsan_handle_sub_overflow(void *_data, void *lhs, void *rhs) {}
new file mode 100644
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Google LLC
+ * Author: George Popescu <georgepope@google.com>
+ */
+
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <asm/kvm_debug_buffer.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <kvm/arm_pmu.h>
+
+#include <ubsan.h>
+#include <asm/kvm_ubsan.h>
+
+DECLARE_KVM_DEBUG_BUFFER(struct kvm_ubsan_info, kvm_ubsan_buffer,
+ kvm_ubsan_buff_wr_ind, KVM_UBSAN_BUFFER_SIZE);
+
+
+void iterate_kvm_ubsan_buffer(unsigned long left, unsigned long right)
+{
+ unsigned long i;
+ struct kvm_ubsan_info *slot;
+
+ slot = (struct kvm_ubsan_info *) this_cpu_ptr_nvhe_sym(kvm_ubsan_buffer);
+ for (i = left; i < right; ++i) {
+ /* check ubsan data */
+ slot[i].type = 0;
+ }
+}
+
+void __kvm_check_ubsan_buffer(void)
+{
+ unsigned long *write_ind;
+
+ write_ind = (unsigned long *) this_cpu_ptr_nvhe_sym(kvm_ubsan_buff_wr_ind);
+ iterate_kvm_ubsan_buffer(0, *write_ind);
+}
+