Logo Search packages:      
Sourcecode: samhain version File versions  Download package

sh_kern.c

/* SAMHAIN file system integrity testing                                   */
/* Copyright (C) 2001 Rainer Wichmann                                      */
/*                                                                         */
/*  This program is free software; you can redistribute it                 */
/*  and/or modify                                                          */
/*  it under the terms of the GNU General Public License as                */
/*  published by                                                           */
/*  the Free Software Foundation; either version 2 of the License, or      */
/*  (at your option) any later version.                                    */
/*                                                                         */
/*  This program is distributed in the hope that it will be useful,        */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*  GNU General Public License for more details.                           */
/*                                                                         */
/*  You should have received a copy of the GNU General Public License      */
/*  along with this program; if not, write to the Free Software            */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */


#include "config_xor.h"

#define SH_SYSCALL_CODE

#ifdef HOST_IS_I86LINUX
#define SH_IDT_TABLE
#define SH_PROC_CHECK
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/wait.h>
#include <signal.h>


#ifdef SH_USE_KERN

#undef  FIL__
#define FIL__  _("sh_kern.c")

#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) 

#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif


#include "samhain.h"
#include "sh_utils.h"
#include "sh_error.h"
#include "sh_modules.h"
#include "sh_kern.h"
#include "sh_ks_xor.h"

#include "sh_unix.h"
#include "sh_hash.h"



sh_rconf sh_kern_table[] = {
  {
    N_("severitykernel"),
    sh_kern_set_severity
  },
  {
    N_("kernelcheckactive"),
    sh_kern_set_activate
  },
  {
    N_("kernelcheckinterval"),
    sh_kern_set_timer
  },
  {
    N_("kernelcheckidt"),
    sh_kern_set_idt
  },
  {
    N_("kernelsystemcall"),
    sh_kern_set_sc_addr
  },
  {
    N_("kernelsyscalltable"),
    sh_kern_set_sct_addr
  },
  {
    N_("kernelprocrootlookup"),
    sh_kern_set_proc_root_lookup
  },
 {
    N_("kernelprocrootiops"),
    sh_kern_set_proc_root_iops
  },
  {
    N_("kernelprocroot"),
    sh_kern_set_proc_root
  },
  {
    NULL,
    NULL
  },
};


static time_t  lastcheck;
static int     ShKernActive   = S_TRUE;
static int     ShKernInterval = 300;
static int     ShKernSeverity = SH_ERR_SEVERE;
static int     ShKernDelay    = 100; /* milliseconds */
static int     ShKernIDT      = S_TRUE;

/* The address of system_call
 */
#ifdef SH_SYS_CALL_ADDR
static unsigned long system_call_addr = SH_SYS_CALL_ADDR;
#else
static unsigned long system_call_addr = 0;
#endif

/* The address of the sys_call_table
 */
#ifdef SH_SYS_CALL_TABLE
static unsigned int  kaddr = SH_SYS_CALL_TABLE;
#else
static unsigned int  kaddr = 0;
#endif

#ifdef PROC_ROOT_LOC
static unsigned long proc_root = PROC_ROOT_LOC;
#else
static unsigned long proc_root = 0;
#endif
#ifdef PROC_ROOT_IOPS_LOC
static unsigned long proc_root_iops = PROC_ROOT_IOPS_LOC;
#else
static unsigned long proc_root_iops = 0;
#endif
#ifdef PROC_ROOT_LOOKUP_LOC
static unsigned long proc_root_lookup = PROC_ROOT_LOOKUP_LOC;
#else
static unsigned long proc_root_lookup = 0;
#endif

int sh_kern_null()
{
  return 0;
}

#ifdef SH_IDT_TABLE

#include <asm/segment.h>

#define SH_MAXIDT   256
unsigned char sh_idt_table[SH_MAXIDT * 8];
char * sh_strseg(unsigned short segment)
{
  switch (segment) {
  case __KERNEL_CS:
    return _("KERNEL_CS");
  case __KERNEL_DS:
    return _("KERNEL_DS");
  case __USER_CS:
    return _("USER_CS");
  case __USER_DS:
    return _("USER_DS");
  default:
    return _("unknown");
  }
}
/* ifdef SH_IDT_TABLE */
#endif

static char * sh_kern_charhex( unsigned char i )
{
  static char i2h[2];
  int j, k;

  j = i / 16;
  k = i - (j*16);

  if (j < 10) i2h[0] = '0'+j;
  else        i2h[0] = 'A'+(j-10);
  
  if (k < 10) i2h[1] = '0'+k;
  else        i2h[1] = 'A'+(k-10);

  return i2h;
}

static void sh_kern_push2db (char * name, unsigned long addr, 
                       unsigned long code1, unsigned long code2,
                       unsigned char * code, int size)
{
  file_type   tmpFile;
  int         i = 0;
  char      * p;

  sl_strlcpy(tmpFile.fullpath, name, PATH_MAX);
  tmpFile.size  = addr;
  tmpFile.mtime = code1;
  tmpFile.ctime = code2;

  tmpFile.atime = 0;
  tmpFile.mode  = 0;
  tmpFile.owner = 0;
  tmpFile.group = 0;
  sl_strlcpy(tmpFile.c_owner, _("root"), 5);
  sl_strlcpy(tmpFile.c_group, _("root"), 5);

  if ((code != NULL) && (size < (PATH_MAX/2)-1))
    {
      tmpFile.c_mode[0] = 'l';  
      tmpFile.c_mode[1] = 'r'; tmpFile.c_mode[2]  = 'w';
      tmpFile.c_mode[3] = 'x'; tmpFile.c_mode[4]  = 'r'; 
      tmpFile.c_mode[5] = 'w'; tmpFile.c_mode[6]  = 'x'; 
      tmpFile.c_mode[7] = 'r'; tmpFile.c_mode[8]  = 'w'; 
      tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0'; 
      for (i = 0; i < size; ++i)
      {
        p = sh_kern_charhex (code[i]);
        tmpFile.linkpath[2*i]   = p[0];
        tmpFile.linkpath[2*i+1] = p[1];
        tmpFile.linkpath[2*i+2] = '\0';
      }
    }
  else
    {
      tmpFile.c_mode[0] = '-';  
      tmpFile.c_mode[1] = '-'; tmpFile.c_mode[2]  = '-';
      tmpFile.c_mode[3] = '-'; tmpFile.c_mode[4]  = '-'; 
      tmpFile.c_mode[5] = '-'; tmpFile.c_mode[6]  = '-'; 
      tmpFile.c_mode[7] = '-'; tmpFile.c_mode[8]  = '-'; 
      tmpFile.c_mode[9] = '-'; tmpFile.c_mode[10] = '\0'; 
      tmpFile.linkpath[0] = '-'; tmpFile.linkpath[1] = '\0';
    }

  sh_hash_pushdata (&tmpFile, 
                _("000000000000000000000000000000000000000000000000"));
  return;
}

extern int sh_util_hextobinary (char * binary, char * hex, int bytes);

static char * sh_kern_db2pop (char * name, unsigned long * addr, 
                        unsigned long * code1, unsigned long * code2,
                        int * size)
{
  file_type   tmpFile;
  char      * p;
  int         i;

  if (0 == sh_hash_get_it (name, &tmpFile))
    {
      *addr  = tmpFile.size;
      *code1 = tmpFile.mtime;
      *code2 = tmpFile.ctime;

      if (tmpFile.linkpath[0] != '-')
      {
        p = SH_ALLOC(PATH_MAX);
        i = sh_util_hextobinary (p, tmpFile.linkpath, 
                           strlen(tmpFile.linkpath));
        if (i == 0)
          {
            *size = (strlen(tmpFile.linkpath)/2);
            p[*size] = '\0';
            return p;
          }
        else
          {
            SH_FREE(p);
            *size = 0;
            return NULL;
          }
      }
      else
      {
        *size = 0;
        return NULL;
      }
    }
  else
    {
      *size = 0;
      *addr = 0;
      return NULL;
    }
}

char * sh_kern_db_syscall (int num, char * prefix,
                     void * in_name, unsigned long * addr,
                     unsigned int * code1, unsigned int * code2,
                     int * size, int direction)
{
  char          path[128];
  char        * p = NULL;
  unsigned long x1, x2;
  char        * name = (char *) in_name;

  sl_snprintf(path, 128, "K_%s_%04d", prefix, num);

  if (direction == 0) 
    {
      x1 = *code1;
      x2 = *code2;

      sh_kern_push2db (path, *addr, x1, x2,
                   name, (name == NULL) ? 0 : (*size));
    }
  else
    {
      p = sh_kern_db2pop (path, addr,  &x1, &x2, size);
      *code1 = (unsigned int) x1;
      *code2 = (unsigned int) x2;
    }
  return p;
}
 
#ifdef HOST_IS_LINUX

int sh_kern_data_init ()
{
  unsigned long store0 = 0;
  unsigned int  store1 = 0, store2 = 0;
  int           datasize, i, j;
  char        * databuf;

#ifdef SH_SYSCALL_CODE
  /* system_call code
   */
  databuf = sh_kern_db_syscall (0, _("system_call"), 
                        NULL, &store0, &store1, &store2,
                        &datasize, 1);
  if (datasize == sizeof(system_call_code))
    {
      memcpy (system_call_code, databuf, sizeof(system_call_code));
      SH_FREE(databuf);
    }
  else
    {
      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                  _("system_call_code not found in database"), 
                  _("sh_kern_data_init"));
      return -1;
    }
#endif

  /* syscall address and code
   */ 
  for (i = 0; i < SH_MAXCALLS; ++i) 
    {
      databuf = sh_kern_db_syscall (i, _("syscall"), 
                            NULL, &store0, &store1, &store2,
                            &datasize, 1);
      sh_syscalls[i].addr = store0;
      if (store0 == 0) {
      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                  _("syscall address not found in database"), 
                  _("sh_kern_data_init"));
      return -1;
      }
#ifdef SH_SYSCALL_CODE
      sh_syscalls[i].code[0] = (unsigned int) store1; 
      sh_syscalls[i].code[1] = (unsigned int) store2;
      if ((store1 == 0) || (store2 == 0)) {
      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                  _("syscall code not found in database"), 
                  _("sh_kern_data_init"));
      /* fprintf(stderr, "Syscall #%d\n", i); */
      /* return -1; */
      }
#endif 
      if (databuf != NULL) {
      SH_FREE(databuf);
      }
      
    }

#ifdef SH_IDT_TABLE
  if (ShKernIDT == S_TRUE)
    {
      for (j = 0; j < SH_MAXIDT; ++j) 
      {
        databuf = sh_kern_db_syscall (j, _("idt_table"), 
                              NULL, 
                              &store0, &store1, &store2,
                              &datasize, 1);
        if (datasize == 8) {
          memcpy(&idt_table[j*8], databuf, 8);
          SH_FREE(databuf);
        } else {
          sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                      _("idt table not found in database"), 
                      _("sh_kern_data_init"));
          return -1;
        }
      }
    }
#endif

  return 0;
}

#ifdef SH_PROC_CHECK
struct inode_operations {
  int (*create) (int *,int *,int);
  int * (*lookup) (int *,int *);
  int (*link) (int *,int *,int *);
  int (*unlink) (int *,int *);
  int (*symlink) (int *,int *,const char *);
  int (*mkdir) (int *,int *,int);
  int (*rmdir) (int *,int *);
  int (*mknod) (int *,int *,int,int);
  int (*rename) (int *, int *,
                 int *, int *);
  int (*readlink) (int *, char *,int);
  int (*follow_link) (int *, int *);
  void (*truncate) (int *);
  int (*permission) (int *, int);
  int (*revalidate) (int *);
  /*
    int (*setattr) (int *, int *);
    int (*getattr) (int *, int *);
    int (*setxattr) (int *, const char *, void *, size_t, int);
    ssize_t (*getxattr) (int *, const char *, void *, size_t);
    ssize_t (*listxattr) (int *, char *, size_t);
    int (*removexattr) (int *, const char *);
  */
};

struct file_operations {
  int (*create) (int *,int *,int);
};

struct proc_dir_entry {
  unsigned short low_ino;
  unsigned short namelen;
  const char * name;
  mode_t mode;
  nlink_t nlink;
  uid_t uid;
  gid_t gid;
  unsigned long size; 
  struct inode_operations * proc_iops;
  struct file_operations * proc_fops;
  /*
  get_info_t *get_info;
  struct module *owner;
  struct proc_dir_entry *next, *parent, *subdir;
  void *data;
  read_proc_t *read_proc;
  write_proc_t *write_proc;
  atomic_t count;         
  int deleted;  
  */          
};
#endif

int sh_kern_check_internal ()
{
  static int is_init = 0;
  int kd;
  int res;
  pid_t mpid;
  int mpipe[2];
  int i, j, status = 0;
  /* unsigned int kaddr; */
  unsigned long kmem_call_table[512];

#ifdef SH_PROC_CHECK
  struct inode_operations proc_root_inode;
  struct proc_dir_entry proc_root_dir;
#endif

#ifdef SH_SYSCALL_CODE
  unsigned int kmem_code_table[512][2];
#endif
#ifdef SH_IDT_TABLE
  unsigned char  buf[6];
  unsigned short idt_size;
  unsigned long  idt_addr;
  /* int            k, curr_keep = 0; */
  unsigned short idt_offset_lo, idt_offset_hi, idt_selector;
  unsigned char  idt_reserved, idt_flag;
  unsigned short sh_idt_offset_lo, sh_idt_offset_hi, sh_idt_selector;
  unsigned char  sh_idt_reserved, sh_idt_flag;
  int            dpl;
  unsigned long  idt_iaddr;
  int            sh_dpl;
  unsigned long  sh_idt_iaddr;
  char           idt_type, sh_idt_type;
#endif

  unsigned char new_system_call_code[256];

#ifdef SH_USE_LKM
  static int check_getdents      = 0;
  /* #ifdef __NR_getdents64 */
  static int check_getdents64    = 0;
  /* #endif */
  static int copy_if_next        = -1;
  static int copy_if_next_64     = -1;
#endif

  unsigned long store0;
  unsigned int  store1, store2;
  int           datasize;
  int           mod_syscall_addr = 0;
  int           mod_syscall_code = 0;
  UINT64        size_old  = 0, size_new = 0;
  UINT64        mtime_old = 0, mtime_new = 0;
  UINT64        ctime_old = 0, ctime_new = 0;
  char          tmp[128];
  char          msg[2*SH_BUFSIZE];
  char timstr_o[32];
  char timstr_n[32];
  char * p;
  int    k;
  char * linkpath_old;
  char * linkpath_new;

  int           max_system_call = (SYS_CALL_LOC < 128) ? 128 : SYS_CALL_LOC;

  SL_ENTER(_("sh_kern_check_internal"));

  
  if (is_init == 0)
    {
      if (sh.flag.checkSum != SH_CHECK_INIT)
      {
        if (0 == sh_kern_data_init()) {
          is_init = 1;
        } else {
          sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, 
                       MSG_E_SUBGEN,
                       _("could not initialize - switching off"),
                       _("kern_check_internal") );
          ShKernActive = S_FALSE;
          SL_RETURN( (-1), _("sh_kern_check_internal"));
        }
      }
      else if ((sh.flag.checkSum == SH_CHECK_INIT) && 
             (sh.flag.update == S_TRUE))
      {
        if (0 == sh_kern_data_init()) {
          is_init = 1;
        } else {
          sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, status, 
                       MSG_E_SUBGEN,
                       _("no or incomplete data in baseline database"),
                       _("kern_check_internal") );
        }
      }
    }

  /*
   * kaddr is the address of the sys_call_table
   */

  if (kaddr == (unsigned int) -1)
    {
      sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN,
                   _("no address for sys_call_table - switching off"),
                   _("kern_check_internal") );
      ShKernActive = S_FALSE;
      SL_RETURN( (-1), _("sh_kern_check_internal"));
    }
  
  kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/dev/kmem"), O_RDONLY, 0);
  
  if (kd < 0)
    {
      status = errno;
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                   _("error opening /dev/kmem"),
                   _("kern_check_internal") );
      SL_RETURN( (-1), _("sh_kern_check_internal"));
    }

  status = aud_pipe(FIL__, __LINE__, mpipe);

  if (status == 0)
    {
      mpid = aud_fork(FIL__, __LINE__);

      switch (mpid) 
      {
      case -1:
        status = -1;
        break;
      case 0:                       /* child */
        status = close(mpipe[0]);
        setpgid(0, 0);
        
        /* Seek to the system call table (at kaddr) and read it into
         * the kmem_call_table array
         */
        if(status == 0)
          {
            if(lseek(kd, (off_t)kaddr, SEEK_SET) == -1)
            {
              status = -2;
            }
          }
        if(status == 0)
          {
            retry_msleep (0, ShKernDelay); /* milliseconds */
            if (sizeof(kmem_call_table) != 
              read(kd, &kmem_call_table, sizeof(kmem_call_table)))
            {
              status = -3;
            }
          }

#ifdef SH_SYSCALL_CODE
        /* 
         * Seek to the system call address (at sh_syscalls[j].addr) and 
         * read first 8 bytes into kmem_code_table[j][] (2 * unsigned int)
         */
        if(status == 0)
          {
            memset(kmem_code_table, 0, sizeof(kmem_code_table));
            for (j = 0; j < SH_MAXCALLS; ++j) 
            {

              if (sh_syscalls[j].addr == 0UL) {
                sh_syscalls[j].addr = kmem_call_table[j];
              }

              if (sh_syscalls[j].name == NULL || 
                  sh_syscalls[j].addr == 0UL)
                break;

              if ((sh.flag.checkSum == SH_CHECK_INIT) && 
                  (sh.flag.update == S_TRUE))
                {
                  lseek (kd, kmem_call_table[j], SEEK_SET);
                }
              else
                {
                  lseek (kd, sh_syscalls[j].addr, SEEK_SET);
                }
              read  (kd, &(kmem_code_table[j][0]), 
                   2 * sizeof(unsigned int));
            }
          }
#endif

#ifdef SH_IDT_TABLE
        if(status == 0)
          {
            /* 
             * Get the address and size of Interrupt Descriptor Table,
             * and read the content into sh_idt_table[]
             */
            __asm__ volatile ("sidt %0": "=m" (buf));
            idt_size = *((unsigned short *) &buf[0]);
            idt_addr = *((unsigned long *)  &buf[2]);
            idt_size = (idt_size + 1)/8;

            if (idt_size > SH_MAXIDT)
            idt_size = SH_MAXIDT;

            memset(sh_idt_table, '\0', SH_MAXIDT*8);
            lseek (kd, idt_addr, SEEK_SET);
            read  (kd, sh_idt_table, idt_size*8);
          }
#endif

        /* 
         * Seek to the system_call address (at system_call_addr) and 
         * read first 256 bytes into new_system_call_code[]
         *
         * system_call_addr is defined in the include file.
         */
        if(status == 0)
          {
            lseek (kd, system_call_addr, SEEK_SET);
            read  (kd, new_system_call_code, 256);
          }


        /* 
         * Seek to proc_root and read the structure.
         * Seek to proc_root_inode_operations and get the structure.
         */
#ifdef SH_PROC_CHECK
        if(status == 0)
          {
            lseek (kd, proc_root, SEEK_SET);
            read  (kd, &proc_root_dir, sizeof(proc_root_dir));
            lseek (kd, proc_root_iops, SEEK_SET);
            read  (kd, &proc_root_inode, sizeof(proc_root_inode));
          }
#endif

        if(status == 0)
          {
            status = 
            write(mpipe[1], &kmem_call_table, sizeof(kmem_call_table));
#ifdef SH_SYSCALL_CODE
            if(status > 0)
            {
              status = 
                write(mpipe[1], &kmem_code_table, sizeof(kmem_code_table));
            }
#endif
#ifdef SH_IDT_TABLE
            if(status > 0)
            {
              status = 
                write(mpipe[1], &sh_idt_table, sizeof(sh_idt_table));
            }
#endif
            if(status > 0)
            {
              status = 
                write(mpipe[1], new_system_call_code, 256);
            }
#ifdef SH_PROC_CHECK
            if(status > 0)
            {
              status = 
                write(mpipe[1], &proc_root_dir, sizeof(proc_root_dir));
            }
            if(status > 0)
            {
              status = 
                write(mpipe[1], &proc_root_inode, sizeof(proc_root_inode));
            }
#endif
          }
        _exit( (status >= 0) ? 0 : status);
        break;
        
      default:
        close (mpipe[1]);
        close (kd);
        retry_msleep (0, ShKernDelay); /* milliseconds */
        if (sizeof(kmem_call_table) != 
            read(mpipe[0], &kmem_call_table, sizeof(kmem_call_table)))
          status = -4;
        else
          status = 0;

#ifdef SH_SYSCALL_CODE
        if(status == 0)
          {
            if (sizeof(kmem_code_table) != 
              read(mpipe[0], &kmem_code_table, sizeof(kmem_code_table)))
            status = -5;
            else
            status = 0;
          }
#endif        

#ifdef SH_IDT_TABLE
        if(status == 0)
          {
            memset(sh_idt_table, '\0', SH_MAXIDT*8);
            if (sizeof(sh_idt_table) != 
              read(mpipe[0], &sh_idt_table, sizeof(sh_idt_table)))
            status = -5;
            else
            status = 0;
          }
#endif        

        if(status == 0)
          {
            if (256 != read(mpipe[0], new_system_call_code, 256))
            status = -6;
            else
            status = 0;
          }

#ifdef SH_PROC_CHECK
        if(status == 0)
          {
            if (sizeof(proc_root_dir) !=
              read(mpipe[0], &proc_root_dir, sizeof(proc_root_dir)))
            status = -7;
            else
            status = 0;
          }
        if(status == 0)
          {
            if (sizeof(proc_root_inode) !=
              read(mpipe[0], &proc_root_inode, sizeof(proc_root_inode)))
            status = -8;
            else
            status = 0;
          }
#endif

        if (status < 0)
          res = waitpid(mpid, NULL,    WNOHANG|WUNTRACED);
        else 
          {
            res = waitpid(mpid, &status, WNOHANG|WUNTRACED);
            if (res == 0 && 0 != WIFEXITED(status))
            status = WEXITSTATUS(status);
          }
        close (mpipe[0]);
        if (res <= 0)
          {
            aud_kill(FIL__, __LINE__, mpid, 9);
            waitpid(mpid, NULL, 0);
          }
        break;
      }
    }

  if ( status < 0)
    {
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                   _("error reading from /dev/kmem"),
                   _("kern_check_internal") );
      SL_RETURN( (-1), _("sh_kern_check_internal"));
    }

  /* Check the proc_root inode.
   *
   * This will detect adore-ng.
   */
  if ( (unsigned int) *proc_root_inode.lookup != proc_root_lookup)
    {
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
                   _("proc_root_inode_operations.lookup != proc_root_lookup"));
    }
  else if ( ( ((unsigned int) * &proc_root_dir.proc_iops) != proc_root_iops) &&
       (proc_root_dir.size != proc_root_iops))
    {
      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
                   _("proc_root.proc_iops != proc_root_inode_operations"));
    }

  /* Check the system_call syscall gate.
   *
   * Stored(old) is system_call_code[]
   */
  if (sh.flag.checkSum == SH_CHECK_INIT)
    {
      store0 = 0; store1 = 0; store2 = 0;
      datasize = sizeof(system_call_code);
      sh_kern_db_syscall (0, _("system_call"), 
                    new_system_call_code, &store0, &store1, &store2,
                    &datasize, 0);
    }

  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
      (sh.flag.update == S_TRUE && is_init == 1))
    {
      for (i = 0; i < (max_system_call + 4); ++i) 
      {
        if (system_call_code[i] != new_system_call_code[i])
          {
#ifdef SH_USE_XML
            sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
                    _("system_call"), 0);
#else
            sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
                    _("system_call"), 0);
#endif
            sl_strlcpy(msg, tmp, SH_BUFSIZE);

            linkpath_old = SH_ALLOC(520);
            linkpath_new = SH_ALLOC(520);
            for (k = 0; k < 256; ++k)
            {
              p = sh_kern_charhex (system_call_code[k]);
              linkpath_old[2*k]   = p[0];
              linkpath_old[2*k+1] = p[1];
              linkpath_old[2*k+2] = '\0';
            }
            for (k = 0; k < 256; ++k)
            {
              p = sh_kern_charhex (new_system_call_code[k]);
              linkpath_new[2*k]   = p[0];
              linkpath_new[2*k+1] = p[1];
              linkpath_new[2*k+2] = '\0';
            }
#ifdef SH_USE_XML
            sl_strlcat(msg, _("link_old=\""),    2*SH_BUFSIZE);
            sl_strlcat(msg, linkpath_old,        2*SH_BUFSIZE);
            sl_strlcat(msg, _("\" link_new=\""), 2*SH_BUFSIZE);
            sl_strlcat(msg, linkpath_new,        2*SH_BUFSIZE);
            sl_strlcat(msg, _("\""),             2*SH_BUFSIZE);
#else
            sl_strlcat(msg, _("link_old=<"),     2*SH_BUFSIZE);
            sl_strlcat(msg, linkpath_old,        2*SH_BUFSIZE);
            sl_strlcat(msg, _(">, link_new=<"),   2*SH_BUFSIZE);
            sl_strlcat(msg, linkpath_new,        2*SH_BUFSIZE);
            sl_strlcat(msg, _(">"),              2*SH_BUFSIZE);
#endif

            sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                         status, MSG_KERN_GATE,
                         new_system_call_code[i], 0,
                         system_call_code[i], 0,
                         0, _("system_call (interrupt handler)"),
                         msg);
            
            SH_FREE(linkpath_old);
            SH_FREE(linkpath_new);

            for (j = 0; j < (max_system_call + 4); ++j)
            system_call_code[j] = new_system_call_code[j];
            break;
          }
      }
    }
  
  /* Check the individual syscalls
   *
   * Stored(old) is sh_syscalls[] array.
   */
  if (sh.flag.checkSum == SH_CHECK_INIT)
    {
      for (i = 0; i < SH_MAXCALLS; ++i) 
      {
        store0 = kmem_call_table[i]; 
#ifdef SH_SYSCALL_CODE
        store1 = kmem_code_table[i][0]; store2 = kmem_code_table[i][1];
#else
        store1 = 0; store2 = 0;
#endif
        sh_kern_db_syscall (i, _("syscall"), 
                        NULL, &store0, &store1, &store2,
                        0, 0);
      }
    }

  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
      (sh.flag.update == S_TRUE && is_init == 1))
    {
      for (i = 0; i < SH_MAXCALLS; ++i) 
      {
        if (sh_syscalls[i].name == NULL /* || sh_syscalls[i].addr == 0UL */)
          break;

#ifdef SH_USE_LKM
        if (sh_syscalls[i].addr != kmem_call_table[i])
          {
            if (check_getdents == 0 && 
              0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents")))
            {
              check_getdents = 1;
              sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
                           status, MSG_E_SUBGEN,
                           _("Modified kernel syscall (expected)."),
                           _(sh_syscalls[i].name) );
              copy_if_next = i;
              sh_syscalls[i].addr = kmem_call_table[i];
              continue;
            }
            /* #ifdef __NR_getdents64 */
            else if  (check_getdents64 == 0 && 
                  0 == strcmp(_(sh_syscalls[i].name), 
                            _("sys_getdents64")))
            {
              check_getdents64 = 1;
              sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
                           status, MSG_E_SUBGEN,
                           _("Modified kernel syscall (expected)."),
                           _(sh_syscalls[i].name) );
              copy_if_next_64 = i;
              sh_syscalls[i].addr = kmem_call_table[i];
              continue;
            }
            /* #endif */
            else
            {
              size_old = sh_syscalls[i].addr;
              size_new = kmem_call_table[i];
              mod_syscall_addr = 1;
              /*
              sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                           status, MSG_KERN_POLICY,
                           kmem_call_table[i],
                           sh_syscalls[i].addr,
                           i, _(sh_syscalls[i].name)
                           );
              */
            }
            sh_syscalls[i].addr = kmem_call_table[i];
          }
#else
        if (sh_syscalls[i].addr != kmem_call_table[i])
          {
            size_old = sh_syscalls[i].addr;
            size_new = kmem_call_table[i];
            mod_syscall_addr = 1;
            /*
            sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                         status, MSG_KERN_POLICY,
                         kmem_call_table[i],
                         sh_syscalls[i].addr,
                         i, _(sh_syscalls[i].name)
                         );
            */
            sh_syscalls[i].addr = kmem_call_table[i];
          }
#endif


        /* Check the code at syscall address
         *
         * Stored(old) is sh_syscalls[]
         */
#ifdef SH_SYSCALL_CODE
        if ( (mod_syscall_addr == 0) && 
             ((sh_syscalls[i].code[0] != kmem_code_table[i][0]) || 
            (sh_syscalls[i].code[1] != kmem_code_table[i][1]))
             )
          {
            mtime_old = sh_syscalls[i].code[0];
            mtime_new = kmem_code_table[i][0];
            ctime_old = sh_syscalls[i].code[1];
            ctime_new = kmem_code_table[i][1];
            mod_syscall_code = 1;

#ifdef SH_USE_LKM
            if (i == copy_if_next)
            {
              mod_syscall_code =  0;
              copy_if_next     = -1;
            }
            if (i == copy_if_next_64)
            {
              mod_syscall_code =  0;
              copy_if_next_64  = -1;
            }
#endif

            /*
            sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                         status, MSG_KERN_POL_CO,
                         kmem_code_table[i][0],  kmem_code_table[i][1],
                         sh_syscalls[i].code[0], sh_syscalls[i].code[1],
                         i, _(sh_syscalls[i].name)
                         );
            */
            sh_syscalls[i].code[0] = kmem_code_table[i][0];
            sh_syscalls[i].code[1] = kmem_code_table[i][1];
          }
#endif
        /*
         * Build the error message, if something has been
         * detected.
         */
        if ((mod_syscall_addr != 0) || (mod_syscall_code != 0))
          {
#ifdef SH_USE_XML
            sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
                    _("syscall"), i);
#else
            sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
                    _("syscall"), i);
#endif
            sl_strlcpy(msg, tmp, SH_BUFSIZE);

            if (mod_syscall_addr != 0)
            {
              sl_snprintf(tmp, 128, sh_hash_size_format(),
                        size_old, size_new);
              sl_strlcat(msg, tmp, SH_BUFSIZE); 
            }
            if (mod_syscall_code != 0)
            {
              sl_strlcpy (timstr_o, sh_unix_gmttime (ctime_old), 32);
              sl_strlcpy (timstr_n, sh_unix_gmttime (ctime_new), 32);
#ifdef SH_USE_XML
              sl_snprintf(tmp, 128, 
                        _("ctime_old=\"%s\" ctime_new=\"%s\" "), 
                        timstr_o, timstr_n);
#else
              sl_snprintf(tmp, 128, 
                        _("ctime_old=<%s>, ctime_new=<%s>, "), 
                        timstr_o, timstr_n);
#endif
              sl_strlcat(msg, tmp, SH_BUFSIZE); 
              sl_strlcpy (timstr_o, sh_unix_gmttime (mtime_old), 32);
              sl_strlcpy (timstr_n, sh_unix_gmttime (mtime_new), 32);
#ifdef SH_USE_XML
              sl_snprintf(tmp, 128, 
                        _("mtime_old=\"%s\" mtime_new=\"%s\" "), 
                        timstr_o, timstr_n);
#else
              sl_snprintf(tmp, 128, 
                        _("mtime_old=<%s>, mtime_new=<%s> "), 
                        timstr_o, timstr_n);
#endif
              sl_strlcat(msg, tmp, SH_BUFSIZE); 
            }
            sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                         status, MSG_KERN_SYSCALL,
                         i, _(sh_syscalls[i].name), msg);
            mod_syscall_addr = 0;
            mod_syscall_code = 0;
          }
      }
    }

#ifdef SH_IDT_TABLE
  if (ShKernIDT == S_TRUE)
    {
      if (sh.flag.checkSum == SH_CHECK_INIT)
      {
        datasize = 8;
        for (j = 0; j < SH_MAXIDT; ++j) 
          {
            sh_kern_db_syscall (j, _("idt_table"), 
                          &sh_idt_table[j*8], 
                          &store0, &store1, &store2,
                          &datasize, 0);
          }
      }

      if ((sh.flag.checkSum != SH_CHECK_INIT) || 
        (sh.flag.update == S_TRUE && is_init == 1))
      {
        /* Check the Interrupt Descriptor Table
         *
         * Stored(old) is idt_table[]
         */
        for (j = 0; j < SH_MAXIDT; ++j)
          {
            i = j * 8;
        
            sh_idt_offset_lo = *((unsigned short *) &sh_idt_table[i]);
            sh_idt_selector  = *((unsigned short *) &sh_idt_table[i+2]);
            sh_idt_reserved  = (unsigned char) sh_idt_table[i+4];
            sh_idt_flag      = (unsigned char) sh_idt_table[i+5];
            sh_idt_offset_hi = *((unsigned short *) &sh_idt_table[i+6]);
            sh_idt_iaddr = (unsigned long)(sh_idt_offset_hi << 16) 
            + sh_idt_offset_lo;
            
            if (sh_idt_iaddr == 0)
            {
              sh_idt_table[i+2] = '\0';
              sh_idt_table[i+3] = '\0';
              sh_idt_table[i+5] = '\0';

              idt_offset_lo = *((unsigned short *) &idt_table[i]);
              idt_offset_hi = *((unsigned short *) &idt_table[i+6]);
              idt_iaddr = (unsigned long)(idt_offset_hi << 16) 
                + idt_offset_lo;
              if (idt_iaddr == 0)
                {
                  idt_table[i+2] = '\0';
                  idt_table[i+3] = '\0';
                  idt_table[i+5] = '\0';
                }
              
            }
        
            if (memcmp(&sh_idt_table[i], &idt_table[i], 8) != 0)
            {
              
              idt_offset_lo = *((unsigned short *) &idt_table[i]);
              idt_selector  = *((unsigned short *) &idt_table[i+2]);
              idt_reserved  = (unsigned char) idt_table[i+4];
              idt_flag      = (unsigned char) idt_table[i+5];
              idt_offset_hi = *((unsigned short *) &idt_table[i+6]);
              idt_iaddr = (unsigned long)(idt_offset_hi << 16) 
                + idt_offset_lo;
            
              if (idt_iaddr != 0)
                {
                  if (idt_flag & 64) { dpl = 3; }
                  else               { dpl = 0; }
                  if (idt_flag & 1)  { 
                  if (dpl == 3) idt_type = 'S'; 
                  else idt_type = 'T'; }
                  else               { idt_type = 'I'; }
                }
              else { dpl = -1; idt_type = 'U'; }
              
              if (sh_idt_iaddr != 0)
                {
                  if (sh_idt_flag & 64) { sh_dpl = 3; }
                  else               { sh_dpl = 0; }
                  if (sh_idt_flag & 1)  { 
                  if (sh_dpl == 3) sh_idt_type = 'S'; 
                  else sh_idt_type = 'T'; }
                  else               { sh_idt_type = 'I'; }
                }
              else { sh_dpl = -1; sh_idt_type = 'U'; }
              
#ifdef SH_USE_XML
              sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
                        _("idt_table"), j);
#else
              sl_snprintf(tmp, 128, "path=<K_%s_%04d> ", 
                        _("idt_table"), j);
#endif
              sl_strlcpy(msg, tmp, SH_BUFSIZE);

              linkpath_old = SH_ALLOC(32);
              linkpath_new = SH_ALLOC(32);
              for (k = 0; k < 8; ++k)
                {
                  p = sh_kern_charhex (idt_table[i+k]);
                  linkpath_old[2*k]   = p[0];
                  linkpath_old[2*k+1] = p[1];
                  linkpath_old[2*k+2] = '\0';
                }
              for (k = 0; k < 8; ++k)
                {
                  p = sh_kern_charhex (sh_idt_table[i+k]);
                  linkpath_new[2*k]   = p[0];
                  linkpath_new[2*k+1] = p[1];
                  linkpath_new[2*k+2] = '\0';
                }
#ifdef SH_USE_XML
              sl_snprintf(tmp, 128,
                        _("link_old=\"%s\" link_new=\"%s\" "), 
                        linkpath_old, linkpath_new);
#else
              sl_snprintf(tmp, 128,
                        _("link_old=<%s> link_new=<%s> "), 
                        linkpath_old, linkpath_new);
#endif
              sl_strlcat(msg, tmp, SH_BUFSIZE);

              sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                           status, MSG_KERN_IDT,
                           j, 
                           sh_idt_iaddr, sh_strseg(sh_idt_selector), 
                           (int) sh_dpl, sh_idt_type, 
                           idt_iaddr, sh_strseg(idt_selector),
                           (int) dpl, idt_type, msg);
              
              SH_FREE(linkpath_old);
              SH_FREE(linkpath_new);

              memcpy(&idt_table[i], &sh_idt_table[i], 8);
            }
          }
      }
    }
#endif

  SL_RETURN( (0), _("sh_kern_check_internal"));
}
/* ifdef HOST_IS_LINUX */
#else

#include <err.h>
#include <kvm.h>
#include <nlist.h>

/* not OpenBSD */
#if defined(HOST_IS_FREEBSD)
#include <sys/sysent.h>
#endif

#include <sys/syscall.h>
#ifndef  SYS_MAXSYSCALL
#define  SYS_MAXSYSCALL 512
#endif

#ifdef __OpenBSD__
struct proc;
struct sysent {
      short sy_narg;
      short sy_argsize;
      int   (*sy_call)(struct proc *, void *, register_t *);
};
#endif

int sh_kern_data_init ()
{
  unsigned long store0 = 0;
  unsigned int  store1 = 0, store2 = 0;
  int           datasize, i;
  char        * databuf = NULL;

  /* syscall address and code
   */ 
  for (i = 0; i < SH_MAXCALLS; ++i) 
    {
      databuf = sh_kern_db_syscall (i, _("syscall"), 
                            NULL, &store0, &store1, &store2,
                            &datasize, 1);
      sh_syscalls[i].addr = store0;
      if (databuf != NULL) { SH_FREE(databuf); }
      if (store0 == 0) {
      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                  _("syscall address not found in database"), 
                  _("sh_kern_data_init"));
      return -1;
      }

      sh_syscalls[i].code[0] = (unsigned int) store1; 
      sh_syscalls[i].code[1] = (unsigned int) store2;
      if ((store1 == 0) || (store2 == 0)) {
      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                  _("syscall code not found in database"), 
                  _("sh_kern_data_init"));
      return -1;
      }

    }

  return 0;
}

int sh_kern_check_internal ()
{
  struct sysent  sy;
  kvm_t * kd;
  int     i;
  int     status = -1;
  char    errbuf[_POSIX2_LINE_MAX+1];
  struct  nlist * sys_list;
  struct  nlist list[2];

  unsigned long offset = 0L;
  unsigned int  syscall_code[2];  /* 8 bytes */
  unsigned long syscall_addr;

  unsigned long store0 = 0;
  unsigned int  store1 = 0, store2 = 0;

  UINT64        size_old  = 0, size_new = 0;
  UINT64        mtime_old = 0, mtime_new = 0;
  UINT64        ctime_old = 0, ctime_new = 0;
  char          tmp[128];
  char          msg[2*SH_BUFSIZE];
  char timstr_o[32];
  char timstr_n[32];

  static int is_init = 0;

  SL_ENTER(_("sh_kern_check_internal"));

  if (is_init == 0)
    { 
      if (sh.flag.checkSum != SH_CHECK_INIT)
      {
        if (0 == sh_kern_data_init()) {
          is_init = 1;
        } else {
          sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, 
                       MSG_E_SUBGEN,
                       _("could not initialize - switching off"),
                       _("kern_check_internal") );
          ShKernActive = S_FALSE;
          SL_RETURN( (-1), _("sh_kern_check_internal"));
        }
      }
      else if ((sh.flag.checkSum == SH_CHECK_INIT) && 
             (sh.flag.update == S_TRUE))
      {     
        if (0 == sh_kern_data_init()) {
          is_init = 1;
        } else {
          sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, 
                       MSG_E_SUBGEN,
                       _("no or incomplete data in baseline database"),
                       _("kern_check_internal") );
        }
      }
    }

  /* defined, but not used
   */
  ShKernDelay    = 0;
   
  list[0].n_name = "_sysent";
  list[1].n_name = NULL;

  kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
  if (!kd)
    {
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                   errbuf,
                   _("kvm_openfiles") );
      SL_RETURN( (-1), _("sh_kern_check_internal"));
    }

  i = kvm_nlist(kd, list);
  if (i == -1)
    {
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                   kvm_geterr(kd),
                   _("kvm_nlist (_sysent)") );
      kvm_close(kd);
      SL_RETURN( (-1), _("sh_kern_check_internal"));
    }

  sys_list = SH_ALLOC((SYS_MAXSYSCALL+1) * sizeof(struct nlist));

  for (i = 0; i < SH_MAXCALLS; ++i)
    sys_list[i].n_name = sh_syscalls[i].name;
  sys_list[SH_MAXCALLS].n_name = NULL;

  i = kvm_nlist(kd, sys_list);
  if (i == -1)
    {
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                   kvm_geterr(kd),
                   _("kvm_nlist (syscalls)") );
      kvm_close(kd);
      SH_FREE(sys_list);
      SL_RETURN( (-1), _("sh_kern_check_internal"));
    }
  else if (i > 0)
    {
      sl_snprintf(tmp, 128,
                  _("%d invalid syscalls"), i);
      /*
      for (i = 0; i < SH_MAXCALLS; ++i) {
        if (sys_list[i].n_type == 0 && sys_list[i].n_value == 0)
          fprintf(stderr, "invalid: [%3d] %s\n", i, sh_syscalls[i].name);
      }
      */
      sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
                       tmp,
                       _("kvm_nlist (syscalls)") );
    }

  /* Check the individual syscalls
   *
   * Stored(old) is sh_syscalls[] array.
   */
  if (sh.flag.checkSum == SH_CHECK_INIT)
    {
      for (i = 0; i < SH_MAXCALLS; ++i) 
      {
        if (sh_syscalls[i].name == NULL)
          {
            sl_snprintf(tmp, 128, 
                    _("too few entries in sh_syscalls[]: have %d, expect %d"), 
                    i, SH_MAXCALLS);

            sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                         tmp,
                         _("sh_kern_check_internal") );
            break;
          }

        /* read address of syscall from sysent table
         */
        offset = list[0].n_value + (i*sizeof(struct sysent));
        if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0)
          {
            sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                         kvm_geterr(kd),
                         _("kvm_read (syscall table)") );
            kvm_close(kd);
            SH_FREE(sys_list);
            SL_RETURN( (-1), _("sh_kern_check_internal"));
          }
        syscall_addr = (unsigned long) sy.sy_call;
        store0 = syscall_addr;
        
        /* read the syscall code
         */
        if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]), 
                  2 * sizeof(unsigned int)) < 0)
          {
            sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                         kvm_geterr(kd),
                         _("kvm_read (syscall code)") );
            kvm_close(kd);
            SH_FREE(sys_list);
            SL_RETURN( (-1), _("sh_kern_check_internal"));
          }
        store1 = syscall_code[0]; store2 = syscall_code[1];
        
        sh_kern_db_syscall (i, _("syscall"), 
                        NULL, &store0, &store1, &store2,
                        0, 0);
      }
    }

  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
      (sh.flag.update == S_TRUE && is_init == 1))
    {
      for (i = 0; i < SH_MAXCALLS; ++i)
      {
        if (sh_syscalls[i].name == NULL)
          {
            sl_snprintf(tmp, 128, 
                    _("too few entries in sh_syscalls[]: have %d, expect %d"), 
                    i, SH_MAXCALLS);

            sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                         tmp,
                         _("sh_kern_check_internal") );
            break;
          }
        
        /* read address of syscall from sysent table
         */
        offset = list[0].n_value + (i*sizeof(struct sysent));
        if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0)
          {
            sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                         kvm_geterr(kd),
                         _("kvm_read (syscall table)") );
            kvm_close(kd);
            SH_FREE(sys_list);
            SL_RETURN( (-1), _("sh_kern_check_internal"));
          }
        syscall_addr = (unsigned long) sy.sy_call;
        
        if (sh_syscalls[i].addr != syscall_addr)
          {
#ifdef SH_USE_XML
            sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
                    _("syscall"), i);
#else
            sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
                    _("syscall"), i);
#endif
            sl_strlcpy(msg, tmp, SH_BUFSIZE);

            size_old = sh_syscalls[i].addr; 
            size_new = syscall_addr;
            sl_snprintf(tmp, 128, sh_hash_size_format(),
                    size_old, size_new);
            sl_strlcat(msg, tmp, SH_BUFSIZE);
 
            sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                         status, MSG_KERN_SYSCALL,
                         /*
                         syscall_addr,
                         sh_syscalls[i].addr,
                         */
                         i, _(sh_syscalls[i].name),
                         msg);
            sh_syscalls[i].addr = syscall_addr;
          }
        else
          {    
            /* read the syscall code
             */
            if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]), 
                    2 * sizeof(unsigned int)) < 0)
            {
              sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                           kvm_geterr(kd),
                           _("kvm_read (syscall code)") );
              kvm_close(kd);
              SH_FREE(sys_list);
              SL_RETURN( (-1), _("sh_kern_check_internal"));
            }
            
            if (sh_syscalls[i].code[0] != syscall_code[0] || 
              sh_syscalls[i].code[1] != syscall_code[1])
            {
              mtime_old = sh_syscalls[i].code[0];
              mtime_new = syscall_code[0];
              ctime_old = sh_syscalls[i].code[1];
              ctime_new = syscall_code[1];

#ifdef SH_USE_XML
              sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
                        _("syscall"), i);
#else
              sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
                        _("syscall"), i);
#endif
              sl_strlcpy(msg, tmp, SH_BUFSIZE);

              sl_strlcpy (timstr_o, sh_unix_gmttime (ctime_old), 32);
              sl_strlcpy (timstr_n, sh_unix_gmttime (ctime_new), 32);
#ifdef SH_USE_XML
              sl_snprintf(tmp, 128, 
                        _("ctime_old=\"%s\" ctime_new=\"%s\" "), 
                        timstr_o, timstr_n);
#else
              sl_snprintf(tmp, 128, 
                        _("ctime_old=<%s>, ctime_new=<%s>, "), 
                        timstr_o, timstr_n);
#endif
              sl_strlcat(msg, tmp, SH_BUFSIZE); 
              sl_strlcpy (timstr_o, sh_unix_gmttime (mtime_old), 32);
              sl_strlcpy (timstr_n, sh_unix_gmttime (mtime_new), 32);
#ifdef SH_USE_XML
              sl_snprintf(tmp, 128, 
                        _("mtime_old=\"%s\" mtime_new=\"%s\" "), 
                        timstr_o, timstr_n);
#else
              sl_snprintf(tmp, 128, 
                        _("mtime_old=<%s>, mtime_new=<%s> "), 
                        timstr_o, timstr_n);
#endif
              sl_strlcat(msg, tmp, SH_BUFSIZE); 

              sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
                           status, MSG_KERN_SYSCALL,
                           /*
                           syscall_code[0],  syscall_code[1],
                           sh_syscalls[i].code[0], sh_syscalls[i].code[1],
                           */
                           i, _(sh_syscalls[i].name),
                           msg);
              sh_syscalls[i].code[0] = syscall_code[0];
              sh_syscalls[i].code[1] = syscall_code[1];
            }
          }
      }
    }
  SH_FREE(sys_list);
  if(kvm_close(kd) < 0)
    {
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
                       kvm_geterr(kd),
                       _("kvm_close") );
      exit(EXIT_FAILURE);
    }

  SL_RETURN( (0), _("sh_kern_check_internal"));
}

#endif

/*************
 *
 * module init
 *
 *************/
#if defined(HOST_IS_LINUX)
#include <sys/utsname.h>
#endif

static int AddressReconf = 0;

int sh_kern_init ()
{
#if defined(HOST_IS_LINUX)
  struct utsname buf;
  char         * str;
#endif

  SL_ENTER(_("sh_kern_init"));
  if (ShKernActive == S_FALSE)
    SL_RETURN( (-1), _("sh_kern_init"));

#if defined(HOST_IS_LINUX)
  uname(&buf);

  if ((AddressReconf < 5) && (0 != strcmp(SH_KERNEL_VERSION, buf.release)))
    {
      str = SH_ALLOC(256);
      sl_snprintf(str, 256, 
              "Compiled for kernel %s, but current kernel is %s, and kernel addresses have not been re-configured",
              SH_KERNEL_VERSION, buf.release);
      sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
                   str,
                   _("kern_check") );
      SH_FREE(str);
      ShKernActive = S_FALSE;
      SL_RETURN( (-1), _("sh_kern_init"));
    }
#endif

  lastcheck  = time (NULL);
  if (sh.flag.checkSum != SH_CHECK_INIT)
    {
      sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
                   _("Checking kernel syscalls"),
                   _("kern_check") );
    }
  sh_kern_check_internal ();
  SL_RETURN( (0), _("sh_kern_init"));
}

/*************
 *
 * module cleanup
 *
 *************/
int sh_kern_end ()
{
  return (0);
}


/*************
 *
 * module timer
 *
 *************/
int sh_kern_timer (time_t tcurrent)
{
  if ((int) (tcurrent - lastcheck) >= ShKernInterval)
    {
      lastcheck  = tcurrent;
      return (-1);
    }
  return 0;
}

/*************
 *
 * module check
 *
 *************/
int sh_kern_check ()
{
  sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
               _("Checking kernel syscalls"),
               _("kern_check") );
  return (sh_kern_check_internal ());
}

/*************
 *
 * module setup
 *
 *************/

int sh_kern_set_severity  (char * c)
{
  char tmp[32];
  tmp[0] = '='; tmp[1] = '\0';
  sl_strlcat (tmp, c, 32);
  sh_error_set_level (tmp, &ShKernSeverity);
  return 0;
}

int sh_kern_set_timer (char * c)
{
  long val;

  SL_ENTER(_("sh_kern_set_timer"));

  val = strtol (c, (char **)NULL, 10);
  if (val <= 0)
    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
                      _("kern timer"), c);

  val = (val <= 0 ? 60 : val);

  ShKernInterval = (time_t) val;
  SL_RETURN( 0, _("sh_kern_set_timer"));
}

int sh_kern_set_activate (char * c)
{
  int i;
  SL_ENTER(_("sh_kern_set_activate"));
  i = sh_util_flagval(c, &ShKernActive);
  SL_RETURN(i, _("sh_kern_set_activate"));
}

int sh_kern_set_idt (char * c)
{
  int i;
  SL_ENTER(_("sh_kern_set_idt"));
  i = sh_util_flagval(c, &ShKernIDT);
  SL_RETURN(i, _("sh_kern_set_idt"));
}

int sh_kern_set_sc_addr (char * c)
{
  char * endptr;
  unsigned long value;

  SL_ENTER(_("sh_kern_set_sc_addr"));
  errno = 0;
  value = strtoul(c, &endptr, 16);
  if ((ULONG_MAX == value) && (errno == ERANGE))
    {
      SL_RETURN((-1), _("sh_kern_set_sc_addr"));
    }
  if ((*c == '\0') || (*endptr != '\0'))
    {
      SL_RETURN((-1), _("sh_kern_set_sc_addr"));
    }
  system_call_addr = value;
  ++AddressReconf;
  SL_RETURN((0), _("sh_kern_set_sc_addr"));
}

int sh_kern_set_sct_addr (char * c)
{
  char * endptr;
  unsigned long value;

  SL_ENTER(_("sh_kern_set_sct_addr"));
  errno = 0;
  value = strtoul(c, &endptr, 16);
  if ((ULONG_MAX == value) && (errno == ERANGE))
    {
      SL_RETURN((-1), _("sh_kern_set_sct_addr"));
    }
  if ((*c == '\0') || (*endptr != '\0'))
    {
      SL_RETURN((-1), _("sh_kern_set_sct_addr"));
    }
  kaddr = (unsigned int) value;
  ++AddressReconf;
  SL_RETURN((0), _("sh_kern_set_sct_addr"));
}

int sh_kern_set_proc_root (char * c)
{
  char * endptr;
  unsigned long value;

  SL_ENTER(_("sh_kern_set_proc_root"));
  errno = 0;
  value = strtoul(c, &endptr, 16);
  if ((ULONG_MAX == value) && (errno == ERANGE))
    {
      SL_RETURN((-1), _("sh_kern_set_proc_root"));
    }
  if ((*c == '\0') || (*endptr != '\0'))
    {
      SL_RETURN((-1), _("sh_kern_set_proc_root"));
    }
  
  proc_root = value;
  ++AddressReconf;
  SL_RETURN((0), _("sh_kern_set_proc_root"));
}

int sh_kern_set_proc_root_iops (char * c)
{
  char * endptr;
  unsigned long value;

  SL_ENTER(_("sh_kern_set_proc_root_iops"));
  errno = 0;
  value = strtoul(c, &endptr, 16);
  if ((ULONG_MAX == value) && (errno == ERANGE))
    {
      SL_RETURN((-1), _("sh_kern_set_proc_root_iops"));
    }
  if ((*c == '\0') || (*endptr != '\0'))
    {
      SL_RETURN((-1), _("sh_kern_set_proc_root_iops"));
    }
  
  proc_root_iops = value;
  ++AddressReconf;
  SL_RETURN((0), _("sh_kern_set_proc_root_iops"));
}

int sh_kern_set_proc_root_lookup (char * c)
{
  char * endptr;
  unsigned long value;

  SL_ENTER(_("sh_kern_set_proc_root_lookup"));
  errno = 0;
  value = strtoul(c, &endptr, 16);
  if ((ULONG_MAX == value) && (errno == ERANGE))
    {
      SL_RETURN((-1), _("sh_kern_set_proc_root_lookup"));
    }
  if ((*c == '\0') || (*endptr != '\0'))
    {
      SL_RETURN((-1), _("sh_kern_set_proc_root_lookup"));
    }
  proc_root_lookup = value;
  ++AddressReconf;
  SL_RETURN((0), _("sh_kern_set_proc_root_lookup"));
}

#endif

/* #ifdef SH_USE_UTMP */
#endif




Generated by  Doxygen 1.6.0   Back to index