Skip to content

Commit

Permalink
feat: Binary syscall bypass through VDSO
Browse files Browse the repository at this point in the history
MUSL utilizes the `__syscall` macro to perform system calls.
Syscalls with varying numbers of parameters are further dispatched to
implementations like `__syscall1`, `__syscall2`, and so on.
These implementations employ the `syscall` instruction for binary
syscalls. To bypass binary syscalls, we extract the `__kernel_vsyscall`
symbol from VDSO and replace the `syscall` instruction with a direct
call to the kernel functions.

Note that during the initialization process of MUSL, certain syscalls
will be used. However, at this point, the `__kernel_vsyscall` symbol
has not yet been extracted. It's also possible that the kernel could
not provide this interface. In such cases, the `__kernel_vsyscall`
pointer remains at its default value of `NULL`, and MUSL will continue
to use binary syscalls.

Since we do not support syscalls with cancellation points (syscall_cp),
we merely map them to regular syscalls.

Signed-off-by: Tianyi Liu <[email protected]>
Signed-off-by: Simon Kuenzer <[email protected]>
Co-authored-by: Simon Kuenzer <[email protected]>
Reviewed-by: Ioan-Teodor Teugea <[email protected]>
Reviewed-by: Andra Paraschiv <[email protected]>
Approved-by: Simon Kuenzer <[email protected]>
GitHub-Closes: #1
  • Loading branch information
2 people authored and razvand committed Aug 17, 2023
1 parent f5f55d6 commit cdd7243
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 24 deletions.
119 changes: 95 additions & 24 deletions src/internal/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,104 @@ hidden long __syscall_ret(unsigned long),
__syscall_cp(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t,
syscall_arg_t, syscall_arg_t, syscall_arg_t);

#define __syscall1(n,a) __syscall1(n,__scc(a))
#define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b))
#define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c))
#define __syscall4(n,a,b,c,d) __syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d))
#define __syscall5(n,a,b,c,d,e) __syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e))
#define __syscall6(n,a,b,c,d,e,f) __syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f))
#define __syscall7(n,a,b,c,d,e,f,g) __syscall7(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g))

#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n
#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,)
#define __SYSCALL_CONCAT_X(a,b) a##b
#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b)
#define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)

#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__)
extern long (*__kernel_vsyscall)(long, long, long, long, long, long, long);

#define uk_syscall_0(syscall_nr) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long))__kernel_vsyscall)(syscall_nr); \
} else { \
resultvar = __syscall0(syscall_nr); \
} \
(long int) resultvar; \
})

#define uk_syscall_1(syscall_nr, a) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long, long))__kernel_vsyscall)(syscall_nr, __scc(a)); \
} else { \
resultvar = __syscall1(syscall_nr, __scc(a)); \
} \
(long int) resultvar; \
})

#define uk_syscall_2(syscall_nr, a, b) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long, long, long))__kernel_vsyscall)(syscall_nr, __scc(a), __scc(b)); \
} else { \
resultvar = __syscall2(syscall_nr, __scc(a), __scc(b)); \
} \
(long int) resultvar; \
})

#define uk_syscall_3(syscall_nr, a, b, c) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long, long, long, long))__kernel_vsyscall)(syscall_nr, __scc(a), __scc(b), __scc(c)); \
} else { \
resultvar = __syscall3(syscall_nr, __scc(a), __scc(b), __scc(c)); \
} \
(long int) resultvar; \
})

#define uk_syscall_4(syscall_nr, a, b, c, d) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long, long, long, long, long))__kernel_vsyscall)(syscall_nr, __scc(a), __scc(b), __scc(c), __scc(d)); \
} else { \
resultvar = __syscall4(syscall_nr, __scc(a), __scc(b), __scc(c), __scc(d)); \
} \
(long int) resultvar; \
})

#define uk_syscall_5(syscall_nr, a, b, c, d, e) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long, long, long, long, long, long))__kernel_vsyscall)(syscall_nr, __scc(a), __scc(b), __scc(c), __scc(d), __scc(e)); \
} else { \
resultvar = __syscall5(syscall_nr, __scc(a), __scc(b), __scc(c), __scc(d), __scc(e)); \
} \
(long int) resultvar; \
})

#define uk_syscall_6(syscall_nr, a, b, c, d, e, f) \
({ \
unsigned long int resultvar; \
if (__builtin_expect(!!(__kernel_vsyscall), 1)) { \
resultvar = ((long(*)(long, long, long, long, long, long, long))__kernel_vsyscall)(syscall_nr, __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)); \
} else { \
resultvar = __syscall6(syscall_nr, __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)); \
} \
(long int) resultvar; \
})

#define __syscall(...) __SYSCALL_DISP(uk_syscall_,__VA_ARGS__)
#define syscall(...) __syscall_ret(__syscall(__VA_ARGS__))

#define socketcall(nm,a,b,c,d,e,f) __syscall_ret(__socketcall(nm,a,b,c,d,e,f))
#define socketcall_cp(nm,a,b,c,d,e,f) __syscall_ret(__socketcall_cp(nm,a,b,c,d,e,f))

#define __syscall_cp0(n) (__syscall_cp)(n,0,0,0,0,0,0)
#define __syscall_cp1(n,a) (__syscall_cp)(n,__scc(a),0,0,0,0,0)
#define __syscall_cp2(n,a,b) (__syscall_cp)(n,__scc(a),__scc(b),0,0,0,0)
#define __syscall_cp3(n,a,b,c) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),0,0,0)
#define __syscall_cp4(n,a,b,c,d) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),0,0)
#define __syscall_cp5(n,a,b,c,d,e) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),0)
#define __syscall_cp6(n,a,b,c,d,e,f) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f))
#define __syscall_cp0(n) uk_syscall_6(n,0,0,0,0,0,0)
#define __syscall_cp1(n,a) uk_syscall_6(n,__scc(a),0,0,0,0,0)
#define __syscall_cp2(n,a,b) uk_syscall_6(n,__scc(a),__scc(b),0,0,0,0)
#define __syscall_cp3(n,a,b,c) uk_syscall_6(n,__scc(a),__scc(b),__scc(c),0,0,0)
#define __syscall_cp4(n,a,b,c,d) uk_syscall_6(n,__scc(a),__scc(b),__scc(c),__scc(d),0,0)
#define __syscall_cp5(n,a,b,c,d,e) uk_syscall_6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),0)
#define __syscall_cp6(n,a,b,c,d,e,f) uk_syscall_6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f))

#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))
Expand Down Expand Up @@ -374,15 +445,15 @@ static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a,
#endif

#ifdef SYS_open
#define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE)
#define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open_cp2(x,pn,fl) __syscall_cp2(SYS_open, pn, (fl)|O_LARGEFILE)
#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open2(x,pn,fl) uk_syscall_2(SYS_open, pn, (fl)|O_LARGEFILE)
#define __sys_open3(x,pn,fl,mo) uk_syscall_3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open_cp2(x,pn,fl) uk_syscall_2(SYS_open, pn, (fl)|O_LARGEFILE)
#define __sys_open_cp3(x,pn,fl,mo) uk_syscall_3(SYS_open, pn, (fl)|O_LARGEFILE, mo)
#else
#define __sys_open2(x,pn,fl) __syscall3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
#define __sys_open3(x,pn,fl,mo) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open2(x,pn,fl) uk_syscall_3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
#define __sys_open3(x,pn,fl,mo) uk_syscall_4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
#define __sys_open_cp2(x,pn,fl) uk_syscall_3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE)
#define __sys_open_cp3(x,pn,fl,mo) uk_syscall_4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo)
#endif

#define __sys_open(...) __SYSCALL_DISP(__sys_open,,__VA_ARGS__)
Expand Down
8 changes: 8 additions & 0 deletions src/misc/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@ long syscall(long n, ...)
va_end(ap);
return __syscall_ret(__syscall(n,a,b,c,d,e,f));
}

long (*__kernel_vsyscall)(long, long, long, long, long, long, long) = NULL;

void uk_init_vsyscall(void) __attribute__((constructor));

void uk_init_vsyscall(void) {
__kernel_vsyscall = __vdsosym("LINUX_2.6", "__kernel_vsyscall");
}

0 comments on commit cdd7243

Please sign in to comment.