github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/executor/common_kvm_arm64.h (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  // This file is shared between executor and csource package.
     5  
     6  // Implementation of syz_kvm_setup_cpu pseudo-syscall.
     7  
     8  struct kvm_text {
     9  	uintptr_t typ;
    10  	const void* text;
    11  	uintptr_t size;
    12  };
    13  
    14  struct kvm_opt {
    15  	uint64 typ;
    16  	uint64 val;
    17  };
    18  
    19  // syz_kvm_setup_cpu(fd fd_kvmvm, cpufd fd_kvmcpu, usermem vma[24], text ptr[in, array[kvm_text, 1]], ntext len[text], flags flags[kvm_setup_flags], opts ptr[in, array[kvm_setup_opt, 0:2]], nopt len[opts])
    20  static volatile long syz_kvm_setup_cpu(volatile long a0, volatile long a1, volatile long a2, volatile long a3, volatile long a4, volatile long a5, volatile long a6, volatile long a7)
    21  {
    22  	const int vmfd = a0;
    23  	const int cpufd = a1;
    24  	char* const host_mem = (char*)a2;
    25  	const struct kvm_text* const text_array_ptr = (struct kvm_text*)a3;
    26  	const uintptr_t text_count = a4;
    27  	const uintptr_t flags = a5;
    28  	const struct kvm_opt* const opt_array_ptr = (struct kvm_opt*)a6;
    29  	uintptr_t opt_count = a7;
    30  
    31  	(void)flags;
    32  	(void)opt_count;
    33  
    34  	const uintptr_t page_size = 4 << 10;
    35  	const uintptr_t guest_mem = 0;
    36  	const uintptr_t guest_mem_size = 24 * page_size;
    37  
    38  	(void)text_count; // fuzzer can spoof count and we need just 1 text, so ignore text_count
    39  	int text_type = text_array_ptr[0].typ;
    40  	const void* text = text_array_ptr[0].text;
    41  	int text_size = text_array_ptr[0].size;
    42  	(void)text_type;
    43  	(void)opt_array_ptr;
    44  
    45  	uint32 features = 0;
    46  	if (opt_count > 1)
    47  		opt_count = 1;
    48  	for (uintptr_t i = 0; i < opt_count; i++) {
    49  		uint64 typ = opt_array_ptr[i].typ;
    50  		uint64 val = opt_array_ptr[i].val;
    51  		switch (typ) {
    52  		case 1:
    53  			features = val;
    54  			break;
    55  		}
    56  	}
    57  
    58  	for (uintptr_t i = 0; i < guest_mem_size / page_size; i++) {
    59  		struct kvm_userspace_memory_region memreg;
    60  		memreg.slot = i;
    61  		memreg.flags = 0; // can be KVM_MEM_LOG_DIRTY_PAGES | KVM_MEM_READONLY
    62  		memreg.guest_phys_addr = guest_mem + i * page_size;
    63  		memreg.memory_size = page_size;
    64  		memreg.userspace_addr = (uintptr_t)host_mem + i * page_size;
    65  		ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &memreg);
    66  	}
    67  
    68  	struct kvm_vcpu_init init;
    69  	// Queries KVM for preferred CPU target type.
    70  	ioctl(vmfd, KVM_ARM_PREFERRED_TARGET, &init);
    71  	init.features[0] = features;
    72  	// Use the modified struct kvm_vcpu_init to initialize the virtual CPU.
    73  	ioctl(cpufd, KVM_ARM_VCPU_INIT, &init);
    74  
    75  	if (text_size > 1000)
    76  		text_size = 1000;
    77  	memcpy(host_mem, text, text_size);
    78  
    79  	return 0;
    80  }