source: branches/samhain_3_1/src/sh_kern.c@ 574

Last change on this file since 574 was 425, checked in by katerina, 12 years ago

Fix for tickets #329, #330, #331, #332

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