syscalls-by-name (aka dynamic syscalls / vsyscalls)
Subsystems (2)
RFC 1/1 syscalls-by-name (aka dynamic syscalls / vsyscalls)
The attached patch implements syscalls-by-name in an initial and rather crud method -- the x86isms need tidying up, but the technique is usable across platforms. Syscalls provided by name are made available to userland by means of a dynamic shared library that maps and provides a jumptable into a set of vsyscalls. The vsyscalls can then enter the kernel through whatever mechanism (the only means implemented right now is via a new syscall, sys_dynamic_syscall) the kernel choses. Version mismatch between the kernel and the library is prevented by means of a unique fingerprint the library checks on load against what the kernel provides via /dev/vsys.
/dev/vsys is a simple device node that allows user code to map the vsyscall area into their address space. This is different from the fixed address that x86-64 uses to allow UML emulation of vsyscalls, and prevent other problems that could crop up with the intrusion of unexpected code into user address space.
For a quick example on how a new syscall is declared, I added the following lines into fs/aio.c in the aio patch:
#include <asm/vsyscall.h> ... rest of file ... add_dynamic_syscall(sys_io_setup); add_dynamic_syscall(sys_io_destroy); add_dynamic_syscall(sys_io_submit); add_dynamic_syscall(sys_io_cancel); add_dynamic_syscall(sys_io_wait); add_dynamic_syscall(sys_io_getevents);
Similarly, vsyscalls can be added by means of adding an attribute to a function declaration that puts the code into the VSYSCALL segment. This segment is linked at a virtual address just above the top of the default user stack, but is kept within the kernel image and mapped via /dev/vsys.
My current todos on the code are to clean it up so that the arch specific parts are better seperated, add symbol versions, and resurrect the sysenter / sysexit code as the means of entering the dynamic syscalls. There's also TSC based gettimeofday() code to finish off and add...
The patch is against 2.4.9-acsomething + aio + stuff, but should be pretty easy to merge into recent kernels. If anyone has any comments or tweaks, I'd like to hear about them. Cheers,
-ben
:r ~/syscall-by-name-A4.diff
Makefile +10 -4
@@ -236,7 +236,7 @@ drivers/sound/pndsperm.c \ drivers/sound/pndspini.c \ drivers/atm/fore200e_*_fw.c drivers/atm/.fore200e_*.fw \ - .version .config* config.in config.old \ + .uniquebytes .version .config* config.in config.old \ scripts/tkparse scripts/kconfig.tk scripts/kconfig.tmp \ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ .menuconfig.log \
@@ -283,6 +283,7 @@ vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o linuxsubdirs @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" kallsyms + @$(MAKE) -C ulib .PHONY: kallsyms
@@ -332,14 +333,17 @@ linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) -$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER +$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/compile.h include/config/MARKER $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@) $(TOPDIR)/include/linux/version.h: include/linux/version.h $(TOPDIR)/include/linux/compile.h: include/linux/compile.h newversion: - . scripts/mkversion > .version + . scripts/mkversion > .tmpversion + @mv -f .tmpversion .version + rm -f .uniquebytes + dd if=/dev/urandom of=.uniquebytes bs=1 count=16 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver
@@ -357,9 +361,10 @@ echo \#define LINUX_COMPILE_DOMAIN ; \ fi >> .ver @echo \#define LINUX_COMPILER \"`$(CC) $(CFLAGS) -v 2>&1 | tail -1`\" >> .ver + @echo \#define LINUX_UNIQUE_BYTES `hexdump -e '1/1 "0x%02x, "' .uniquebytes | sed -e 's/, \$$//g'` >>.ver @mv -f .ver $@ -include/linux/version.h: ./Makefile include/linux/autoconf.h +include/linux/version.h: ./Makefile include/linux/autoconf.h @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver @echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
@@ -453,6 +458,7 @@ rm -f $(CLEAN_FILES) rm -rf $(CLEAN_DIRS) $(MAKE) -C Documentation/DocBook clean + $(MAKE) -C ulib clean mrproper: clean archmrproper find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
arch/i386/Makefile +1 -1
@@ -127,7 +127,7 @@ zlilo: vmlinux @$(MAKEBOOT) BOOTIMAGE=zImage zlilo -tmp: +tmp: ulib @$(MAKEBOOT) BOOTIMAGE=bzImage zlilo bzlilo: vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage zlilo
arch/i386/kernel/Makefile +2 -2
@@ -23,8 +23,7 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \ - bootflag.o - + bootflag.o vsysdata.o vunique.o dynamic_syscall.o ifdef CONFIG_PCI obj-y += pci-i386.o
@@ -53,3 +52,4 @@ abi-machdep.o: $(abi-machdep-objs) $(LD) -r -o $@ $(abi-machdep-objs) +
arch/i386/kernel/dynamic_syscall.c +66 -0
66 lines not on this page · raw message
arch/i386/kernel/entry.S +6 -0
@@ -46,6 +46,7 @@ #include <asm/segment.h> #define ASSEMBLY #include <asm/smp.h> +#include <asm/unistd.h> EBX = 0x00 ECX = 0x04
@@ -635,6 +636,11 @@ # endif #endif + .rept __NR_sys_dynamic_syscall-(.-sys_call_table)/4 + .long SYMBOL_NAME(sys_ni_syscall) + .endr + .long SYMBOL_NAME(sys_dynamic_syscall) + /* More patch resilient means of adding syscalls */ .rept 244-(.-sys_call_table)/4 .long SYMBOL_NAME(sys_ni_syscall)
arch/i386/kernel/vsysdata.c +11 -0
@@ -0,0 +1,11 @@ +/* vsysdata.c - declarations for variables shared with the kernel +* +* Items placed in .data.vsyscall have a kernel virtual address +* and are read/write from kernel space only. The copy placed +* in .vsyscall_data are linked at a userspace address and are +* read only accessible from userland. +*/ +#include <linux/vsyscall.h> + +union vsys_union user_vsys_cpudata[256] __attribute__((section(".vsyscall_data"))); +//asm(".globl vsys_cpudata ; bobbob = user_vsys_cpudata - vsyscall_text_begin ; vsys_cpudata = bobbob + VSYSCALL_text");
arch/i386/kernel/vunique.S +7 -0
@@ -0,0 +1,7 @@ +#include <linux/compile.h> + + .section .first_vsyscall_text,"xa" + .globl signature +signature: + .byte LINUX_UNIQUE_BYTES + .size signature,.-signature
arch/i386/vmlinux.lds +41 -1
63 lines not on this page · raw message
arch/i386/vmlinux.lds.S +46 -0
62 lines not on this page · raw message
drivers/char/mem.c +77 -1
102 lines not on this page · raw message
include/asm-i386/a.out.h +3 -1
@@ -19,7 +19,9 @@#ifdef __KERNEL__ -#define STACK_TOP TASK_SIZE +#define VSYSCALL_SIZE 0x10000/* 64KB for vsyscalls */ +#define STACK_GUARD_SIZE 0x02000/* 8KB guard area */ +#define STACK_TOP (TASK_SIZE - VSYSCALL_SIZE - STACK_GUARD_SIZE)#endif
include/asm-i386/unistd.h +2 -0
@@ -228,6 +228,8 @@#define __NR_getdents64 220#define __NR_fcntl64 221 +#define __NR_sys_dynamic_syscall 230 +/* gap here for now */ #define __NR_io_setup 244#define __NR_io_destroy 245
include/asm-i386/vsyscall.h +41 -0
41 lines not on this page · raw message
include/linux/vsyscall.h +20 -0
@@ -0,0 +1,20 @@ +#ifndef _LINUX__VSYSCALL_H +#define _LINUX__VSYSCALL_H + +struct vsys_cpudata { +unsigned long context_switches; +unsigned long tv_sec; +unsigned long tsc_low, tsc_high; +unsigned long cycles_per_sec; +}; + +union vsys_union { +struct vsys_cpudata data; +char pad[128 ]; +}; + +extern union vsys_union vsys_cpudata[256] __attribute__((section(".data.vsyscall"))); + +#define vsys_data (cpu) (&vsys_cpudata[cpu].data) + +#endif /*ndef _LINUX__VSYSCALL_H*/
ulib/Makefile +26 -0
@@ -0,0 +1,26 @@ +all: libkernel.so + +ASFLAGS=-D__KERNEL__ -D__ASSEMBLY__ -I../include -nostdlib -nostartfiles +CFLAGS=-D__KERNEL__ -I../include -nostdlib -nostartfiles + +vsysaddr.S: ../System.map stub.S Makefile + rm -f vsysaddr.S + echo '#include "stub.S"' >vsysaddr.S + awk -- "/^bfff.* vsys_/ { print \"dynamic_syscall(\"\$$3 \",0x\" \$$1 \")\"; }" <../System.map >>vsysaddr.S + +vsysaddr.o: vsysaddr.S + +kso_init.o: ../include/linux/compile.h + +libkernel.so.1: vsysaddr.o kso_init.o + ld -E -symbolic -shared -soname=libkernel.so -o $@ vsysaddr.o kso_init.o + +libkernel.so: libkernel.so.1 + ln -sf $< $@ + +clean: + rm -f *.o libkernel.so myln libkernel.so.1 vsysaddr.S + +# test app +myln: myln.c libkernel.so Makefile + cc -g -o myln myln.c -L. -lkernel
ulib/kso_init.c +48 -0
48 lines not on this page · raw message
ulib/myln.c +25 -0
@@ -0,0 +1,25 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> + +int main () +{ +long ctx =0 ; +extern long vsys_io_setup (long ,long *); +unsigned char *bob = (void *)&vsys_io_setup; +long ret; +int i; +printf ("%p\n" , bob); +//printf("%p\n", mmap(0, 65536, PROT_READ | PROT_EXEC, MAP_SHARED, +// open("/dev/vsys", O_RDONLY), 0)); +//for (i=0; i<16; i++) +// printf(" %02x\n", bob[i]); +//printf("\n"); + + ret =vsys_io_setup (100 , &ctx); + +printf ("ret=%ld, ctx=0x%lx\n" , ret, ctx); +return 0 ; +}
ulib/stub.S +18 -0
@@ -0,0 +1,18 @@ +/* stub.S */ +#include <asm/segment.h> +#include <asm/errno.h> + + .text + +#define dynamic_syscall(x,a) \ + .globl x ;\ + .align 16 ;\ + x: ;\ + cmpb $0,libkernel_enosys ;\ + jne 1f ;\ + ljmp $__USER_CS, $a ;\ + 1: ;\ + movl $-ENOSYS,%eax ;\ + ret ;\ + .size x,.-x +
Quoted 4 lines · Benjamin LaHaise
The attached patch implements syscalls-by-name [...]
If anyone has any comments [...]
Don't miss the wood for the trees.
Ciao, ET.
So, will this need recompilling only glibc?
Best regards.