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_datafunction where defined inasm/vdso/vsyscall.hto access the_vdso_data, I encounter some variable redefinition errors. If I includevsyscall.hin bothkernel/sys.candarch/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#endifmacros around it but the error still exists. - Another thing I tried is only declaring the
_vdso_dataasexternvariable shown in thesyscallimplementation. 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
syscallis doing the right work and the problem is how to access thevDSOdata.In fact,
__arch_get_vdso_datais 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_datanever works and I suspect the_k_in the function name indicates that this function can be only used in kernel space.