I am trying to implement a syscall
on x86
that is able to modify the content of vDSO
. Given vDSO
content is read-only for userspace, I believe a syscall
is needed. Otherwise it will cause segmentation fault. However, I can't do it successfully at this moment.
My plan:
syscall in kernel/sys.c
extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden")));
SYSCALL_DEFINE1(foo, int, num) {
struct vdso_data *vdata = _vdso_data;
vdata[0].__unused = num;
return 0;
}
The syscall
will read the _vdso_data
which is declared in arch/x86/include/asm/vvar.h
and defined in arch/x86/include/asm/vdso/vsyscall.h
.
Then it will modify the variable __unused
into some number input by the user.
vDSO in arch/x86/entry/vdso/vclock_gettime.c
#include <asm/vdso/vsyscall.h>
notrace int __vdso_query()
{
struct vdso_data *vdata = __arch_get_k_vdso_data();
return vdata[0].__unused;
}
I know it's a bad idea to define something unrelated to time in a timing fucntion, but this is what I'm testing right now. The __vdso_query()
function will read the data and return the value of the __unused
variable.
Testing plan
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#define SYS_foo 548
extern int __vdso_query();
int main(int argc, char **argv)
{
int before = __vdso_query();
printf("Before syscall: %d\n", before);
int num = 10;
long res = syscall(SYS_foo, num);
int after = __vdso_query();
printf("After syscall: %d\n", after);
return res;
}
Expected results
I want to see 0
before the syscall
and 10
after the syscall
returned by __vdso_query()
since the syscall
will change the _vdso_data[0].__unused
if everything follows the plan.
Current results
For now, the content is always 0
regardless of the syscall
.
Questions
How to access _vdso_data
properly
There are 2 ways I tried to access the _vdso_data
: __arch_sync_vdso_data()
and extern
.
- When I tried to use
__arch_get_k_vdso_data
function where defined inasm/vdso/vsyscall.h
to access the_vdso_data
, I encounter some variable redefinition errors. If I includevsyscall.h
in bothkernel/sys.c
andarch/x86/entry/vdso/vclock_gettime.c
, it seemsDEFINE_VVAR(struct vdso_data, _vdso_data);
will be called twice and leads to redefinition error of_vdso_data
. I tried to put#ifndef
,#def
, and#endif
macros around it but the error still exists. - Another thing I tried is only declaring the
_vdso_data
asextern
variable shown in thesyscall
implementation. The redefinition error is gone if I do this. The code compiles and runs properly without error or segmentation fault, but the result doesn't change.
__arch_sync_vdso_data()
function
I read some example usages in the kernel source code a little bit and I find people use __arch_sync_vdso_data
function to write the _vdso_data
in the end. However, I think this function is actually empty in the generic-asm
and the only definition I can find is on Arm
. Not really sure how this will work on x86
and is it needed.
It's really hard to find vdso resources online and I've read all the recent posts. I would really appreciate the help and thanks in advance.
It turns out
syscall
is doing the right work and the problem is how to access thevDSO
data.In fact,
__arch_get_vdso_data
is the right function to access vDSO data. It returns a pointer which can be further dereferenced to access the data like__arch_get_vdso_data()->__unused
.On the other hand,
__arch_get_k_vdso_data
never works and I suspect the_k_
in the function name indicates that this function can be only used in kernel space.