• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Support for decoding of KVM_* ioctl commands.
3  *
4  * Copyright (c) 2017 Masatake YAMATO <yamato@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 *
vcpu_find(struct tcb * const tcp,int fd)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 *
vcpu_alloc(struct tcb * const tcp,int fd,int cpuid)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
kvm_vcpu_info_free(struct tcb * tcp)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
vcpu_register(struct tcb * const tcp,int fd,int cpuid)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
is_map_for_file(struct mmap_cache_entry_t * map_info,void * data)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
map_len(struct mmap_cache_entry_t * map_info)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*
vcpu_get_info(struct tcb * const tcp,int fd)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
kvm_ioctl_create_vcpu(struct tcb * const tcp,const kernel_ulong_t arg)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
kvm_ioctl_set_user_memory_region(struct tcb * const tcp,const kernel_ulong_t arg)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
kvm_ioctl_decode_regs(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)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
print_kvm_cpuid_entry(struct tcb * const tcp,void * elem_buf,size_t elem_size,void * data)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
kvm_ioctl_decode_cpuid2(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)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
kvm_ioctl_decode_sregs(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)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
kvm_ioctl_decode_check_extension(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)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
kvm_ioctl_run_attach_auxstr(struct tcb * const tcp,struct vcpu_info * info)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
kvm_ioctl_decode_run(struct tcb * const tcp)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
kvm_ioctl(struct tcb * const tcp,const unsigned int code,const kernel_ulong_t arg)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
kvm_run_structure_decoder_init(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