Disabling vsyscalls in Linux
Asked Answered
S

5

8

I'm working on a piece of software that monitors other processes' system calls using ptrace(2). Unfortunately most modern operating system implement some kind of fast user-mode syscalls that are called vsyscalls in Linux.

Is there any way to disable the use of vsyscalls/vDSO for a single process or, if that is not possible, for the whole operating system?

Swansdown answered 26/11, 2011 at 16:55 Comment(1)
Do you imply that ptrace don't catch all vsyscall-ed syscalls?Subtotal
N
7

Try echo 0 > /proc/sys/kernel/vsyscall64

If you're trying to ptrace on gettimeofday calls and they aren't showing up, what time source is the system using (pmtimer, acpi, tsc, hpet, etc). I wonder if you'd humor me by trying to force your timer to something older like pmtimer. It's possible one of the many gtod timer specific optimizations is causing your ptrace calls to be avoided, even with vsyscall set to zero.

Nickolasnickolaus answered 26/11, 2011 at 16:59 Comment(6)
Tried it, does not seem to work, I still don't see time/gettimeofday syscalls. I also tried the vdso=0 boot option without success.Swansdown
@Swansdown have you looked at the source of gettimeofday, seen if it honors the vsyscall flag? I'm going to look into it myself tonight.Nickolasnickolaus
OK, I can see the gettimeofday syscall with vsyscall64=0, but I still don't see the time syscall.Swansdown
Must have been some other issue, you were right, I can see all syscalls with vsyscall64=0.Swansdown
For a way to avoid vDSO calls for a specific process without system-wide changes, see my answer: https://mcmap.net/q/1264913/-disabling-vsyscalls-in-linuxAfebrile
This doesn't work in newer kernels as this tunable was removed in 2011.Benzocaine
S
4

For newer systems echo 0 > /proc/sys/kernel/vsyscall64 might not work. In Ubuntu 16.04 vDSO can be disabled system-wide by adding the kernel parameter vdso=0 in /etc/default/grub under the parameter: GRUB_CMDLINE_LINUX_DEFAULT.

IMPORTANT: Parameter GRUB_CMDLINE_LINUX_DEFAULT might be overwriten by other configuration files in /etc/default/grub.d/..., so double check when to add your custom configuration.

Subatomic answered 16/5, 2017 at 1:9 Comment(1)
For a way to avoid vDSO calls for a specific process without system-wide changes, see my answer: https://mcmap.net/q/1264913/-disabling-vsyscalls-in-linuxAfebrile
A
4

Is there any way to disable the use of vsyscalls/vDSO for a single process or, if that is not possible, for the whole operating system?

It turns out there IS a way to effectively disable linking vDSO for a single process without disabling it system-wide using ptrace!

All you have to do is to stop the traced process before it returns from execve and remove the AT_SYSINFO_EHDR entry from the auxiliary vector (which comes directly after environment variables along the memory region pointed to in rsp). PTRACE_EVENT_EXEC is a good place to do this.

AT_SYSINFO_EHDR is what the kernel uses to tell the system linker where vDSO is mapped in the process's address space. If this entry is not present, ld seems to act as if the system hasn't mapped a vDSO.

Note that this doesn't somehow unmap the vDSO from your processes memory, it merely ignores it when linking other shared libraries. A malicious program will still be able to interact with it if the author really wanted to.

I know this answer is a bit late, but I hope this information will spare some poor soul a headache

Afebrile answered 19/9, 2018 at 9:16 Comment(1)
This requires that the process (for which you want to disable vdso) runs under some wrapper executable/script, right? Can you please post a source code for such executable or script (or post a link to it) in case you have one?Voiture
D
2

Picking up on Tenders McChiken's approach, I did create a wrapper that disables vDSO for an arbitrary binary, without affecting the rest of the system: https://github.com/danteu/novdso

The general procedure is quite simple:

  1. use ptrace to wait for return from execve(2)
  2. find the address of the auxvector
  3. overwrite the AT_SYSINFO_EHDR entry with AT_IGNORE, telling the application to ignore the following value
Dextrocular answered 9/9, 2020 at 11:46 Comment(0)
J
1

I know this is an older question, but nobody has mentioned a third useful way of disabling the vDSO on a per-process basis. You can overwrite the libc functions with your own that performs the actual system call using LD_PRELOAD.

A simple shared library for overriding the gettimeofday and time functions, for example, could look like this:

vdso_override.c:

#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/syscall.h>

int gettimeofday(struct timeval *restrict tv, struct timezone *restrict tz)
{
    return syscall(__NR_gettimeofday, (long)tv, (long)tz, 0, 0, 0, 0);
}

time_t time(time_t *tloc)
{
    return syscall(__NR_time, (long)tloc, 0, 0, 0, 0, 0);
}

This uses the libc wrapper to issue a raw system call (see syscall(2)), so the vDSO is circumvented. You would have to overwrite all system calls that the vDSO exports on your architecture in this way (listed at vdso(7)).

Compile with

gcc -fpic -shared -o vdso_override.so vdso_override.c

Then run any program in which you want to disable VDSO calls as follows:

LD_PRELOAD=./vdso_override.so <some program>

This of course only works if the program you are running is not actively trying to circumvent this. While you can override a symbol using LD_PRELOAD, if the target program really wants to, there is a way to find the original symbol and use that instead.

Jaret answered 29/12, 2022 at 22:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.