Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ptrace changing syscall parameters with setregs #1491

Closed
kpocza opened this issue Dec 11, 2016 · 7 comments
Closed

ptrace changing syscall parameters with setregs #1491

kpocza opened this issue Dec 11, 2016 · 7 comments

Comments

@kpocza
Copy link

kpocza commented Dec 11, 2016

According to #1470 I'm trying to change mmap flags to MAP_ANONYMOUS|MAP_PRIVATE and the fd to -1 via ptrace.

I'm trying to do it exactly after when PTRACE_SYSCALL stops the tracee before enterring into the mmap syscall of /dev/fb0.
I was expecting that PTRACE_SETREGS will do the job, since it works correctly after returning from any syscall. However the registers are not correctly updated before a syscall.
(Hm. I'm depending on a bug since setting orig_rax to -1 and calling SETREGS has no real effect before syscall, SETREGS just ruins some context....)

I've created the following PoC to demonstrate this behavior.

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <errno.h>

int main(int argc, char **argv)
{
	char *name = "no.txt\0yes.txt";
	int pid, status, fd;
	struct user_regs_struct regs;	

	pid = fork();

	if(pid == 0) {
		ptrace(PTRACE_TRACEME, 0, 0, 0);
		raise(SIGTRAP);
		fd = open(name, O_CREAT, S_IRWXU);
		close(fd);
	}
	else {
		waitpid(pid, &status, 0);
		ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD); 
		ptrace(PTRACE_SYSCALL, pid, 0, 0);
		waitpid(pid, &status, 0);
		ptrace(PTRACE_GETREGS, pid, 0, &regs);
		regs.rdi+=7;
		ptrace(PTRACE_SETREGS, pid, 0, &regs);
		ptrace(PTRACE_CONT, pid, 0, 0);
		waitpid(pid, &status, 0);
	}	
	return 0;
}

On Ubuntu 16.04 LTS this program correctly creates yes.txt, however on Bash on Windows 10 AU and RS2 14965 it creates no.txt. It means that the rdi register is not properly updated on Bash on Windows. Of course the problem is not only with rdi but with the other regs, as well.

Am I messing something and should I do something differently, or is this really a bug somewhere?

@fpqc
Copy link

fpqc commented Dec 12, 2016

@kpocza When you run it on WSL, do you see any failing syscalls or sockopts or something in strace -ff?

If not, you may have found an implementation bug.

@kpocza
Copy link
Author

kpocza commented Dec 12, 2016

@fpqc strace -ff won't produce valuable output since the ptrace in the child fails with EPERM as strace is using the same ptrace mechanism.

There are no failing syscalls according to strace:

wait4(242, [{WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP}], 0, NULL) = 242
ptrace(PTRACE_SETOPTIONS, 242, 0, PTRACE_O_TRACESYSGOOD) = 0
ptrace(PTRACE_SYSCALL, 242, 0, SIG_0)   = 0
wait4(242, [{WIFSTOPPED(s) && WSTOPSIG(s) == 133}], 0, NULL) = 242
ptrace(PTRACE_GETREGS, 242, 0, 0x7fffed4aff20) = 0
ptrace(PTRACE_SETREGS, 242, 0, 0x7fffed4aff20) = 0
ptrace(PTRACE_CONT, 242, 0, SIG_0)      = 0
wait4(242, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 242
exit_group(0)                           = ?

@fpqc
Copy link

fpqc commented Dec 12, 2016

@kpocza Ok, cool hopefully one of the devs will use your poc to see if it's an implementation bug good luck!

@ckahlo
Copy link

ckahlo commented Apr 15, 2019

What's the current state of this issue? I am running into the same bug. Using a ptracer I have to modify syscall values (in this case including the syscall number itself and the arguments) to work around missing implementations in WSL. However changes to the register set are ignored and only visible when back in user space. I.e. registers are changed as they should be. WSLs seems to rely on values fetched bevor the tracer is called and ignores any changes afterwards. With respect to certain "implementation specific abnormalities" this does not allow to fix things with the help of a tracer. It should be rather easy to use the values from the register sets. The linux kernel works the same way.

The proof of concept from @kpocza is valid.

@ckahlo
Copy link

ckahlo commented Apr 15, 2019

PS: verified up to 4.4.0-17763-Microsoft #379-Microsoft Wed Mar 06 19:16:00 PST 2019 x86_64 x86_64 x86_64 GNU/Linux

So this is still a current issue.

@Anutrix
Copy link

Anutrix commented Nov 30, 2019

Any updates?

@therealkenc
Copy link
Collaborator

Tried the OP PoC on a Real Linux box and (oddly) it did not create yes.txt or no.txt (it just exits). Finding out why is probably academic. The landing zone for PTRACE_TRACEME effectively became #2028 and is better on WSL2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants