나는 이것을 x86_64에서 시도했다.
94836ecf1e7378b64d37624fbb81fe48fbd4c772에 대한 패치 : (또한 https://github.com/pskocik/linux/tree/supersyscall )
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 5aef183e2f85..8df2e98eb403 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -339,6 +339,7 @@
330 common pkey_alloc sys_pkey_alloc
331 common pkey_free sys_pkey_free
332 common statx sys_statx
+333 common supersyscall sys_supersyscall
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 980c3c9b06f8..c61c14e3ff4e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -905,5 +905,20 @@ asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
asmlinkage long sys_pkey_free(int pkey);
asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
unsigned mask, struct statx __user *buffer);
-
#endif
+
+struct supersyscall_args {
+ unsigned call_nr;
+ long args[6];
+};
+#define SUPERSYSCALL__abort_on_failure 0
+#define SUPERSYSCALL__continue_on_failure 1
+/*#define SUPERSYSCALL__lock_something 2?*/
+
+
+asmlinkage
+long
+sys_supersyscall(long* Rets,
+ struct supersyscall_args *Args,
+ int Nargs,
+ int Flags);
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index a076cf1a3a23..56184b84530f 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -732,9 +732,11 @@ __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc)
__SYSCALL(__NR_pkey_free, sys_pkey_free)
#define __NR_statx 291
__SYSCALL(__NR_statx, sys_statx)
+#define __NR_supersyscall 292
+__SYSCALL(__NR_supersyscall, sys_supersyscall)
#undef __NR_syscalls
-#define __NR_syscalls 292
+#define __NR_syscalls (__NR_supersyscall+1)
/*
* All syscalls below here should go away really,
diff --git a/init/Kconfig b/init/Kconfig
index a92f27da4a27..25f30bf0ebbb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2184,4 +2184,9 @@ config ASN1
inform it as to what tags are to be expected in a stream and what
functions to call on what tags.
+config SUPERSYSCALL
+ bool
+ help
+ System call for batching other system calls
+
source "kernel/Kconfig.locks"
diff --git a/kernel/Makefile b/kernel/Makefile
index b302b4731d16..4d86bcf90f90 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y = fork.o exec_domain.o panic.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
- async.o range.o smpboot.o ucount.o
+ async.o range.o smpboot.o ucount.o supersyscall.o
obj-$(CONFIG_MULTIUSER) += groups.o
diff --git a/kernel/supersyscall.c b/kernel/supersyscall.c
new file mode 100644
index 000000000000..d7fac5d3f970
--- /dev/null
+++ b/kernel/supersyscall.c
@@ -0,0 +1,83 @@
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/compiler.h>
+#include <linux/sched/signal.h>
+
+/*TODO: do this properly*/
+/*#include <uapi/asm-generic/unistd.h>*/
+#ifndef __NR_syscalls
+# define __NR_syscalls (__NR_supersyscall+1)
+#endif
+
+#define uif(Cond) if(unlikely(Cond))
+#define lif(Cond) if(likely(Cond))
+
+
+typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long, unsigned long);
+extern const sys_call_ptr_t sys_call_table[];
+
+static bool
+syscall__failed(unsigned long Ret)
+{
+ return (Ret > -4096UL);
+}
+
+
+static bool
+syscall(unsigned Nr, long A[6])
+{
+ uif (Nr >= __NR_syscalls )
+ return -ENOSYS;
+ return sys_call_table[Nr](A[0], A[1], A[2], A[3], A[4], A[5]);
+}
+
+
+static int
+segfault(void const *Addr)
+{
+ struct siginfo info[1];
+ info->si_signo = SIGSEGV;
+ info->si_errno = 0;
+ info->si_code = 0;
+ info->si_addr = (void*)Addr;
+ return send_sig_info(SIGSEGV, info, current);
+ //return force_sigsegv(SIGSEGV, current);
+}
+
+asmlinkage long /*Ntried*/
+sys_supersyscall(long* Rets,
+ struct supersyscall_args *Args,
+ int Nargs,
+ int Flags)
+{
+ int i = 0, nfinished = 0;
+ struct supersyscall_args args; /*7 * sizeof(long) */
+
+ for (i = 0; i<Nargs; i++){
+ long ret;
+
+ uif (0!=copy_from_user(&args, Args+i, sizeof(args))){
+ segfault(&Args+i);
+ return nfinished;
+ }
+
+ ret = syscall(args.call_nr, args.args);
+ nfinished++;
+
+ if ((Flags & 1) == SUPERSYSCALL__abort_on_failure
+ && syscall__failed(ret))
+ return nfinished;
+
+
+ uif (0!=put_user(ret, Rets+1)){
+ segfault(Rets+i);
+ return nfinished;
+ }
+ }
+ return nfinished;
+
+}
+
+
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 8acef8576ce9..c544883d7a13 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -258,3 +258,5 @@ cond_syscall(sys_membarrier);
cond_syscall(sys_pkey_mprotect);
cond_syscall(sys_pkey_alloc);
cond_syscall(sys_pkey_free);
+
+cond_syscall(sys_supersyscall);
그리고 그것은 작동하는 것처럼 보입니다. 단 하나의 syscall로 hello를 fd 1에, world를 fd 2에 쓸 수 있습니다 :
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
struct supersyscall_args {
unsigned call_nr;
long args[6];
};
#define SUPERSYSCALL__abort_on_failure 0
#define SUPERSYSCALL__continue_on_failure 1
long
supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags);
int main(int c, char**v)
{
puts("HELLO WORLD:");
long r=0;
struct supersyscall_args args[] = {
{SYS_write, {1, (long)"hello\n", 6 }},
{SYS_write, {2, (long)"world\n", 6 }},
};
long rets[sizeof args / sizeof args[0]];
r = supersyscall(rets,
args,
sizeof(rets)/sizeof(rets[0]),
0);
printf("r=%ld\n", r);
printf( 0>r ? "%m\n" : "\n");
puts("");
#if 1
#if SEGFAULT
r = supersyscall(0,
args,
sizeof(rets)/sizeof(rets[0]),
0);
printf("r=%ld\n", r);
printf( 0>r ? "%m\n" : "\n");
#endif
#endif
return 0;
}
long
supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags)
{
return syscall(333, Rets, Args, Nargs, Flags);
}
기본적으로 나는 다음을 사용하고 있습니다 :
long a_syscall(long, long, long, long, long, long);
x86_64에서 작동하는 방식으로 보이는 범용 syscall 프로토 타입으로, "슈퍼"syscall은 다음과 같습니다.
struct supersyscall_args {
unsigned call_nr;
long args[6];
};
#define SUPERSYSCALL__abort_on_failure 0
#define SUPERSYSCALL__continue_on_failure 1
/*#define SUPERSYSCALL__lock_something 2?*/
asmlinkage
long
sys_supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags);
그것은 (시도 콜의 수를 반환하는 ==Nargs
경우 생성 SUPERSYSCALL__continue_on_failure
그렇지 않으면, 플래그가 전달됩니다 >0 && <=Nargs
)과 실패는 커널 공간과 사용자 공간 대신 보통의 세그먼테이션 폴트 (segfault)에 의해 신호하는 사이에 복사합니다 -EFAULT
.
내가 모르는 것은 이것이 다른 아키텍처로 포팅되는 방법이지만 커널에서 이와 같은 것을 갖는 것이 좋을 것입니다.
이것이 모든 아치에서 가능하다면, 일부 공용체와 매크로를 통해 유형 안전을 제공하는 사용자 공간 래퍼가있을 수 있다고 생각합니다 (syscall 이름을 기반으로 공용체 멤버를 선택할 수 있으며 모든 공용체가 6 long으로 변환됩니다) 또는 아키텍처가 6 long과 동등한 것이 무엇이든간에).
batch
syscall을batch
syscall에 내포 하면 임의의 syscall로 임의로 깊은 호출 트리를 만들 수 있습니다. 기본적으로 전체 응용 프로그램을 단일 syscall에 넣을 수 있습니다.