For past few weeks, I’ve been reading qemu source code and cross compiling it for android. I was going to fuzz some binaries. But I can’t go into details about that projects so here I just share some thing about qemu source code with you. This post is mainly about qemu user mode and its ioctls realization.

I’ve record a video here for those who prefer to watch videos.

So for the qemu user mode, the point that we start with is /linux-user/main.c. The story starts at the main function here. There are two function calls here that I want to mention.

1
2
3
syscall_init();

cpu_loop(env);

For the syscall_init(), we can find it in the /linux-user/syscall.c . In this function, we can find this piece of code.

1
2
3
4
5
#define STRUCT(name, ...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
#include "syscall_types.h"
#undef STRUCT
#undef STRUCT_SPECIAL

So here it translates the STRUCT() in the syscall_types to a function. Basically what this function does is put the structs into some kind of struct_entries. We can also see that there is a while loop that calculates all the ie-target_cmd. This is used when there are syscalls from user land and qemu just passes it to the kernel.

For the cpuloop(), since we are on the aarch64 phone we can find it in the /linux-user/aarch64/cpuloop.c. So in this function we have a infinite for loop. And the key here is that switch().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
switch (trapnr)

Most of the time, we go into this case.

case EXCP_SWI:
ret = do_syscall(env,
env->xregs[8],
env->xregs[0],
env->xregs[1],
env->xregs[2],
env->xregs[3],
env->xregs[4],
env->xregs[5],
0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
env->xregs[0] = ret;
}
break;

We see here the do_syscall takes in the register values. So this function is in the syscall.c And in the do_syscall we can still find a switch.

1
switch(num)

Since I want to talk about ioctl, it’s in this case.

1
2
3
case TARGET_NR_ioctl:
ret = do_ioctl(arg1, arg2, arg3);
break;

And in the do_ioctl function, we can find that it actually do that ioctl using safe_ioctl. So we know that qemu here uses this method to implement those ioctls it regards as safe. So in order to let the qemu think one ioctl is safe, we have to add the new ioctl in these three files: syscall_defs.h syscall_types.h ioctls.h. Take a look at this patch, you will know everything.

https://lists.gnu.org/archive/html/qemu-devel/2017-10/msg00873.html

Now you can add your personal ioctls that qemu is not supporting.