* 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