* Changes from v1 - Introduce the patch as a bug fix, rather than a security fix - Use do_openat and safe_execveat instead of copying exec_path - Extensive test case example * Test case
I will present a short program that demonstrated the bug, i.e. what is the expected behavior and what really happens. Then, I will explain how this patch fixes this bug. ** The program ------------------------------------------------------------------- #include <errno.h> #include <string.h> #include <unistd.h> static char *ARG0 = "STOP"; static char *ARG1 = "-this-is-not-an-option"; int main(int argc, char *argv[], char *envp[]) { (void)argc; if (0 == strcmp(argv[0], ARG0)) return 0; argv[0] = ARG0; argv[1] = ARG1; execve("/proc/self/exe", (char **const)argv, (char **const)envp); return errno; } ------------------------------------------------------------------- Note that in every cases, this program should be run with at least one argument, so that argv[1] points to something. *** Expected behavior This program when run normally, i.e. without an emulator or with this patch applied, will run two times. The first time, it will change its argv[0] and argv[1] and recursively call itself. The second time, it will stop at the string comparaison between argv[0] and the sentinel ARG0, returning 0. Thus, we expect the program to finish with error code 0 and nothing is printed to stdout&stderr. *** What really happens When emulated by qemu-user, this program will fail to call itself recursively and will instead call qemu-user. This is where ARG1 becomes useful. It's indeed set to an option that is not supported by qemu-user, and thus we expected two things 1) A message will be printed to stdout&|stderr 2) A error code different from 0 will be returned For example, I get the following output with error code 1 ------------------------------------------------------------------- qemu: unknown option 'this-is-not-an-option' ------------------------------------------------------------------- *** Automated testing The following is a quick bash script that demonstrates how to use this test case. I suppose here that qemu-user is the correct emulator for the arch of the compiled program a.out. ------------------------------------------------------------------ #!/bin/bash out=$(qemu-user ./a.out foo) ret=0 if [[ $out != "" || $? != 0 ]]; then ret=1 fi exit $ret ------------------------------------------------------------------ * Fixing the bug This patch introduces the use of safe_execveat instead of safe_execve for the emulation of execve. By using the do_openat function, we ensure that the executable file descriptor is really the one the user wants. Olivier Dion (1): Handle /proc/self/exe in syscall execve linux-user/syscall.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) -- 2.23.0