Home | History | Annotate | Download | only in strace
      1 /*
      2  * Support for decoding of KVM_* ioctl commands.
      3  *
      4  * Copyright (c) 2017 Masatake YAMATO <yamato (at) redhat.com>
      5  * Copyright (c) 2017 Red Hat, Inc.
      6  * Copyright (c) 2017-2018 The strace developers.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of the author may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "defs.h"
     33 
     34 #ifdef HAVE_LINUX_KVM_H
     35 # include <linux/kvm.h>
     36 # include "print_fields.h"
     37 # include "arch_kvm.c"
     38 # include "xmalloc.h"
     39 # include "mmap_cache.h"
     40 
     41 struct vcpu_info {
     42 	struct vcpu_info *next;
     43 	int fd;
     44 	int cpuid;
     45 	long mmap_addr;
     46 	unsigned long mmap_len;
     47 	bool resolved;
     48 };
     49 
     50 static bool dump_kvm_run_structure;
     51 
     52 static struct vcpu_info *
     53 vcpu_find(struct tcb *const tcp, int fd)
     54 {
     55 	for (struct vcpu_info *vcpu_info = tcp->vcpu_info_list;
     56 	     vcpu_info;
     57 	     vcpu_info = vcpu_info->next)
     58 		if (vcpu_info->fd == fd)
     59 			return vcpu_info;
     60 
     61 	return NULL;
     62 }
     63 
     64 static struct vcpu_info *
     65 vcpu_alloc(struct tcb *const tcp, int fd, int cpuid)
     66 {
     67 	struct vcpu_info *vcpu_info = xcalloc(1, sizeof(*vcpu_info));
     68 
     69 	vcpu_info->fd = fd;
     70 	vcpu_info->cpuid = cpuid;
     71 
     72 	vcpu_info->next = tcp->vcpu_info_list;
     73 	tcp->vcpu_info_list = vcpu_info;
     74 
     75 	return vcpu_info;
     76 }
     77 
     78 void
     79 kvm_vcpu_info_free(struct tcb *tcp)
     80 {
     81 	struct vcpu_info *head, *next;
     82 
     83 	for (head = tcp->vcpu_info_list; head; head = next) {
     84 		next = head->next;
     85 		free(head);
     86 	}
     87 
     88 	tcp->vcpu_info_list = NULL;
     89 }
     90 
     91 static void
     92 vcpu_register(struct tcb *const tcp, int fd, int cpuid)
     93 {
     94 	if (fd < 0)
     95 		return;
     96 
     97 	struct vcpu_info *vcpu_info = vcpu_find(tcp, fd);
     98 
     99 	if (!vcpu_info)
    100 		vcpu_info = vcpu_alloc(tcp, fd, cpuid);
    101 	else if (vcpu_info->cpuid != cpuid)
    102 	{
    103 		vcpu_info->cpuid = cpuid;
    104 		vcpu_info->resolved = false;
    105 	}
    106 }
    107 
    108 static bool
    109 is_map_for_file(struct mmap_cache_entry_t *map_info, void *data)
    110 {
    111 	/* major version for anon inode may be given in get_anon_bdev()
    112 	 * in linux kernel.
    113 	 *
    114 	 * 	*p = MKDEV(0, dev & MINORMASK);
    115 	 *-----------------^
    116 	 */
    117 	return map_info->binary_filename &&
    118 		map_info->major == 0 &&
    119 		strcmp(map_info->binary_filename, data) == 0;
    120 }
    121 
    122 static unsigned long
    123 map_len(struct mmap_cache_entry_t *map_info)
    124 {
    125 	return map_info->start_addr < map_info->end_addr
    126 		? map_info->end_addr - map_info->start_addr
    127 		: 0;
    128 }
    129 
    130 #define VCPU_DENTRY_PREFIX "anon_inode:kvm-vcpu:"
    131 
    132 static struct vcpu_info*
    133 vcpu_get_info(struct tcb *const tcp, int fd)
    134 {
    135 	struct vcpu_info *vcpu_info = vcpu_find(tcp, fd);
    136 	struct mmap_cache_entry_t *map_info;
    137 	const char *cpuid_str;
    138 
    139 	enum mmap_cache_rebuild_result mc_stat =
    140 		mmap_cache_rebuild_if_invalid(tcp, __func__);
    141 	if (mc_stat == MMAP_CACHE_REBUILD_NOCACHE)
    142 		return NULL;
    143 
    144 	if (vcpu_info && vcpu_info->resolved) {
    145 		if (mc_stat == MMAP_CACHE_REBUILD_READY)
    146 			return vcpu_info;
    147 		else {
    148 			map_info = mmap_cache_search(tcp, vcpu_info->mmap_addr);
    149 			if (map_info) {
    150 				cpuid_str =
    151 					STR_STRIP_PREFIX(map_info->binary_filename,
    152 							 VCPU_DENTRY_PREFIX);
    153 				if (cpuid_str != map_info->binary_filename) {
    154 					int cpuid = string_to_uint(cpuid_str);
    155 					if (cpuid < 0)
    156 						return NULL;
    157 					if (vcpu_info->cpuid == cpuid)
    158 						return vcpu_info;
    159 				}
    160 			}
    161 
    162 			/* The vcpu vma may be mremap'ed. */
    163 			vcpu_info->resolved = false;
    164 		}
    165 	}
    166 
    167 	/* Slow path: !vcpu_info || !vcpu_info->resolved */
    168 	char path[PATH_MAX + 1];
    169 	cpuid_str = path;
    170 	if (getfdpath(tcp, fd, path, sizeof(path)) >= 0)
    171 		cpuid_str = STR_STRIP_PREFIX(path, VCPU_DENTRY_PREFIX);
    172 	if (cpuid_str == path)
    173 		map_info = NULL;
    174 	else
    175 		map_info = mmap_cache_search_custom(tcp, is_map_for_file, path);
    176 
    177 	if (map_info) {
    178 		int cpuid = string_to_uint(cpuid_str);
    179 		if (cpuid < 0)
    180 			return NULL;
    181 		if (!vcpu_info)
    182 			vcpu_info = vcpu_alloc(tcp, fd, cpuid);
    183 		else if (vcpu_info->cpuid != cpuid)
    184 			vcpu_info->cpuid = cpuid;
    185 		vcpu_info->mmap_addr = map_info->start_addr;
    186 		vcpu_info->mmap_len  = map_len(map_info);
    187 		vcpu_info->resolved  = true;
    188 		return vcpu_info;
    189 	}
    190 
    191 	return NULL;
    192 }
    193 
    194 static int
    195 kvm_ioctl_create_vcpu(struct tcb *const tcp, const kernel_ulong_t arg)
    196 {
    197 	uint32_t cpuid = arg;
    198 
    199 	if (entering(tcp)) {
    200 		tprintf(", %u", cpuid);
    201 		if (dump_kvm_run_structure)
    202 			return 0;
    203 	} else if (!syserror(tcp)) {
    204 		vcpu_register(tcp, tcp->u_rval, cpuid);
    205 	}
    206 
    207 	return RVAL_IOCTL_DECODED | RVAL_FD;
    208 }
    209 
    210 # ifdef HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION
    211 #  include "xlat/kvm_mem_flags.h"
    212 static int
    213 kvm_ioctl_set_user_memory_region(struct tcb *const tcp, const kernel_ulong_t arg)
    214 {
    215 	struct kvm_userspace_memory_region u_memory_region;
    216 
    217 	tprints(", ");
    218 	if (umove_or_printaddr(tcp, arg, &u_memory_region))
    219 		return RVAL_IOCTL_DECODED;
    220 
    221 	PRINT_FIELD_U("{", u_memory_region, slot);
    222 	PRINT_FIELD_FLAGS(", ", u_memory_region, flags, kvm_mem_flags,
    223 			  "KVM_MEM_???");
    224 	PRINT_FIELD_X(", ", u_memory_region, guest_phys_addr);
    225 	PRINT_FIELD_U(", ", u_memory_region, memory_size);
    226 	PRINT_FIELD_X(", ", u_memory_region, userspace_addr);
    227 	tprints("}");
    228 
    229 	return RVAL_IOCTL_DECODED;
    230 }
    231 # endif /* HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION */
    232 
    233 # ifdef HAVE_STRUCT_KVM_REGS
    234 static int
    235 kvm_ioctl_decode_regs(struct tcb *const tcp, const unsigned int code,
    236 		      const kernel_ulong_t arg)
    237 {
    238 	struct kvm_regs regs;
    239 
    240 	if (code == KVM_GET_REGS && entering(tcp))
    241 		return 0;
    242 
    243 	tprints(", ");
    244 	if (!umove_or_printaddr(tcp, arg, &regs))
    245 		arch_print_kvm_regs(tcp, arg, &regs);
    246 
    247 	return RVAL_IOCTL_DECODED;
    248 }
    249 # endif /* HAVE_STRUCT_KVM_REGS */
    250 
    251 # ifdef HAVE_STRUCT_KVM_CPUID2
    252 #  include "xlat/kvm_cpuid_flags.h"
    253 static bool
    254 print_kvm_cpuid_entry(struct tcb *const tcp,
    255 		      void* elem_buf, size_t elem_size, void* data)
    256 {
    257 	const struct kvm_cpuid_entry2 *entry = elem_buf;
    258 	PRINT_FIELD_X("{", *entry, function);
    259 	PRINT_FIELD_X(", ", *entry, index);
    260 	PRINT_FIELD_FLAGS(", ", *entry, flags, kvm_cpuid_flags,
    261 			  "KVM_CPUID_FLAG_???");
    262 	PRINT_FIELD_X(", ", *entry, eax);
    263 	PRINT_FIELD_X(", ", *entry, ebx);
    264 	PRINT_FIELD_X(", ", *entry, ecx);
    265 	PRINT_FIELD_X(", ", *entry, edx);
    266 	tprints("}");
    267 
    268 	return true;
    269 }
    270 
    271 static int
    272 kvm_ioctl_decode_cpuid2(struct tcb *const tcp, const unsigned int code,
    273 			const kernel_ulong_t arg)
    274 {
    275 	struct kvm_cpuid2 cpuid;
    276 
    277 	if (entering(tcp) && (code == KVM_GET_SUPPORTED_CPUID
    278 #  ifdef KVM_GET_EMULATED_CPUID
    279 			      || code == KVM_GET_EMULATED_CPUID
    280 #  endif
    281 			     ))
    282 		return 0;
    283 
    284 	tprints(", ");
    285 	if (!umove_or_printaddr(tcp, arg, &cpuid)) {
    286 		PRINT_FIELD_U("{", cpuid, nent);
    287 
    288 		tprints(", entries=");
    289 		if (abbrev(tcp)) {
    290 			tprints("[");
    291 			if (cpuid.nent)
    292 				tprints("...");
    293 			tprints("]");
    294 
    295 		} else {
    296 			struct kvm_cpuid_entry2 entry;
    297 			print_array(tcp, arg + sizeof(cpuid), cpuid.nent,
    298 				    &entry, sizeof(entry), tfetch_mem,
    299 				    print_kvm_cpuid_entry, NULL);
    300 		}
    301 		tprints("}");
    302 	}
    303 
    304 	return RVAL_IOCTL_DECODED;
    305 }
    306 # endif /* HAVE_STRUCT_KVM_CPUID2 */
    307 
    308 # ifdef HAVE_STRUCT_KVM_SREGS
    309 static int
    310 kvm_ioctl_decode_sregs(struct tcb *const tcp, const unsigned int code,
    311 		       const kernel_ulong_t arg)
    312 {
    313 	struct kvm_sregs sregs;
    314 
    315 	if (code == KVM_GET_SREGS && entering(tcp))
    316 		return 0;
    317 
    318 	tprints(", ");
    319 	if (!umove_or_printaddr(tcp, arg, &sregs))
    320 		arch_print_kvm_sregs(tcp, arg, &sregs);
    321 
    322 	return RVAL_IOCTL_DECODED;
    323 }
    324 # endif /* HAVE_STRUCT_KVM_SREGS */
    325 
    326 # include "xlat/kvm_cap.h"
    327 static int
    328 kvm_ioctl_decode_check_extension(struct tcb *const tcp, const unsigned int code,
    329 				 const kernel_ulong_t arg)
    330 {
    331 	tprints(", ");
    332 	printxval_index(kvm_cap, arg, "KVM_CAP_???");
    333 	return RVAL_IOCTL_DECODED;
    334 }
    335 
    336 # include "xlat/kvm_exit_reason.h"
    337 static void
    338 kvm_ioctl_run_attach_auxstr(struct tcb *const tcp,
    339 			    struct vcpu_info *info)
    340 
    341 {
    342 	static struct kvm_run vcpu_run_struct;
    343 
    344 	if (info->mmap_len < sizeof(vcpu_run_struct))
    345 		return;
    346 
    347 	if (umove(tcp, info->mmap_addr, &vcpu_run_struct) < 0)
    348 		return;
    349 
    350 	tcp->auxstr = xlat_idx(kvm_exit_reason, ARRAY_SIZE(kvm_exit_reason) - 1,
    351 			       vcpu_run_struct.exit_reason);
    352 	if (!tcp->auxstr)
    353 		tcp->auxstr = "KVM_EXIT_???";
    354 }
    355 
    356 static int
    357 kvm_ioctl_decode_run(struct tcb *const tcp)
    358 {
    359 
    360 	if (entering(tcp))
    361 		return 0;
    362 
    363 	int r = RVAL_DECODED;
    364 
    365 	if (syserror(tcp))
    366 		return r;
    367 
    368 	if (dump_kvm_run_structure) {
    369 		tcp->auxstr = NULL;
    370 		int fd = tcp->u_arg[0];
    371 		struct vcpu_info *info = vcpu_get_info(tcp, fd);
    372 
    373 		if (info) {
    374 			kvm_ioctl_run_attach_auxstr(tcp, info);
    375 			if (tcp->auxstr)
    376 				r |= RVAL_STR;
    377 		}
    378 	}
    379 
    380 	return r;
    381 }
    382 
    383 int
    384 kvm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
    385 {
    386 	switch (code) {
    387 	case KVM_CREATE_VCPU:
    388 		return kvm_ioctl_create_vcpu(tcp, arg);
    389 
    390 # ifdef HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION
    391 	case KVM_SET_USER_MEMORY_REGION:
    392 		return kvm_ioctl_set_user_memory_region(tcp, arg);
    393 # endif
    394 
    395 # ifdef HAVE_STRUCT_KVM_REGS
    396 	case KVM_SET_REGS:
    397 	case KVM_GET_REGS:
    398 		return kvm_ioctl_decode_regs(tcp, code, arg);
    399 # endif
    400 
    401 # ifdef HAVE_STRUCT_KVM_SREGS
    402 	case KVM_SET_SREGS:
    403 	case KVM_GET_SREGS:
    404 		return kvm_ioctl_decode_sregs(tcp, code, arg);
    405 # endif
    406 
    407 # ifdef HAVE_STRUCT_KVM_CPUID2
    408        case KVM_SET_CPUID2:
    409        case KVM_GET_SUPPORTED_CPUID:
    410 #  ifdef KVM_GET_EMULATED_CPUID
    411        case KVM_GET_EMULATED_CPUID:
    412 #  endif
    413                return kvm_ioctl_decode_cpuid2(tcp, code, arg);
    414 # endif
    415 
    416 	case KVM_CHECK_EXTENSION:
    417 		return kvm_ioctl_decode_check_extension(tcp, code, arg);
    418 
    419 	case KVM_CREATE_VM:
    420 		return RVAL_DECODED | RVAL_FD;
    421 
    422 	case KVM_RUN:
    423 		return kvm_ioctl_decode_run(tcp);
    424 
    425 	case KVM_GET_VCPU_MMAP_SIZE:
    426 	case KVM_GET_API_VERSION:
    427 	default:
    428 		return RVAL_DECODED;
    429 	}
    430 }
    431 
    432 void
    433 kvm_run_structure_decoder_init(void)
    434 {
    435 	dump_kvm_run_structure = true;
    436 	mmap_cache_enable();
    437 }
    438 
    439 #endif /* HAVE_LINUX_KVM_H */
    440