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_OLDSETOPTIONS incompatible behaviour #1692

Closed
woachk opened this issue Feb 10, 2017 · 12 comments
Closed

PTRACE_OLDSETOPTIONS incompatible behaviour #1692

woachk opened this issue Feb 10, 2017 · 12 comments

Comments

@woachk
Copy link

woachk commented Feb 10, 2017

On real Linux, ptrace(PTRACE_OLDSETOPTIONS, 2831, NULL, 0x1) works properly, but it returns EINVAL (Invalid argument) on WSL. This syscall is called in the "Checking that ptrace can change system call numbers..." routine of UML.

@woachk woachk changed the title Ptrace difference in behaviour PTRACE_OLDSETOPTIONS incompatible behaviour Feb 10, 2017
@benhillis
Copy link
Member

Looks like we do not have this ptrace implemented. Could you please provide a little bit more detail on the application that is using this option so we can prioritize the implementation?

@woachk
Copy link
Author

woachk commented Feb 15, 2017

@benhillis the application is the User-Mode Linux kernel itself :)
It's an official implementation of the Linux kernel that runs fully in user-mode, with modules and everything.

@therealkenc
Copy link
Collaborator

therealkenc commented Feb 21, 2017

@benhillis - PTRACE_OLDSETOPTIONS (value 21 decimal) behaves the same as PTRACE_SETOPTIONS (value 0x4200). They changed the value of the constant (for reasons) over a decade ago, but the semantics did not change. That is, the other three ptrace() parameters are treated exactly the same, whether the first parameter is 21 or 0x4200. The values are literally aliases. So you can fix this in five minutes if you feel inclined. Might as well, because it is that easy. No strings, honest. You do not need to emulate any 'old' behavior. From man7.org:

On hosts with 2.6 kernel headers, PTRACE_SETOPTIONS is declared with a different value than the one for 2.4. This leads to applications compiled with 2.6 kernel headers failing when run on 2.4 kernels. This can be worked around by redefining PTRACE_SETOPTIONS to PTRACE_OLDSETOPTIONS, if that is defined.

Also, for a little context, the only software I can find on the planet that cares is User Mode Linux. Unless someone tries to run some statically linked strace or maybe gdb binary from the 2.4 era, this will simply never be hit on WSL in 2017. UML seems to still care, entirely academically, to maintain binary compatibility with 2.4. You can think of it as UML never buying into the idea the value changed, while everyone else moved on.

UML won't run on WSL right now anyway, because it will brick wall on #688, and who knows what else. But the issue as presented can be addressed.

Repro steps for the pedantry of it.

wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.10.tar.xz
tar xf linux-4.10.tar.xz
cd linux-4.10
make defconfig ARCH=um
make -j8 ARCH=um
./linux

@benhillis
Copy link
Member

I've fixed this but the change is unlikely to make the Creators Update release because User-Mode Linux is blocked by other things and as @therealkenc noticed the usage of this is exceedingly rare.

@woachk
Copy link
Author

woachk commented Feb 21, 2017

@benhillis thanks anyway ;)
I hope that it'll start to work somewhere in the future

@daiconrad
Copy link

This is apparently also needed to run the Swift REPL under WSL: #688

@thorsteneb
Copy link

thorsteneb commented Apr 22, 2017

@benhillis I see "Add support for PTRACE_OLDSETOPTIONS. [GH 1692]" in build 16170. I'm in 16179. I don't think it's fixed yet.

When I follow @therealkenc 's reproduction steps and run ./linux, I get:

Checking that ptrace can change system call numbers...check_ptrace : failed to modify system call: Invalid argument

When I try to strace that behavior, I get a different error:

tbehrens@WSL-Insider-Test:~/linux-4.10$ strace -o ptrace_fail -ff ./linux
Core dump limits :
        soft - 0
        hard - NONE
Checking that ptrace can change system call numbers...ptrace: Operation not permitted
check_ptrace : expected SIGSTOP, got status = 9

The strace file contains this:

tbehrens@WSL-Insider-Test:~/linux-4.10$ cat ptrace_fail.22
set_robust_list(0x7f82443b09e0, 24)     = 0
getpid()                                = 22
getppid()                               = 21
rt_sigprocmask(SIG_BLOCK, [WINCH], NULL, 8) = 0
ptrace(PTRACE_TRACEME, 0, NULL, NULL)   = -1 EPERM (Operation not permitted)
write(2, "ptrace: Operation not permitted\n", 32) = 32
kill(22, SIGKILL <unfinished ...>
+++ killed by SIGKILL +++

@therealkenc
Copy link
Collaborator

PTRACE_TRACEME is #688, as cited twice above. This issue is PTRACE_OLDSETOPTIONS, which was addressed successfully if you are now hitting PTRACE_TRACEME.

@thorsteneb
Copy link

"Invalid argument" and "operation not permitted" are different errors though? I get the PTRACE_TRACEME when strace'ing, but I'm not sure what's happening when I don't strace, and whether that's still the "invalid argument" that @woachk got originally.

How do I figure out what's going on, and why I get different errors with and without strace?

@therealkenc
Copy link
Collaborator

How do I figure out what's going on

Based on the error to stdout you reported, it looks like UML is also hitting PTRACE_POKEUSER here:

			n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
				   __NR_getppid);
			if (n < 0)
				fatal_perror("check_ptrace : failed to modify "
					     "system call");

So: "Yeah, that too"

@richardweinberger
Copy link

richardweinberger commented May 11, 2017

UML maintainer here.
Strictly speaking, to run UML you don't need PTRACE_OLDSETOPTIONS nor the ability to change syscall numbers via ptrace(). UML checks for these features because Linux supports them since ever and UML can fallback to them.
What you really need is PTRACE_SYSEMU.

That's the ptrace() side, what worries me more is that a quick test on WSL showed that SIGSEGV has no valid machine specific signal context. At least the CR2 register is 0x0 and does not expose the faulting address. This makes it impossible for UML to handle page faults in userspace.

i.e.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/ucontext.h>
#include <signal.h>
#include <errno.h>

static void segv(int sig, siginfo_t *info, void *context)
{
	ucontext_t *c = context;
	mcontext_t m = c->uc_mcontext;
	void *fault_addr = (void *)m.gregs[REG_CR2];
	void *addr;

	printf("SIGSEGV at 0x%lx, fixing up\n", (unsigned long)fault_addr);

	addr = mmap(fault_addr, 4096, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
	if (addr == MAP_FAILED) {
		printf("map failed!\n");
		exit(1);
	}
}

static void install_handler(void)
{
	struct sigaction sa;

	sa.sa_sigaction = segv;
	sa.sa_flags = SA_SIGINFO;

	sigaction(SIGSEGV, &sa, NULL);
}

int main(void)
{
	int *x = (void *)0xdeadbeef;

	install_handler();

	*x = 3;

	printf("x=%i, &x=%p\n", *x, x);

	return 0;
}

The expected output is:

SIGSEGV at 0xdeadbeef, fixing up
x=3, &x=0xdeadbeef

Please let me know if there is something I can do or explain. UML is rather old and uses not so well known Linux features. :-)

@therealkenc
Copy link
Collaborator

The (very narrow) request for PTRACE_OLDSETOPTIONS in the OP has been dangling in a fixinbound state since early 2017. #2555 can serve as a surrogate for the "SIGSEGV has no valid machine specific signal context" issue. PTRACE_SYSEMU would be really nice, but that should be filed under its own cover. People can take another run at UML on WSL (in general) after those two blockers (at least) are addressed.

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

No branches or pull requests

6 participants