source: trunk/src/sh_kern.c @ 303

Last change on this file since 303 was 303, checked in by katerina, 11 years ago

Fix compile error when using --with-kcheck (ticket #225).

File size: 50.8 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 2001 Rainer Wichmann                                      */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program is distributed in the hope that it will be useful,        */
12/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14/*  GNU General Public License for more details.                           */
15/*                                                                         */
16/*  You should have received a copy of the GNU General Public License      */
17/*  along with this program; if not, write to the Free Software            */
18/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20
21#include "config_xor.h"
22
23#define SH_SYSCALL_CODE
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <errno.h>
34#include <limits.h>
35#include <sys/wait.h>
36#include <signal.h>
37#include <sys/mman.h>
38
39
40#ifdef SH_USE_KERN
41
42#undef  FIL__
43#define FIL__  _("sh_kern.c")
44
45#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
46
47#if TIME_WITH_SYS_TIME
48#include <sys/time.h>
49#include <time.h>
50#else
51#if HAVE_SYS_TIME_H
52#include <sys/time.h>
53#else
54#include <time.h>
55#endif
56#endif
57
58
59#include "samhain.h"
60#include "sh_pthread.h"
61#include "sh_utils.h"
62#include "sh_error.h"
63#include "sh_modules.h"
64#include "sh_kern.h"
65#include "sh_ks_xor.h"
66
67#include "sh_unix.h"
68#include "sh_hash.h"
69
70
71
72sh_rconf sh_kern_table[] = {
73  {
74    N_("severitykernel"),
75    sh_kern_set_severity
76  },
77  {
78    N_("kernelcheckactive"),
79    sh_kern_set_activate
80  },
81  {
82    N_("kernelcheckinterval"),
83    sh_kern_set_timer
84  },
85  {
86    N_("kernelcheckidt"),
87    sh_kern_set_idt
88  },
89  {
90    N_("kernelcheckpci"),
91    sh_kern_set_pci
92  },
93  {
94    N_("kernelsystemcall"),
95    sh_kern_set_sc_addr
96  },
97  {
98    N_("kernelsyscalltable"),
99    sh_kern_set_sct_addr
100  },
101  {
102    N_("kernelprocrootlookup"),
103    sh_kern_set_proc_root_lookup
104  },
105 {
106    N_("kernelprocrootiops"),
107    sh_kern_set_proc_root_iops
108  },
109  {
110    N_("kernelprocroot"),
111    sh_kern_set_proc_root
112  },
113  {
114    NULL,
115    NULL
116  },
117};
118
119
120static time_t  lastcheck;
121static int     ShKernActive   = S_TRUE;
122static int     ShKernInterval = 300;
123static int     ShKernSeverity = SH_ERR_SEVERE;
124static int     ShKernDelay    = 100; /* milliseconds */
125static int     ShKernIDT      = S_TRUE;
126static int     ShKernPCI      = S_TRUE;
127
128/* The address of system_call
129 */
130#ifdef SH_SYS_CALL_ADDR
131static unsigned long system_call_addr = SH_SYS_CALL_ADDR;
132#else
133static unsigned long system_call_addr = 0;
134#endif
135
136/* The address of the sys_call_table
137 */
138#ifdef SH_SYS_CALL_TABLE
139static unsigned long  kaddr = SH_SYS_CALL_TABLE;
140#else
141static unsigned long  kaddr = 0;
142#endif
143
144#ifdef PROC_ROOT_LOC
145static unsigned long proc_root = PROC_ROOT_LOC;
146#else
147static unsigned long proc_root = 0;
148#endif
149#ifdef PROC_ROOT_IOPS_LOC
150static unsigned long proc_root_iops = PROC_ROOT_IOPS_LOC;
151#else
152static unsigned long proc_root_iops = 0;
153#endif
154#ifdef PROC_ROOT_LOOKUP_LOC
155static unsigned long proc_root_lookup = PROC_ROOT_LOOKUP_LOC;
156#else
157static unsigned long proc_root_lookup = 0;
158#endif
159
160/* This is the module 'reconfigure' function, which is a no-op.
161 */
162int sh_kern_null()
163{
164  return 0;
165}
166
167#define SH_KERN_DBPUSH 0
168#define SH_KERN_DBPOP  1
169
170char * sh_kern_db_syscall (int num, char * prefix,
171                           void * in_name, unsigned long * addr,
172                           unsigned int * code1, unsigned int * code2,
173                           int * size, int direction)
174{
175  char            path[128];
176  char          * p = NULL;
177
178  unsigned char * name = (unsigned char *) in_name;
179  struct store2db save;
180
181  sl_snprintf(path, 128, "K_%s_%04d", prefix, num);
182
183  memset(&save, '\0', sizeof(struct store2db));
184
185  if (direction == SH_KERN_DBPUSH) 
186    {
187      save.val0 = *addr;
188      save.val1 = *code1;
189      save.val2 = *code2;
190      save.str  = name;
191      save.size = (name == NULL) ? 0 : (*size);
192
193      sh_hash_push2db (path, &save);
194    }
195  else
196    {
197      p = sh_hash_db2pop (path, &save);
198
199      *addr  = (unsigned long) save.val0;
200      *code1 = (unsigned int)  save.val1;
201      *code2 = (unsigned int)  save.val2;
202
203      *size  = (int)           save.size;
204    }
205  return p;
206}
207
208static char * sh_kern_pathmsg (char * msg, size_t msg_len,
209                               int num, char * prefix,
210                               unsigned char * old, size_t old_len,
211                               unsigned char * new, size_t new_len)
212{
213  size_t k;
214  char   tmp[128];
215  char  *p;
216  char  *linkpath_old;
217  char  *linkpath_new;
218  char   i2h[2];
219
220#ifdef SH_USE_XML
221  sl_snprintf(tmp, sizeof(tmp), _("path=\"K_%s_%04d\" "), 
222              prefix, num);
223#else
224  sl_snprintf(tmp, sizeof(tmp), _("path=<K_%s_%04d> "), 
225              prefix, num);
226#endif
227  sl_strlcpy(msg, tmp, msg_len);
228
229  if (SL_TRUE == sl_ok_muls(old_len, 2) &&
230      SL_TRUE == sl_ok_adds(old_len * 2, 1))
231    linkpath_old = SH_ALLOC(old_len * 2 + 1);
232  else
233    return msg;
234
235  if (SL_TRUE == sl_ok_muls(new_len, 2) &&
236      SL_TRUE == sl_ok_adds(new_len * 2, 1))
237    linkpath_new = SH_ALLOC(new_len * 2 + 1);
238  else
239    return msg;
240
241  for (k = 0; k < old_len; ++k)
242    {
243      p = sh_util_charhex (old[k], i2h);
244      linkpath_old[2*k]   = p[0];
245      linkpath_old[2*k+1] = p[1];
246      linkpath_old[2*k+2] = '\0';
247    }
248
249  for (k = 0; k < new_len; ++k)
250    {
251      p = sh_util_charhex (new[k], i2h);
252      linkpath_new[2*k]   = p[0];
253      linkpath_new[2*k+1] = p[1];
254      linkpath_new[2*k+2] = '\0';
255   
256}
257#ifdef SH_USE_XML
258  sl_strlcat(msg, _("link_old=\""),    msg_len);
259  sl_strlcat(msg, linkpath_old,        msg_len);
260  sl_strlcat(msg, _("\" link_new=\""), msg_len);
261  sl_strlcat(msg, linkpath_new,        msg_len);
262  sl_strlcat(msg, _("\""),             msg_len);
263#else
264  sl_strlcat(msg, _("link_old=<"),     msg_len);
265  sl_strlcat(msg, linkpath_old,        msg_len);
266  sl_strlcat(msg, _(">, link_new=<"),  msg_len);
267  sl_strlcat(msg, linkpath_new,        msg_len);
268  sl_strlcat(msg, _(">"),              msg_len);
269#endif
270
271  SH_FREE(linkpath_old);
272  SH_FREE(linkpath_new);
273
274  return msg;
275}
276 
277#ifdef HOST_IS_LINUX
278
279#ifndef KERNEL_VERSION
280#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
281#endif
282
283/*
284 * Interrupt Descriptor Table
285 */
286#ifdef HAVE_ASM_SEGMENT_H
287#include <asm/segment.h>
288#endif
289
290#define SH_MAXIDT   256
291
292static unsigned char sh_idt_table[SH_MAXIDT * 8];
293
294static char * sh_strseg(unsigned short segment)
295{
296  static int flip = 0;
297  static char one[32];
298  static char two[32];
299
300  switch (segment) {
301#ifdef __KERNEL_CS
302  case __KERNEL_CS:
303    return _("KERNEL_CS");
304#endif
305#ifdef __KERNEL_DS
306  case __KERNEL_DS:
307    return _("KERNEL_DS");
308#endif
309#ifdef __USER_CS
310  case __USER_CS:
311    return _("USER_CS");
312#endif
313#ifdef __USER_DS
314  case __USER_DS:
315    return _("USER_DS");
316#endif
317  default:
318    if (flip == 0)
319      {
320        snprintf(one, sizeof(one), "%hX", segment);
321        flip = 1;
322        return one;
323      }
324    else
325      {
326        snprintf(two, sizeof(two), "%hX", segment);
327        flip = 0;
328        return two;
329      }
330  }
331}
332
333
334static int sh_kern_data_init ()
335{
336  unsigned long store0 = 0;
337  unsigned int  store1 = 0, store2 = 0;
338  int           datasize, i, j;
339  char        * databuf;
340
341  /* system_call code
342   */
343  databuf = sh_kern_db_syscall (0, _("system_call"), 
344                                NULL, &store0, &store1, &store2,
345                                &datasize, SH_KERN_DBPOP);
346  if (datasize == sizeof(system_call_code))
347    {
348      memcpy (system_call_code, databuf, sizeof(system_call_code));
349      SH_FREE(databuf);
350    }
351  else
352    {
353      sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
354                      _("system_call_code not found in database"), 
355                      _("sh_kern_data_init"));
356      return -1;
357    }
358
359  /* syscall address and code
360   */ 
361  for (i = 0; i < SH_MAXCALLS; ++i) 
362    {
363      databuf = sh_kern_db_syscall (i, _("syscall"), 
364                                    NULL, &store0, &store1, &store2,
365                                    &datasize, SH_KERN_DBPOP);
366      sh_syscalls[i].addr = store0;
367      if (store0 == 0) {
368        sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, i, MSG_E_SUBGEN,
369                        _("syscall address not found in database"), 
370                        _("sh_kern_data_init"));
371        return -1;
372      }
373
374      sh_syscalls[i].code[0] = (unsigned int) store1; 
375      sh_syscalls[i].code[1] = (unsigned int) store2;
376      if ((store1 == 0) || (store2 == 0)) {
377        sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, i, MSG_E_SUBGEN,
378                        _("syscall code not found in database"), 
379                        _("sh_kern_data_init"));
380      }
381
382      if (databuf != NULL) {
383        SH_FREE(databuf);
384      }
385     
386    }
387
388  if (ShKernIDT == S_TRUE)
389    {
390      for (j = 0; j < SH_MAXIDT; ++j) 
391        {
392          databuf = sh_kern_db_syscall (j, _("idt_table"), 
393                                        NULL, 
394                                        &store0, &store1, &store2,
395                                        &datasize, SH_KERN_DBPOP);
396          if (datasize == 8) {
397            memcpy(&idt_table[j*8], databuf, 8);
398            SH_FREE(databuf);
399          } else {
400            sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, j, MSG_E_SUBGEN,
401                            _("idt table not found in database"), 
402                            _("sh_kern_data_init"));
403            return -1;
404          }
405        }
406    }
407
408  return 0;
409}
410
411
412/*
413 * Defined in include/linux/fs.h
414 */
415
416/* Here. we are only interested in 'lookup'. I.e. the struct
417 * must be <= the real one, and 'lookup' must be at the
418 * correct position.
419 */
420struct inode_operations {
421  int (*create) (int *,int *,int);
422  int * (*lookup) (int *,int *);
423  int (*link) (int *,int *,int *);
424  int (*unlink) (int *,int *);
425  int (*symlink) (int *,int *,const char *);
426  int (*mkdir) (int *,int *,int);
427  int (*rmdir) (int *,int *);
428  int (*mknod) (int *,int *,int,int);
429  int (*rename) (int *, int *,
430                 int *, int *);
431  /* flawfinder: ignore */
432  int (*readlink) (int *, char *,int);
433  int (*follow_link) (int *, int *);
434  void (*truncate) (int *);
435  int (*permission) (int *, int);
436  int (*revalidate) (int *);
437  /*
438    int (*setattr) (int *, int *);
439    int (*getattr) (int *, int *);
440    int (*setxattr) (int *, const char *, void *, size_t, int);
441    ssize_t (*getxattr) (int *, const char *, void *, size_t);
442    ssize_t (*listxattr) (int *, char *, size_t);
443    int (*removexattr) (int *, const char *);
444  */
445};
446
447/*
448 * this one is just for dummy purposes
449 */
450struct file_operations {
451  int (*create) (int *,int *,int);
452};
453
454/* Defined in include/linux/proc_fs.h
455 * Here we are interested in the 'proc_iops' member.
456 */
457struct proc_dir_entry {
458  unsigned short low_ino;
459  unsigned short namelen;
460  const char * name;
461  mode_t mode;
462  nlink_t nlink;
463  uid_t uid;
464  gid_t gid;
465#if defined  TWO_SIX_SEVENTEEN_PLUS
466  /* size is loff_t in 2.6.17+ kernels */
467  unsigned long dummy; 
468#endif
469  unsigned long size;
470  struct inode_operations * proc_iops;
471  struct file_operations * proc_fops;
472  /*
473  get_info_t *get_info;
474  struct module *owner;
475  struct proc_dir_entry *next, *parent, *subdir;
476  void *data;
477  read_proc_t *read_proc;
478  write_proc_t *write_proc;
479  atomic_t count;         
480  int deleted; 
481  */         
482};
483
484
485static int sh_kern_kmem_read (int fd, unsigned long addr, 
486                              unsigned char * buf, int len)
487{
488  if (lseek(fd, addr, SEEK_SET) == (off_t) (-1))
489    {
490      return -1;
491    }
492  if (read(fd, buf, len) < 0)
493    {
494      return -1;
495    }
496  return 0;
497}
498
499static int sh_kern_read_data (int fd, unsigned long addr, 
500                              unsigned char * buf, size_t len)
501{
502  size_t    moff, roff;
503  size_t    sz;
504  char    * kmap;
505
506  /* next, try mmap()
507   */
508  sz = getpagesize(); /* unistd.h */
509
510  moff = ((size_t)(addr/sz)) * sz;                 /* lower page boundary */
511  roff = addr - moff;    /* off relative to lower address of mmapped area */
512
513  kmap = mmap(0, len+sz, PROT_READ, MAP_PRIVATE, fd, moff);/* sys/mman.h */
514
515  if (kmap == MAP_FAILED)
516    {
517      /* then, try read()
518       */
519      if (0 == sh_kern_kmem_read (fd, addr, buf, len))
520        return 0;
521
522      memset(buf, '\0', len);
523      return -1;
524    }
525
526  memcpy (buf, &kmap[roff], len);
527  return munmap(kmap, len+sz);
528}
529
530
531static int check_init (int * init_retval)
532{
533  static int is_init = 0;
534
535  SL_ENTER(_("check_init"));
536
537  if (is_init == 0)
538    {
539      if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE)
540        {
541          if (0 == sh_kern_data_init()) {
542            is_init = 1;
543          } else {
544            sh_error_handle (ShKernSeverity, FIL__, __LINE__, 1, 
545                             MSG_E_SUBGEN,
546                             _("could not initialize kernel check - switching off"),
547                             _("check_init") );
548            ShKernActive = S_FALSE;
549            *init_retval = is_init;
550            SL_RETURN( (-1), _("check_init"));
551          }
552        }
553      else if ((sh.flag.checkSum == SH_CHECK_INIT || 
554                sh.flag.checkSum == SH_CHECK_CHECK) && 
555               (sh.flag.update == S_TRUE))
556        {
557          if (0 == sh_kern_data_init()) {
558            is_init = 1;
559          } else {
560            sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 0, 
561                             MSG_E_SUBGEN,
562                             _("no or incomplete data in baseline database for kernel check"),
563                             _("check_init") );
564          }
565        }
566    }
567  *init_retval = is_init;
568  SL_RETURN( (0), _("check_init"));
569}
570
571#define SH_KERN_SIZ 512
572#define SH_KERN_SCC 256
573
574static void run_child(int kd, int mpipe[2])
575{
576  int j;
577
578  unsigned long kmem_call_table[SH_KERN_SIZ];
579  unsigned int  kmem_code_table[SH_KERN_SIZ][2];
580
581  unsigned char new_system_call_code[SH_KERN_SCC];
582
583  struct inode_operations proc_root_inode;
584  struct proc_dir_entry   proc_root_dir;
585
586  int status = sl_close_fd(FIL__, __LINE__, mpipe[0]);
587
588  setpgid(0, 0);
589         
590  /* Seek to the system call table (at kaddr) and read it into
591   * the kmem_call_table array
592   */
593  if(status == 0)
594    {
595      retry_msleep (0, ShKernDelay); /* milliseconds */
596     
597      if (sh_kern_read_data (kd, kaddr, 
598                             (unsigned char *) &kmem_call_table, 
599                             sizeof(kmem_call_table)))
600        {
601          status = -2;
602        }
603    }
604
605  /*
606   * Seek to the system call address (at sh_syscalls[j].addr) and
607   * read first 8 bytes into the array kmem_code_table[j][] (2 * unsigned int)
608   */
609  if(status == 0)
610    {
611      memset(kmem_code_table, 0, sizeof(kmem_code_table));
612      for (j = 0; j < SH_MAXCALLS; ++j) 
613        {
614          if (sh_syscalls[j].addr == 0UL) {
615            sh_syscalls[j].addr = kmem_call_table[j];
616          }
617
618          if (sh_syscalls[j].name == NULL || 
619              sh_syscalls[j].addr == 0UL)
620            break;
621
622          if ((sh.flag.checkSum == SH_CHECK_INIT || 
623               sh.flag.checkSum == SH_CHECK_CHECK) && 
624              (sh.flag.update == S_TRUE))
625            {
626              if (sh_kern_read_data (kd, kmem_call_table[j], 
627                                     (unsigned char *) &(kmem_code_table[j][0]),
628                                     2 * sizeof(unsigned int)))
629                status = -3;
630            }
631          else
632            {
633              if (sh_kern_read_data (kd, sh_syscalls[j].addr, 
634                                     (unsigned char *) &(kmem_code_table[j][0]),
635                                     2 * sizeof(unsigned int)))
636                status = -4;
637            }
638        }
639    }
640
641  if(status == 0)
642    {
643      /*
644       * Get the address and size of Interrupt Descriptor Table,
645       * and read the content into the global array sh_idt_table[]
646       */
647      struct {
648        char pad[6];
649        unsigned short size;
650        unsigned long  addr;
651      } idt;
652
653      __asm__ volatile ("sidt %0": "=m" (idt.size));
654
655      idt.size = (idt.size + 1)/8;
656     
657      if (idt.size > SH_MAXIDT)
658        idt.size = SH_MAXIDT;
659     
660      memset(sh_idt_table, '\0', SH_MAXIDT*8);
661      if (sh_kern_read_data (kd, idt.addr, 
662                             (unsigned char *) sh_idt_table, idt.size*8))
663        status = -5;
664    }
665
666  /*
667   * Seek to the system_call address (at system_call_addr) and
668   * read first 256 bytes into new_system_call_code[]
669   *
670   * system_call_addr is defined in the include file.
671   */
672  if(status == 0)
673    {
674      if (sh_kern_read_data (kd, system_call_addr, 
675                             (unsigned char *) new_system_call_code, 
676                             SH_KERN_SCC))
677        status = -6;
678    }
679 
680  /*
681   * Seek to proc_root and read the structure.
682   * Seek to proc_root_inode_operations and get the structure.
683   */
684  if(status == 0)
685    {
686      if (sh_kern_read_data (kd, proc_root, 
687                             (unsigned char *) &proc_root_dir, 
688                             sizeof(proc_root_dir)))
689        status = -7;
690    }
691/* 2.6.21 (((2) << 16) + ((6) << 8) + (21)) */
692#if SH_KERNEL_NUMBER < KERNEL_VERSION(2,6,21)
693  if(status == 0)
694    {
695      if (sh_kern_read_data (kd, proc_root_iops, 
696                             (unsigned char *) &proc_root_inode, 
697                             sizeof(proc_root_inode)))
698        status = -8;
699    }
700#else
701    memset(&proc_root_inode, '\0', sizeof(proc_root_inode));
702#endif
703 
704  /*
705   * Write out data to the pipe
706   */
707  status = write(mpipe[1], &status, sizeof(int));
708
709  if (status > 0)
710    status = write(mpipe[1], &kmem_call_table, sizeof(kmem_call_table));
711 
712  if(status > 0)
713    status = write(mpipe[1], &kmem_code_table, sizeof(kmem_code_table));
714 
715  if(status > 0)
716    status = write(mpipe[1], &sh_idt_table, sizeof(sh_idt_table));
717 
718  if(status > 0)
719    status = write(mpipe[1], new_system_call_code, SH_KERN_SCC);
720 
721  if(status > 0)
722    status = write(mpipe[1], &proc_root_dir, sizeof(proc_root_dir));
723 
724  if(status > 0)
725    status = write(mpipe[1], &proc_root_inode, sizeof(proc_root_inode));
726
727  _exit( (status >= 0) ? 0 : status);
728}
729
730struct sh_kernel_info {
731  unsigned long kmem_call_table[SH_KERN_SIZ];
732  unsigned int  kmem_code_table[SH_KERN_SIZ][2];
733
734  unsigned char new_system_call_code[SH_KERN_SCC];
735
736  struct inode_operations proc_root_inode;
737  struct proc_dir_entry   proc_root_dir;
738};
739
740static int read_from_child(pid_t mpid, int * mpipe, 
741                           struct sh_kernel_info * kinfo)
742{
743  int  res;
744  int  status;
745  long size;
746  int  errcode;
747
748  /* Close reading side of pipe, and wait some milliseconds
749   */
750  sl_close_fd (FIL__, __LINE__, mpipe[1]);
751  retry_msleep (0, ShKernDelay); /* milliseconds */
752
753  if (sizeof(int) != read(mpipe[0], &errcode, sizeof(int)))
754    status = -3;
755  else
756    status = 0;
757
758  if (errcode)
759    status = errcode - 100;
760
761  if(status == 0)
762    {
763      size = SH_KERN_SIZ * sizeof(unsigned long);
764
765      if (size != read(mpipe[0], &(kinfo->kmem_call_table), size))
766        status = -4;
767      else
768        status = 0;
769    }
770
771  if(status == 0)
772    {
773      size = sizeof(unsigned int) * 2 * SH_KERN_SIZ;
774
775      if (size != read(mpipe[0], &(kinfo->kmem_code_table), size))
776        status = -5;
777      else
778        status = 0;
779    }
780
781  if(status == 0)
782    {
783      memset(sh_idt_table, '\0', SH_MAXIDT*8);
784      if (sizeof(sh_idt_table) != 
785          read(mpipe[0], &sh_idt_table, sizeof(sh_idt_table)))
786        status = -5;
787      else
788        status = 0;
789    }
790
791  if(status == 0)
792    {
793      size = SH_KERN_SCC;
794
795      if (size != read(mpipe[0], &(kinfo->new_system_call_code), size))
796        status = -6;
797      else
798        status = 0;
799    }
800 
801  if(status == 0)
802    {
803      size = sizeof (struct proc_dir_entry);
804
805      if (size != read(mpipe[0], &(kinfo->proc_root_dir), size))
806        status = -7;
807      else
808        status = 0;
809    }
810
811  if(status == 0)
812    {
813      size = sizeof (struct inode_operations);
814
815      if (size != read(mpipe[0], &(kinfo->proc_root_inode), size))
816        status = -8;
817      else
818        status = 0;
819    }
820
821  if (status < 0)
822    res = waitpid(mpid, NULL,    WNOHANG|WUNTRACED);
823  else 
824    {
825      res = waitpid(mpid, &status, WNOHANG|WUNTRACED);
826      if (res == 0 && 0 != WIFEXITED(status))
827        status = WEXITSTATUS(status);
828    }
829  sl_close_fd (FIL__, __LINE__, mpipe[0]);
830  if (res <= 0)
831    {
832      aud_kill(FIL__, __LINE__, mpid, 9);
833      waitpid(mpid, NULL, 0);
834    }
835  return status;
836}
837
838
839static void check_idt_table(int is_init)
840{
841  int            i, j;
842
843  unsigned short idt_offset_lo, idt_offset_hi, idt_selector;
844  unsigned char  idt_reserved, idt_flag;
845  unsigned short sh_idt_offset_lo, sh_idt_offset_hi, sh_idt_selector;
846  unsigned char  sh_idt_reserved, sh_idt_flag;
847  int            dpl;
848  unsigned long  idt_iaddr;
849  int            sh_dpl;
850  unsigned long  sh_idt_iaddr;
851  char           idt_type, sh_idt_type;
852
853  unsigned long store0;
854  unsigned int  store1, store2;
855  int           datasize;
856  char          msg[2*SH_BUFSIZE];
857
858  if (ShKernIDT == S_TRUE)
859    {
860      if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
861        {
862          datasize = 8;
863          for (j = 0; j < SH_MAXIDT; ++j) 
864            {
865              sh_kern_db_syscall (j, _("idt_table"), 
866                                  &sh_idt_table[j*8], 
867                                  &store0, &store1, &store2,
868                                  &datasize, SH_KERN_DBPUSH);
869            }
870        }
871
872      if ((sh.flag.checkSum != SH_CHECK_INIT) || 
873          (sh.flag.update == S_TRUE && is_init == 1))
874        {
875          /* Check the Interrupt Descriptor Table
876           *
877           * Stored(old) is idt_table[]
878           */
879          for (j = 0; j < SH_MAXIDT; ++j)
880            {
881              i = j * 8;
882         
883              sh_idt_offset_lo = *((unsigned short *) &sh_idt_table[i]);
884              sh_idt_selector  = *((unsigned short *) &sh_idt_table[i+2]);
885              sh_idt_reserved  = (unsigned char) sh_idt_table[i+4];
886              sh_idt_flag      = (unsigned char) sh_idt_table[i+5];
887              sh_idt_offset_hi = *((unsigned short *) &sh_idt_table[i+6]);
888              sh_idt_iaddr = (unsigned long)(sh_idt_offset_hi << 16) 
889                + sh_idt_offset_lo;
890             
891              if (sh_idt_iaddr == 0)
892                {
893                  sh_idt_table[i+2] = '\0';
894                  sh_idt_table[i+3] = '\0';
895                  sh_idt_table[i+5] = '\0';
896
897                  idt_offset_lo = *((unsigned short *) &idt_table[i]);
898                  idt_offset_hi = *((unsigned short *) &idt_table[i+6]);
899                  idt_iaddr = (unsigned long)(idt_offset_hi << 16) 
900                    + idt_offset_lo;
901                  if (idt_iaddr == 0)
902                    {
903                      idt_table[i+2] = '\0';
904                      idt_table[i+3] = '\0';
905                      idt_table[i+5] = '\0';
906                    }
907                 
908                }
909         
910              if (memcmp(&sh_idt_table[i], &idt_table[i], 8) != 0)
911                {
912                 
913                  idt_offset_lo = *((unsigned short *) &idt_table[i]);
914                  idt_selector  = *((unsigned short *) &idt_table[i+2]);
915                  idt_reserved  = (unsigned char) idt_table[i+4];
916                  idt_flag      = (unsigned char) idt_table[i+5];
917                  idt_offset_hi = *((unsigned short *) &idt_table[i+6]);
918                  idt_iaddr = (unsigned long)(idt_offset_hi << 16) 
919                    + idt_offset_lo;
920             
921                  if (idt_iaddr != 0)
922                    {
923                      if (idt_flag & 64) { dpl = 3; }
924                      else               { dpl = 0; }
925                      if (idt_flag & 1)  { 
926                        if (dpl == 3) idt_type = 'S'; 
927                        else idt_type = 'T'; }
928                      else               { idt_type = 'I'; }
929                    }
930                  else { dpl = -1; idt_type = 'U'; }
931                 
932                  if (sh_idt_iaddr != 0)
933                    {
934                      if (sh_idt_flag & 64) { sh_dpl = 3; }
935                      else               { sh_dpl = 0; }
936                      if (sh_idt_flag & 1)  { 
937                        if (sh_dpl == 3) sh_idt_type = 'S'; 
938                        else sh_idt_type = 'T'; }
939                      else               { sh_idt_type = 'I'; }
940                    }
941                  else { sh_dpl = -1; sh_idt_type = 'U'; }
942                 
943                  sh_kern_pathmsg (msg, SH_BUFSIZE,
944                                   j, _("idt_table"),
945                                   &idt_table[i], 8,
946                                   &sh_idt_table[i], 8);
947
948                  sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
949                                   0, MSG_KERN_IDT,
950                                   j, 
951                                   sh_idt_iaddr, sh_strseg(sh_idt_selector), 
952                                   (int) sh_dpl, sh_idt_type, 
953                                   idt_iaddr, sh_strseg(idt_selector),
954                                   (int) dpl, idt_type, msg);
955                 
956                  memcpy(&idt_table[i], &sh_idt_table[i], 8);
957                }
958            }
959        }
960    }
961}
962
963
964#define SYS_BUS_PCI _("/sys/bus/pci/devices")
965#include <dirent.h>
966
967static void check_rom (char * pcipath, char * name)
968{
969  file_type       theFile;
970  char            fileHash[2*(KEY_LEN + 1)];
971  int             status;
972  char          * tmp;
973  extern unsigned long sh_files_maskof (int class);
974
975  (void) sl_strlcpy (theFile.fullpath, pcipath, PATH_MAX);
976  theFile.check_mask  = sh_files_maskof(SH_LEVEL_READONLY);
977  theFile.check_mask &= ~(MODI_MTM|MODI_CTM|MODI_INO);
978  CLEAR_SH_FFLAG_REPORTED(theFile.file_reported);
979  theFile.attr_string = NULL;
980  theFile.link_path   = NULL;
981 
982  status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO], 
983                            name, &theFile, fileHash, 0);
984
985  if (status != 0)
986    {
987      tmp = sh_util_safe_name(pcipath);
988      sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
989                       0, MSG_E_SUBGPATH,
990                       _("Could not check PCI ROM"),
991                       _("check_rom"),
992                       tmp);
993      SH_FREE(tmp);
994      goto out;
995    }
996
997  if ( sh.flag.checkSum == SH_CHECK_INIT ) 
998    {
999      sh_hash_pushdata (&theFile, fileHash);
1000    }
1001  else if (sh.flag.checkSum == SH_CHECK_CHECK ) 
1002    {
1003      sh_hash_compdata (SH_LEVEL_READONLY, &theFile, fileHash, NULL, -1);
1004    }
1005
1006 out:
1007  if (theFile.attr_string) SH_FREE(theFile.attr_string);
1008  if (theFile.link_path)   SH_FREE(theFile.link_path);
1009  return;
1010}
1011
1012static void check_pci_rom (char * pcipath, char * name)
1013{
1014  struct stat buf;
1015  int         fd;
1016  int         status;
1017
1018  if (0 == stat(pcipath, &buf))
1019    {
1020      /* Need to write "1" to the file to enable the ROM. Afterwards,
1021       * write "0" to disable it.
1022       */
1023      fd = open ( pcipath, O_RDWR );
1024      if (fd)
1025        {
1026          do {
1027            status = write( fd, "1", 1 );
1028          } while (status < 0 && errno == EINTR);
1029          sl_close_fd (FIL__, __LINE__,  fd );
1030
1031          if (status > 0)
1032            {
1033              check_rom(pcipath, name);
1034             
1035              fd = open ( pcipath, O_RDWR );
1036              if (fd)
1037                {
1038                  do {
1039                    status = write( fd, "0", 1 );
1040                  } while (status < 0 && errno == EINTR);
1041                  sl_close_fd (FIL__, __LINE__,  fd );
1042                }
1043            }
1044        }
1045    }
1046  return;
1047}
1048
1049static void check_pci()
1050{
1051  char pci_dir[256];
1052  char * pcipath;
1053  DIR * df;
1054  struct dirent * entry;
1055
1056  if (ShKernPCI != S_TRUE)
1057    return;
1058
1059  sl_strlcpy(pci_dir, SYS_BUS_PCI, sizeof(pci_dir));
1060
1061  df = opendir(pci_dir);
1062  if (df)
1063    {
1064      while (1)
1065        {
1066          SH_MUTEX_LOCK(mutex_readdir);
1067          entry = readdir(df);
1068          SH_MUTEX_UNLOCK(mutex_readdir);
1069
1070          if (entry == NULL)
1071            break;
1072
1073          if (0 == strcmp(entry->d_name, ".") && 
1074              0 == strcmp(entry->d_name, ".."))
1075            continue;
1076
1077          pcipath = sh_util_strconcat(pci_dir, "/", 
1078                                      entry->d_name, "/rom", NULL);
1079          check_pci_rom(pcipath, entry->d_name);
1080          SH_FREE(pcipath);
1081        }
1082
1083      closedir(df);
1084    }
1085  return;
1086}
1087
1088/* -- Check the proc_root inode.
1089 *
1090 * This will detect adore-ng.
1091 */
1092static void check_proc_root (struct sh_kernel_info * kinfo)
1093{
1094  struct proc_dir_entry     proc_root_dir;
1095  struct inode_operations * proc_root_inode_op = NULL;
1096
1097/* 2.6.21 (((2) << 16) + ((6) << 8) + (21)) */
1098#if SH_KERNEL_NUMBER < KERNEL_VERSION(2,6,21)
1099  struct inode_operations proc_root_inode;
1100
1101  memcpy (&proc_root_inode, &(kinfo->proc_root_inode), sizeof(struct inode_operations));
1102
1103  /* Seems that the info does not relate anymore to proc_root_lookup(?)
1104   */
1105  if ( (unsigned int) *proc_root_inode.lookup != proc_root_lookup)
1106    {
1107      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
1108                       _("proc_root_inode_operations.lookup != proc_root_lookup"));
1109    }
1110#endif
1111
1112  memcpy (&proc_root_dir,   &(kinfo->proc_root_dir),   sizeof(struct proc_dir_entry));
1113
1114  if (((unsigned long) * &proc_root_dir.proc_iops) == proc_root_iops)
1115    {
1116      proc_root_inode_op = (struct inode_operations *) &(proc_root_dir.proc_iops);
1117    }
1118  else if (proc_root_dir.size == proc_root_iops)
1119    {
1120      proc_root_inode_op = (struct inode_operations *) &(proc_root_dir.size);
1121    }
1122  else if ((unsigned long) * &proc_root_dir.proc_fops == proc_root_iops)
1123    {
1124      proc_root_inode_op = (struct inode_operations *) &(proc_root_dir.proc_fops);
1125    }
1126
1127  if (!proc_root_inode_op)
1128    {
1129      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
1130                       _("proc_root.proc_iops != proc_root_inode_operations"));
1131    }
1132
1133  return;
1134}
1135
1136/* -- Check the system_call syscall gate.
1137 *
1138 * Stored(old) is system_call_code[]
1139 */
1140static void check_syscall_gate(int is_init, struct sh_kernel_info * kinfo)
1141{
1142  int           i, j;
1143  unsigned long store0;
1144  unsigned int  store1, store2;
1145  int           datasize;
1146  int           max_system_call = (SYS_CALL_LOC < 128) ? 128 : SYS_CALL_LOC;
1147  char          msg[2*SH_BUFSIZE];
1148 
1149  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
1150    {
1151      store0 = 0; store1 = 0; store2 = 0;
1152      datasize = SH_KERN_SCC;
1153      sh_kern_db_syscall (0, _("system_call"), 
1154                          &(kinfo->new_system_call_code), &store0, &store1, &store2,
1155                          &datasize, SH_KERN_DBPUSH);
1156    }
1157
1158  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
1159      (sh.flag.update == S_TRUE && is_init == 1))
1160    {
1161      for (i = 0; i < (max_system_call + 4); ++i) 
1162        {
1163          if (system_call_code[i] != kinfo->new_system_call_code[i])
1164            {
1165
1166              sh_kern_pathmsg (msg, sizeof(msg),
1167                               0, _("system_call"),
1168                               system_call_code, SH_KERN_SCC,
1169                               kinfo->new_system_call_code, SH_KERN_SCC);
1170
1171              sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
1172                               0, MSG_KERN_GATE,
1173                               kinfo->new_system_call_code[i], 0,
1174                               system_call_code[i], 0,
1175                               0, _("system_call (interrupt handler)"),
1176                               msg);
1177             
1178              for (j = 0; j < (max_system_call + 4); ++j)
1179                system_call_code[j] = kinfo->new_system_call_code[j];
1180              break;
1181            }
1182        }
1183    }
1184  return;
1185}
1186
1187static void check_system_calls (int is_init, struct sh_kernel_info * kinfo)
1188{
1189  int           i;
1190
1191#ifdef SH_USE_LKM
1192  static int check_getdents      = 0;
1193  /* #ifdef __NR_getdents64 */
1194  static int check_getdents64    = 0;
1195  /* #endif */
1196  static int copy_if_next        = -1;
1197  static int copy_if_next_64     = -1;
1198#endif
1199
1200  unsigned long store0;
1201  unsigned int  store1, store2;
1202  int           mod_syscall_addr = 0;
1203  int           mod_syscall_code = 0;
1204  UINT64        size_old  = 0, size_new = 0;
1205  UINT64        mtime_old = 0, mtime_new = 0;
1206  UINT64        ctime_old = 0, ctime_new = 0;
1207  char          tmp[128];
1208  char          msg[2*SH_BUFSIZE];
1209  char timstr_o[32];
1210  char timstr_n[32];
1211
1212  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
1213    {
1214      for (i = 0; i < SH_MAXCALLS; ++i) 
1215        {
1216          store0 = kinfo->kmem_call_table[i]; 
1217          store1 = kinfo->kmem_code_table[i][0]; store2 = kinfo->kmem_code_table[i][1];
1218          sh_kern_db_syscall (i, _("syscall"), 
1219                              NULL, &store0, &store1, &store2,
1220                              0, SH_KERN_DBPUSH);
1221        }
1222    }
1223
1224  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
1225      (sh.flag.update == S_TRUE && is_init == 1))
1226    {
1227      for (i = 0; i < SH_MAXCALLS; ++i) 
1228        {
1229          if (sh_syscalls[i].name == NULL /* || sh_syscalls[i].addr == 0UL */)
1230            break;
1231
1232#ifdef SH_USE_LKM
1233          if (sh_syscalls[i].addr != kinfo->kmem_call_table[i])
1234            {
1235              if (check_getdents == 0 && 
1236                  0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents")))
1237                {
1238                  check_getdents = 1;
1239                  sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
1240                                   0, MSG_E_SUBGEN,
1241                                   _("Modified kernel syscall (expected)."),
1242                                   _(sh_syscalls[i].name) );
1243                  copy_if_next = i;
1244                  sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1245                  continue;
1246                }
1247              /* #ifdef __NR_getdents64 */
1248              else if  (check_getdents64 == 0 && 
1249                        0 == strcmp(_(sh_syscalls[i].name), 
1250                                    _("sys_getdents64")))
1251                {
1252                  check_getdents64 = 1;
1253                  sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, 
1254                                   0, MSG_E_SUBGEN,
1255                                   _("Modified kernel syscall (expected)."),
1256                                   _(sh_syscalls[i].name) );
1257                  copy_if_next_64 = i;
1258                  sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1259                  continue;
1260                }
1261              /* #endif */
1262              else
1263                {
1264                  size_old = sh_syscalls[i].addr;
1265                  size_new = kinfo->kmem_call_table[i];
1266                  mod_syscall_addr = 1;
1267                }
1268              sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1269            }
1270#else
1271          if (sh_syscalls[i].addr != kinfo->kmem_call_table[i])
1272            {
1273              size_old = sh_syscalls[i].addr;
1274              size_new = kinfo->kmem_call_table[i];
1275              mod_syscall_addr = 1;
1276              sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1277            }
1278#endif
1279
1280
1281          /* -- Check the code at syscall address
1282           *
1283           * Stored(old) is sh_syscalls[]
1284           */
1285          if ( (mod_syscall_addr == 0) && 
1286               ((sh_syscalls[i].code[0] != kinfo->kmem_code_table[i][0]) || 
1287                (sh_syscalls[i].code[1] != kinfo->kmem_code_table[i][1]))
1288               )
1289            {
1290              mtime_old = sh_syscalls[i].code[0];
1291              mtime_new = kinfo->kmem_code_table[i][0];
1292              ctime_old = sh_syscalls[i].code[1];
1293              ctime_new = kinfo->kmem_code_table[i][1];
1294              mod_syscall_code = 1;
1295
1296#ifdef SH_USE_LKM
1297              if (i == copy_if_next)
1298                {
1299                  mod_syscall_code =  0;
1300                  copy_if_next     = -1;
1301                }
1302              if (i == copy_if_next_64)
1303                {
1304                  mod_syscall_code =  0;
1305                  copy_if_next_64  = -1;
1306                }
1307#endif
1308
1309              sh_syscalls[i].code[0] = kinfo->kmem_code_table[i][0];
1310              sh_syscalls[i].code[1] = kinfo->kmem_code_table[i][1];
1311            }
1312
1313          /* Build the error message, if something has been
1314           * detected.
1315           */
1316          if ((mod_syscall_addr != 0) || (mod_syscall_code != 0))
1317            {
1318#ifdef SH_USE_XML
1319              sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
1320                          _("syscall"), i);
1321#else
1322              sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
1323                          _("syscall"), i);
1324#endif
1325              sl_strlcpy(msg, tmp, SH_BUFSIZE);
1326
1327              if (mod_syscall_addr != 0)
1328                {
1329                  sl_snprintf(tmp, 128, sh_hash_size_format(),
1330                              size_old, size_new);
1331                  sl_strlcat(msg, tmp, SH_BUFSIZE); 
1332                }
1333              if (mod_syscall_code != 0)
1334                {
1335                  (void) sh_unix_gmttime (ctime_old, timstr_o, sizeof(timstr_o));
1336                  (void) sh_unix_gmttime (ctime_new, timstr_n, sizeof(timstr_n));
1337#ifdef SH_USE_XML
1338                  sl_snprintf(tmp, 128, 
1339                              _("ctime_old=\"%s\" ctime_new=\"%s\" "), 
1340                              timstr_o, timstr_n);
1341#else
1342                  sl_snprintf(tmp, 128, 
1343                              _("ctime_old=<%s>, ctime_new=<%s>, "), 
1344                              timstr_o, timstr_n);
1345#endif
1346                  sl_strlcat(msg, tmp, SH_BUFSIZE); 
1347                  (void) sh_unix_gmttime (mtime_old, timstr_o, sizeof(timstr_o));
1348                  (void) sh_unix_gmttime (mtime_new, timstr_n, sizeof(timstr_n));
1349#ifdef SH_USE_XML
1350                  sl_snprintf(tmp, 128, 
1351                              _("mtime_old=\"%s\" mtime_new=\"%s\" "), 
1352                              timstr_o, timstr_n);
1353#else
1354                  sl_snprintf(tmp, 128, 
1355                              _("mtime_old=<%s>, mtime_new=<%s> "), 
1356                              timstr_o, timstr_n);
1357#endif
1358                  sl_strlcat(msg, tmp, SH_BUFSIZE); 
1359                }
1360              sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
1361                               0, MSG_KERN_SYSCALL,
1362                               i, _(sh_syscalls[i].name), msg);
1363              mod_syscall_addr = 0;
1364              mod_syscall_code = 0;
1365            }
1366        }
1367    }
1368  return;
1369}
1370 
1371int sh_kern_check_internal ()
1372{
1373  int kd;
1374  int is_init;
1375  pid_t mpid;
1376  int mpipe[2];
1377  int status = 0;
1378
1379  struct sh_kernel_info kinfo;
1380
1381
1382  SL_ENTER(_("sh_kern_check_internal"));
1383
1384  /* -- Check whether initialisation is required; if yes, initialize.
1385   */
1386
1387  if (0 != check_init(&is_init))
1388    {
1389      SL_RETURN( (-1), _("sh_kern_check_internal"));
1390    }
1391
1392
1393  /* -- Open /dev/kmem and fork subprocess to read from it.
1394   */
1395   
1396  if (kaddr == (unsigned int) -1) /* kaddr = address of the sys_call_table */
1397    {
1398      sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN,
1399                       _("no address for sys_call_table - switching off"),
1400                       _("kern_check_internal") );
1401      ShKernActive = S_FALSE;
1402      SL_RETURN( (-1), _("sh_kern_check_internal"));
1403    }
1404 
1405  kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/dev/kmem"), O_RDONLY, 0);
1406 
1407  if (kd < 0)
1408    {
1409      kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/proc/kmem"), O_RDONLY, 0);
1410    }
1411
1412  if (kd < 0)
1413    {
1414      status = errno;
1415      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1416                       _("error opening /dev/kmem"),
1417                       _("kern_check_internal") );
1418      SL_RETURN( (-1), _("sh_kern_check_internal"));
1419    }
1420
1421  status = aud_pipe(FIL__, __LINE__, mpipe);
1422
1423  if (status == 0)
1424    {
1425      mpid = aud_fork(FIL__, __LINE__);
1426
1427      switch (mpid) 
1428        {
1429        case -1:
1430          status = -1;
1431          break;
1432        case 0: 
1433
1434          /* -- Child process reads /dev/kmem and writes to pipe
1435           */
1436          run_child(kd, mpipe);
1437          break;
1438         
1439          /* -- Parent process reads from child via pipe
1440           */
1441        default:
1442          sl_close_fd(FIL__, __LINE__, kd);
1443          status = read_from_child(mpid, mpipe, &kinfo);
1444          break;
1445        }
1446    }
1447
1448  if ( status < 0)
1449    {
1450      char errmsg[SH_ERRBUF_SIZE];
1451      sl_snprintf(errmsg, SH_ERRBUF_SIZE, 
1452                  _("error reading from /dev/kmem: %d"), status);
1453      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1454                       errmsg,
1455                       _("kern_check_internal") );
1456      SL_RETURN( (-1), _("sh_kern_check_internal"));
1457    }
1458
1459  /* -- Check the proc_root inode.
1460   *
1461   * This will detect adore-ng.
1462   */
1463  check_proc_root( &kinfo );
1464
1465
1466  /* -- Check the system_call syscall gate.
1467   *
1468   * Stored(old) is system_call_code[]
1469   */
1470  check_syscall_gate( is_init, &kinfo );
1471
1472  /* -- Check the individual syscalls
1473   *
1474   * Stored(old) is sh_syscalls[] array.
1475   */
1476  check_system_calls ( is_init, &kinfo );
1477
1478  /* -- Check the Interrupt Descriptor Table
1479   */
1480  check_idt_table(is_init);
1481
1482  /* -- Check PCI ROM
1483   */
1484  check_pci();
1485
1486  SL_RETURN( (0), _("sh_kern_check_internal"));
1487}
1488/* ifdef HOST_IS_LINUX */
1489#else
1490
1491/********************************************************
1492 *
1493 *  --- BSD ---
1494 *
1495 ********************************************************/
1496
1497#include <err.h>
1498#include <kvm.h>
1499#include <nlist.h>
1500
1501/* not OpenBSD */
1502#if defined(HOST_IS_FREEBSD)
1503#include <sys/sysent.h>
1504#endif
1505
1506#include <sys/syscall.h>
1507#ifndef  SYS_MAXSYSCALL
1508#define  SYS_MAXSYSCALL 512
1509#endif
1510
1511#ifdef __OpenBSD__
1512struct proc;
1513struct sysent {
1514        short sy_narg;
1515        short sy_argsize;
1516        int   (*sy_call)(struct proc *, void *, register_t *);
1517};
1518#endif
1519
1520int sh_kern_data_init ()
1521{
1522  unsigned long store0 = 0;
1523  unsigned int  store1 = 0, store2 = 0;
1524  int           datasize, i;
1525  char        * databuf = NULL;
1526
1527  /* syscall address and code
1528   */ 
1529  for (i = 0; i < SH_MAXCALLS; ++i) 
1530    {
1531      databuf = sh_kern_db_syscall (i, _("syscall"), 
1532                                    NULL, &store0, &store1, &store2,
1533                                    &datasize, SH_KERN_DBPOP);
1534      sh_syscalls[i].addr = store0;
1535      if (databuf != NULL) { SH_FREE(databuf); }
1536      if (store0 == 0) {
1537        sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1538                        _("syscall address not found in database"), 
1539                        _("sh_kern_data_init"));
1540        return -1;
1541      }
1542
1543      sh_syscalls[i].code[0] = (unsigned int) store1; 
1544      sh_syscalls[i].code[1] = (unsigned int) store2;
1545      if ((store1 == 0) || (store2 == 0)) {
1546        sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1547                        _("syscall code not found in database"), 
1548                        _("sh_kern_data_init"));
1549        return -1;
1550      }
1551
1552    }
1553
1554  return 0;
1555}
1556
1557int sh_kern_check_internal ()
1558{
1559  struct sysent  sy;
1560  kvm_t * kd;
1561  int     i;
1562  int     status = -1;
1563  char    errbuf[_POSIX2_LINE_MAX+1];
1564  struct  nlist * sys_list;
1565  struct  nlist list[2];
1566
1567  unsigned long offset = 0L;
1568  unsigned int  syscall_code[2];  /* 8 bytes */
1569  unsigned long syscall_addr;
1570
1571  unsigned long store0 = 0;
1572  unsigned int  store1 = 0, store2 = 0;
1573
1574  UINT64        size_old  = 0, size_new = 0;
1575  UINT64        mtime_old = 0, mtime_new = 0;
1576  UINT64        ctime_old = 0, ctime_new = 0;
1577  char          tmp[128];
1578  char          msg[2*SH_BUFSIZE];
1579  char timstr_o[32];
1580  char timstr_n[32];
1581
1582  static int is_init = 0;
1583
1584  SL_ENTER(_("sh_kern_check_internal"));
1585
1586  if (is_init == 0)
1587    { 
1588      if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE)
1589        {
1590          if (0 == sh_kern_data_init()) {
1591            is_init = 1;
1592          } else {
1593            sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, 
1594                             MSG_E_SUBGEN,
1595                             _("could not initialize - switching off"),
1596                             _("kern_check_internal") );
1597            ShKernActive = S_FALSE;
1598            SL_RETURN( (-1), _("sh_kern_check_internal"));
1599          }
1600        }
1601      else if ((sh.flag.checkSum == SH_CHECK_INIT ||
1602                sh.flag.checkSum == SH_CHECK_CHECK) && 
1603               (sh.flag.update == S_TRUE))
1604        {       
1605          if (0 == sh_kern_data_init()) {
1606            is_init = 1;
1607          } else {
1608            sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, 
1609                             MSG_E_SUBGEN,
1610                             _("no or incomplete data in baseline database"),
1611                             _("kern_check_internal") );
1612          }
1613        }
1614    }
1615
1616  /* defined, but not used
1617   */
1618  ShKernDelay    = 0;
1619   
1620  list[0].n_name = "_sysent";
1621  list[1].n_name = NULL;
1622
1623  kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
1624  if (!kd)
1625    {
1626      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1627                       errbuf,
1628                       _("kvm_openfiles") );
1629      SL_RETURN( (-1), _("sh_kern_check_internal"));
1630    }
1631
1632  i = kvm_nlist(kd, list);
1633  if (i == -1)
1634    {
1635      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1636                       kvm_geterr(kd),
1637                       _("kvm_nlist (_sysent)") );
1638      kvm_close(kd);
1639      SL_RETURN( (-1), _("sh_kern_check_internal"));
1640    }
1641
1642  sys_list = SH_ALLOC((SYS_MAXSYSCALL+1) * sizeof(struct nlist));
1643
1644  for (i = 0; i < SH_MAXCALLS; ++i)
1645    sys_list[i].n_name = sh_syscalls[i].name;
1646  sys_list[SH_MAXCALLS].n_name = NULL;
1647
1648  i = kvm_nlist(kd, sys_list);
1649  if (i == -1)
1650    {
1651      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1652                       kvm_geterr(kd),
1653                       _("kvm_nlist (syscalls)") );
1654      kvm_close(kd);
1655      SH_FREE(sys_list);
1656      SL_RETURN( (-1), _("sh_kern_check_internal"));
1657    }
1658  else if (i > 0)
1659    {
1660      sl_snprintf(tmp, 128,
1661                  _("%d invalid syscalls"), i);
1662      /*
1663      for (i = 0; i < SH_MAXCALLS; ++i) {
1664        if (sys_list[i].n_type == 0 && sys_list[i].n_value == 0)
1665          fprintf(stderr, "invalid: [%3d] %s\n", i, sh_syscalls[i].name);
1666      }
1667      */
1668      sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1669                       tmp,
1670                       _("kvm_nlist (syscalls)") );
1671    }
1672
1673  /* Check the individual syscalls
1674   *
1675   * Stored(old) is sh_syscalls[] array.
1676   */
1677  if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
1678    {
1679      for (i = 0; i < SH_MAXCALLS; ++i) 
1680        {
1681          if (sh_syscalls[i].name == NULL)
1682            {
1683              sl_snprintf(tmp, 128, 
1684                          _("too few entries in sh_syscalls[]: have %d, expect %d"), 
1685                          i, SH_MAXCALLS);
1686
1687              sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1688                               tmp,
1689                               _("sh_kern_check_internal") );
1690              break;
1691            }
1692
1693          /* read address of syscall from sysent table
1694           */
1695          offset = list[0].n_value + (i*sizeof(struct sysent));
1696          if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0)
1697            {
1698              sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1699                               kvm_geterr(kd),
1700                               _("kvm_read (syscall table)") );
1701              kvm_close(kd);
1702              SH_FREE(sys_list);
1703              SL_RETURN( (-1), _("sh_kern_check_internal"));
1704            }
1705          syscall_addr = (unsigned long) sy.sy_call;
1706          store0 = syscall_addr;
1707         
1708          /* read the syscall code
1709           */
1710          if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]), 
1711                      2 * sizeof(unsigned int)) < 0)
1712            {
1713              sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1714                               kvm_geterr(kd),
1715                               _("kvm_read (syscall code)") );
1716              kvm_close(kd);
1717              SH_FREE(sys_list);
1718              SL_RETURN( (-1), _("sh_kern_check_internal"));
1719            }
1720          store1 = syscall_code[0]; store2 = syscall_code[1];
1721         
1722          sh_kern_db_syscall (i, _("syscall"), 
1723                              NULL, &store0, &store1, &store2,
1724                              0, SH_KERN_DBPUSH);
1725        }
1726    }
1727
1728  if ((sh.flag.checkSum != SH_CHECK_INIT) || 
1729      (sh.flag.update == S_TRUE && is_init == 1))
1730    {
1731      for (i = 0; i < SH_MAXCALLS; ++i)
1732        {
1733          if (sh_syscalls[i].name == NULL)
1734            {
1735              sl_snprintf(tmp, 128, 
1736                          _("too few entries in sh_syscalls[]: have %d, expect %d"), 
1737                          i, SH_MAXCALLS);
1738
1739              sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1740                               tmp,
1741                               _("sh_kern_check_internal") );
1742              break;
1743            }
1744         
1745          /* read address of syscall from sysent table
1746           */
1747          offset = list[0].n_value + (i*sizeof(struct sysent));
1748          if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0)
1749            {
1750              sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1751                               kvm_geterr(kd),
1752                               _("kvm_read (syscall table)") );
1753              kvm_close(kd);
1754              SH_FREE(sys_list);
1755              SL_RETURN( (-1), _("sh_kern_check_internal"));
1756            }
1757          syscall_addr = (unsigned long) sy.sy_call;
1758         
1759          if (sh_syscalls[i].addr != syscall_addr)
1760            {
1761#ifdef SH_USE_XML
1762              sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
1763                          _("syscall"), i);
1764#else
1765              sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
1766                          _("syscall"), i);
1767#endif
1768              sl_strlcpy(msg, tmp, SH_BUFSIZE);
1769
1770              size_old = sh_syscalls[i].addr; 
1771              size_new = syscall_addr;
1772              sl_snprintf(tmp, 128, sh_hash_size_format(),
1773                          size_old, size_new);
1774              sl_strlcat(msg, tmp, SH_BUFSIZE);
1775 
1776              sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
1777                               status, MSG_KERN_SYSCALL,
1778                               i, _(sh_syscalls[i].name),
1779                               msg);
1780              sh_syscalls[i].addr = syscall_addr;
1781            }
1782          else
1783            {   
1784              /* read the syscall code
1785               */
1786              if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]), 
1787                          2 * sizeof(unsigned int)) < 0)
1788                {
1789                  sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1790                                   kvm_geterr(kd),
1791                                   _("kvm_read (syscall code)") );
1792                  kvm_close(kd);
1793                  SH_FREE(sys_list);
1794                  SL_RETURN( (-1), _("sh_kern_check_internal"));
1795                }
1796             
1797              if (sh_syscalls[i].code[0] != syscall_code[0] || 
1798                  sh_syscalls[i].code[1] != syscall_code[1])
1799                {
1800                  mtime_old = sh_syscalls[i].code[0];
1801                  mtime_new = syscall_code[0];
1802                  ctime_old = sh_syscalls[i].code[1];
1803                  ctime_new = syscall_code[1];
1804
1805#ifdef SH_USE_XML
1806                  sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", 
1807                              _("syscall"), i);
1808#else
1809                  sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ", 
1810                              _("syscall"), i);
1811#endif
1812                  sl_strlcpy(msg, tmp, SH_BUFSIZE);
1813
1814                  (void) sh_unix_gmttime (ctime_old, timstr_o, sizeof(timstr_o));
1815                  (void) sh_unix_gmttime (ctime_new, timstr_n, sizeof(timstr_n));
1816#ifdef SH_USE_XML
1817                  sl_snprintf(tmp, 128, 
1818                              _("ctime_old=\"%s\" ctime_new=\"%s\" "), 
1819                              timstr_o, timstr_n);
1820#else
1821                  sl_snprintf(tmp, 128, 
1822                              _("ctime_old=<%s>, ctime_new=<%s>, "), 
1823                              timstr_o, timstr_n);
1824#endif
1825                  sl_strlcat(msg, tmp, SH_BUFSIZE); 
1826                  (void) sh_unix_gmttime (mtime_old, timstr_o, sizeof(timstr_o));
1827                  (void) sh_unix_gmttime (mtime_new, timstr_n, sizeof(timstr_n));
1828#ifdef SH_USE_XML
1829                  sl_snprintf(tmp, 128, 
1830                              _("mtime_old=\"%s\" mtime_new=\"%s\" "), 
1831                              timstr_o, timstr_n);
1832#else
1833                  sl_snprintf(tmp, 128, 
1834                              _("mtime_old=<%s>, mtime_new=<%s> "), 
1835                              timstr_o, timstr_n);
1836#endif
1837                  sl_strlcat(msg, tmp, SH_BUFSIZE); 
1838
1839                  sh_error_handle (ShKernSeverity, FIL__, __LINE__, 
1840                                   status, MSG_KERN_SYSCALL,
1841                                   i, _(sh_syscalls[i].name),
1842                                   msg);
1843                  sh_syscalls[i].code[0] = syscall_code[0];
1844                  sh_syscalls[i].code[1] = syscall_code[1];
1845                }
1846            }
1847        }
1848    }
1849  SH_FREE(sys_list);
1850  if(kvm_close(kd) < 0)
1851    {
1852      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1853                       kvm_geterr(kd),
1854                       _("kvm_close") );
1855      exit(EXIT_FAILURE);
1856    }
1857
1858  SL_RETURN( (0), _("sh_kern_check_internal"));
1859}
1860
1861#endif
1862
1863/*************
1864 *
1865 * module init
1866 *
1867 *************/
1868#if defined(HOST_IS_LINUX)
1869#include <sys/utsname.h>
1870#endif
1871
1872static int AddressReconf = 0;
1873
1874int sh_kern_init (struct mod_type * arg)
1875{
1876#if defined(HOST_IS_LINUX)
1877  struct utsname buf;
1878  char         * str;
1879#endif
1880  (void) arg;
1881
1882  SL_ENTER(_("sh_kern_init"));
1883  if (ShKernActive == S_FALSE)
1884    SL_RETURN( (-1), _("sh_kern_init"));
1885
1886#if defined(HOST_IS_LINUX)
1887  uname(&buf);
1888
1889  if ((AddressReconf < 5) && (0 != strcmp(SH_KERNEL_VERSION, buf.release)))
1890    {
1891      str = SH_ALLOC(256);
1892      sl_snprintf(str, 256, 
1893                  "Compiled for kernel %s, but current kernel is %s, and kernel addresses have not been re-configured",
1894                  SH_KERNEL_VERSION, buf.release);
1895      sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1896                       str,
1897                       _("kern_check") );
1898      SH_FREE(str);
1899      ShKernActive = S_FALSE;
1900      SL_RETURN( (-1), _("sh_kern_init"));
1901    }
1902#endif
1903
1904  lastcheck  = time (NULL);
1905  if (sh.flag.checkSum != SH_CHECK_INIT)
1906    {
1907      sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1908                       _("Checking kernel syscalls"),
1909                       _("kern_check") );
1910    }
1911  sh_kern_check_internal ();
1912  SL_RETURN( (0), _("sh_kern_init"));
1913}
1914
1915/*************
1916 *
1917 * module cleanup
1918 *
1919 *************/
1920int sh_kern_end ()
1921{
1922  return (0);
1923}
1924
1925
1926/*************
1927 *
1928 * module timer
1929 *
1930 *************/
1931int sh_kern_timer (time_t tcurrent)
1932{
1933  if (ShKernActive == S_FALSE)
1934    return 0;
1935
1936  if ((int) (tcurrent - lastcheck) >= ShKernInterval)
1937    {
1938      lastcheck  = tcurrent;
1939      return (-1);
1940    }
1941  return 0;
1942}
1943
1944/*************
1945 *
1946 * module check
1947 *
1948 *************/
1949int sh_kern_check ()
1950{
1951  sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1952                   _("Checking kernel syscalls"),
1953                   _("kern_check") );
1954  return (sh_kern_check_internal ());
1955}
1956
1957/*************
1958 *
1959 * module setup
1960 *
1961 *************/
1962
1963int sh_kern_set_severity  (const char * c)
1964{
1965  char tmp[32];
1966  tmp[0] = '='; tmp[1] = '\0';
1967  sl_strlcat (tmp, c, 32);
1968  sh_error_set_level (tmp, &ShKernSeverity);
1969  return 0;
1970}
1971
1972int sh_kern_set_timer (const char * c)
1973{
1974  long val;
1975
1976  SL_ENTER(_("sh_kern_set_timer"));
1977
1978  val = strtol (c, (char **)NULL, 10);
1979  if (val <= 0)
1980    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1981                      _("kern timer"), c);
1982
1983  val = (val <= 0 ? 60 : val);
1984
1985  ShKernInterval = (time_t) val;
1986  SL_RETURN( 0, _("sh_kern_set_timer"));
1987}
1988
1989int sh_kern_set_activate (const char * c)
1990{
1991  int i;
1992  SL_ENTER(_("sh_kern_set_activate"));
1993  i = sh_util_flagval(c, &ShKernActive);
1994  SL_RETURN(i, _("sh_kern_set_activate"));
1995}
1996
1997int sh_kern_set_idt (const char * c)
1998{
1999  int i;
2000  SL_ENTER(_("sh_kern_set_idt"));
2001  i = sh_util_flagval(c, &ShKernIDT);
2002  SL_RETURN(i, _("sh_kern_set_idt"));
2003}
2004
2005int sh_kern_set_pci (const char * c)
2006{
2007  int i;
2008  SL_ENTER(_("sh_kern_set_pci"));
2009  i = sh_util_flagval(c, &ShKernPCI);
2010  SL_RETURN(i, _("sh_kern_set_pci"));
2011}
2012
2013int sh_kern_set_sc_addr (const char * c)
2014{
2015  char * endptr;
2016  unsigned long value;
2017
2018  SL_ENTER(_("sh_kern_set_sc_addr"));
2019  errno = 0;
2020  value = strtoul(c, &endptr, 16);
2021  if ((ULONG_MAX == value) && (errno == ERANGE))
2022    {
2023      SL_RETURN((-1), _("sh_kern_set_sc_addr"));
2024    }
2025  if ((*c == '\0') || (*endptr != '\0'))
2026    {
2027      SL_RETURN((-1), _("sh_kern_set_sc_addr"));
2028    }
2029  system_call_addr = value;
2030  ++AddressReconf;
2031  SL_RETURN((0), _("sh_kern_set_sc_addr"));
2032}
2033
2034int sh_kern_set_sct_addr (const char * c)
2035{
2036  char * endptr;
2037  unsigned long value;
2038
2039  SL_ENTER(_("sh_kern_set_sct_addr"));
2040  errno = 0;
2041  value = strtoul(c, &endptr, 16);
2042  if ((ULONG_MAX == value) && (errno == ERANGE))
2043    {
2044      SL_RETURN((-1), _("sh_kern_set_sct_addr"));
2045    }
2046  if ((*c == '\0') || (*endptr != '\0'))
2047    {
2048      SL_RETURN((-1), _("sh_kern_set_sct_addr"));
2049    }
2050  kaddr = (unsigned int) value;
2051  ++AddressReconf;
2052  SL_RETURN((0), _("sh_kern_set_sct_addr"));
2053}
2054
2055int sh_kern_set_proc_root (const char * c)
2056{
2057  char * endptr;
2058  unsigned long value;
2059
2060  SL_ENTER(_("sh_kern_set_proc_root"));
2061  errno = 0;
2062  value = strtoul(c, &endptr, 16);
2063  if ((ULONG_MAX == value) && (errno == ERANGE))
2064    {
2065      SL_RETURN((-1), _("sh_kern_set_proc_root"));
2066    }
2067  if ((*c == '\0') || (*endptr != '\0'))
2068    {
2069      SL_RETURN((-1), _("sh_kern_set_proc_root"));
2070    }
2071 
2072  proc_root = value;
2073  ++AddressReconf;
2074  SL_RETURN((0), _("sh_kern_set_proc_root"));
2075}
2076
2077int sh_kern_set_proc_root_iops (const char * c)
2078{
2079  char * endptr;
2080  unsigned long value;
2081
2082  SL_ENTER(_("sh_kern_set_proc_root_iops"));
2083  errno = 0;
2084  value = strtoul(c, &endptr, 16);
2085  if ((ULONG_MAX == value) && (errno == ERANGE))
2086    {
2087      SL_RETURN((-1), _("sh_kern_set_proc_root_iops"));
2088    }
2089  if ((*c == '\0') || (*endptr != '\0'))
2090    {
2091      SL_RETURN((-1), _("sh_kern_set_proc_root_iops"));
2092    }
2093 
2094  proc_root_iops = value;
2095  ++AddressReconf;
2096  SL_RETURN((0), _("sh_kern_set_proc_root_iops"));
2097}
2098
2099int sh_kern_set_proc_root_lookup (const char * c)
2100{
2101  char * endptr;
2102  unsigned long value;
2103
2104  SL_ENTER(_("sh_kern_set_proc_root_lookup"));
2105  errno = 0;
2106  value = strtoul(c, &endptr, 16);
2107  if ((ULONG_MAX == value) && (errno == ERANGE))
2108    {
2109      SL_RETURN((-1), _("sh_kern_set_proc_root_lookup"));
2110    }
2111  if ((*c == '\0') || (*endptr != '\0'))
2112    {
2113      SL_RETURN((-1), _("sh_kern_set_proc_root_lookup"));
2114    }
2115  proc_root_lookup = value;
2116  ++AddressReconf;
2117  SL_RETURN((0), _("sh_kern_set_proc_root_lookup"));
2118}
2119
2120#endif
2121
2122/* #ifdef SH_USE_KERN */
2123#endif
Note: See TracBrowser for help on using the repository browser.