source: trunk/src/sh_kern.c@ 327

Last change on this file since 327 was 321, checked in by katerina, 14 years ago

Fix for ticket #240: The samhain_kmem kernel module should be loaded earlier

File size: 50.9 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#ifdef WCONTINUED
749 int wflags = WNOHANG|WUNTRACED|WCONTINUED;
750#else
751 int wflags = WNOHANG|WUNTRACED;
752#endif
753
754 /* Close reading side of pipe, and wait some milliseconds
755 */
756 sl_close_fd (FIL__, __LINE__, mpipe[1]);
757 retry_msleep (0, ShKernDelay); /* milliseconds */
758
759 if (sizeof(int) != read(mpipe[0], &errcode, sizeof(int)))
760 status = -3;
761 else
762 status = 0;
763
764 if (errcode)
765 status = errcode - 100;
766
767 if(status == 0)
768 {
769 size = SH_KERN_SIZ * sizeof(unsigned long);
770
771 if (size != read(mpipe[0], &(kinfo->kmem_call_table), size))
772 status = -4;
773 else
774 status = 0;
775 }
776
777 if(status == 0)
778 {
779 size = sizeof(unsigned int) * 2 * SH_KERN_SIZ;
780
781 if (size != read(mpipe[0], &(kinfo->kmem_code_table), size))
782 status = -5;
783 else
784 status = 0;
785 }
786
787 if(status == 0)
788 {
789 memset(sh_idt_table, '\0', SH_MAXIDT*8);
790 if (sizeof(sh_idt_table) !=
791 read(mpipe[0], &sh_idt_table, sizeof(sh_idt_table)))
792 status = -5;
793 else
794 status = 0;
795 }
796
797 if(status == 0)
798 {
799 size = SH_KERN_SCC;
800
801 if (size != read(mpipe[0], &(kinfo->new_system_call_code), size))
802 status = -6;
803 else
804 status = 0;
805 }
806
807 if(status == 0)
808 {
809 size = sizeof (struct proc_dir_entry);
810
811 if (size != read(mpipe[0], &(kinfo->proc_root_dir), size))
812 status = -7;
813 else
814 status = 0;
815 }
816
817 if(status == 0)
818 {
819 size = sizeof (struct inode_operations);
820
821 if (size != read(mpipe[0], &(kinfo->proc_root_inode), size))
822 status = -8;
823 else
824 status = 0;
825 }
826
827 if (status < 0)
828 res = waitpid(mpid, NULL, wflags);
829 else
830 {
831 res = waitpid(mpid, &status, wflags);
832 if (res == 0 && 0 != WIFEXITED(status))
833 status = WEXITSTATUS(status);
834 }
835 sl_close_fd (FIL__, __LINE__, mpipe[0]);
836 if (res <= 0)
837 {
838 aud_kill(FIL__, __LINE__, mpid, 9);
839 waitpid(mpid, NULL, 0);
840 }
841 return status;
842}
843
844
845static void check_idt_table(int is_init)
846{
847 int i, j;
848
849 unsigned short idt_offset_lo, idt_offset_hi, idt_selector;
850 unsigned char idt_reserved, idt_flag;
851 unsigned short sh_idt_offset_lo, sh_idt_offset_hi, sh_idt_selector;
852 unsigned char sh_idt_reserved, sh_idt_flag;
853 int dpl;
854 unsigned long idt_iaddr;
855 int sh_dpl;
856 unsigned long sh_idt_iaddr;
857 char idt_type, sh_idt_type;
858
859 unsigned long store0;
860 unsigned int store1, store2;
861 int datasize;
862 char msg[2*SH_BUFSIZE];
863
864 if (ShKernIDT == S_TRUE)
865 {
866 if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
867 {
868 datasize = 8;
869 for (j = 0; j < SH_MAXIDT; ++j)
870 {
871 sh_kern_db_syscall (j, _("idt_table"),
872 &sh_idt_table[j*8],
873 &store0, &store1, &store2,
874 &datasize, SH_KERN_DBPUSH);
875 }
876 }
877
878 if ((sh.flag.checkSum != SH_CHECK_INIT) ||
879 (sh.flag.update == S_TRUE && is_init == 1))
880 {
881 /* Check the Interrupt Descriptor Table
882 *
883 * Stored(old) is idt_table[]
884 */
885 for (j = 0; j < SH_MAXIDT; ++j)
886 {
887 i = j * 8;
888
889 sh_idt_offset_lo = *((unsigned short *) &sh_idt_table[i]);
890 sh_idt_selector = *((unsigned short *) &sh_idt_table[i+2]);
891 sh_idt_reserved = (unsigned char) sh_idt_table[i+4];
892 sh_idt_flag = (unsigned char) sh_idt_table[i+5];
893 sh_idt_offset_hi = *((unsigned short *) &sh_idt_table[i+6]);
894 sh_idt_iaddr = (unsigned long)(sh_idt_offset_hi << 16)
895 + sh_idt_offset_lo;
896
897 if (sh_idt_iaddr == 0)
898 {
899 sh_idt_table[i+2] = '\0';
900 sh_idt_table[i+3] = '\0';
901 sh_idt_table[i+5] = '\0';
902
903 idt_offset_lo = *((unsigned short *) &idt_table[i]);
904 idt_offset_hi = *((unsigned short *) &idt_table[i+6]);
905 idt_iaddr = (unsigned long)(idt_offset_hi << 16)
906 + idt_offset_lo;
907 if (idt_iaddr == 0)
908 {
909 idt_table[i+2] = '\0';
910 idt_table[i+3] = '\0';
911 idt_table[i+5] = '\0';
912 }
913
914 }
915
916 if (memcmp(&sh_idt_table[i], &idt_table[i], 8) != 0)
917 {
918
919 idt_offset_lo = *((unsigned short *) &idt_table[i]);
920 idt_selector = *((unsigned short *) &idt_table[i+2]);
921 idt_reserved = (unsigned char) idt_table[i+4];
922 idt_flag = (unsigned char) idt_table[i+5];
923 idt_offset_hi = *((unsigned short *) &idt_table[i+6]);
924 idt_iaddr = (unsigned long)(idt_offset_hi << 16)
925 + idt_offset_lo;
926
927 if (idt_iaddr != 0)
928 {
929 if (idt_flag & 64) { dpl = 3; }
930 else { dpl = 0; }
931 if (idt_flag & 1) {
932 if (dpl == 3) idt_type = 'S';
933 else idt_type = 'T'; }
934 else { idt_type = 'I'; }
935 }
936 else { dpl = -1; idt_type = 'U'; }
937
938 if (sh_idt_iaddr != 0)
939 {
940 if (sh_idt_flag & 64) { sh_dpl = 3; }
941 else { sh_dpl = 0; }
942 if (sh_idt_flag & 1) {
943 if (sh_dpl == 3) sh_idt_type = 'S';
944 else sh_idt_type = 'T'; }
945 else { sh_idt_type = 'I'; }
946 }
947 else { sh_dpl = -1; sh_idt_type = 'U'; }
948
949 sh_kern_pathmsg (msg, SH_BUFSIZE,
950 j, _("idt_table"),
951 &idt_table[i], 8,
952 &sh_idt_table[i], 8);
953
954 sh_error_handle (ShKernSeverity, FIL__, __LINE__,
955 0, MSG_KERN_IDT,
956 j,
957 sh_idt_iaddr, sh_strseg(sh_idt_selector),
958 (int) sh_dpl, sh_idt_type,
959 idt_iaddr, sh_strseg(idt_selector),
960 (int) dpl, idt_type, msg);
961
962 memcpy(&idt_table[i], &sh_idt_table[i], 8);
963 }
964 }
965 }
966 }
967}
968
969
970#define SYS_BUS_PCI _("/sys/bus/pci/devices")
971#include <dirent.h>
972
973static void check_rom (char * pcipath, char * name)
974{
975 file_type theFile;
976 char fileHash[2*(KEY_LEN + 1)];
977 int status;
978 char * tmp;
979 extern unsigned long sh_files_maskof (int class);
980
981 (void) sl_strlcpy (theFile.fullpath, pcipath, PATH_MAX);
982 theFile.check_mask = sh_files_maskof(SH_LEVEL_READONLY);
983 theFile.check_mask &= ~(MODI_MTM|MODI_CTM|MODI_INO);
984 CLEAR_SH_FFLAG_REPORTED(theFile.file_reported);
985 theFile.attr_string = NULL;
986 theFile.link_path = NULL;
987
988 status = sh_unix_getinfo (ShDFLevel[SH_ERR_T_RO],
989 name, &theFile, fileHash, 0);
990
991 if (status != 0)
992 {
993 tmp = sh_util_safe_name(pcipath);
994 sh_error_handle (ShKernSeverity, FIL__, __LINE__,
995 0, MSG_E_SUBGPATH,
996 _("Could not check PCI ROM"),
997 _("check_rom"),
998 tmp);
999 SH_FREE(tmp);
1000 goto out;
1001 }
1002
1003 if ( sh.flag.checkSum == SH_CHECK_INIT )
1004 {
1005 sh_hash_pushdata (&theFile, fileHash);
1006 }
1007 else if (sh.flag.checkSum == SH_CHECK_CHECK )
1008 {
1009 sh_hash_compdata (SH_LEVEL_READONLY, &theFile, fileHash, NULL, -1);
1010 }
1011
1012 out:
1013 if (theFile.attr_string) SH_FREE(theFile.attr_string);
1014 if (theFile.link_path) SH_FREE(theFile.link_path);
1015 return;
1016}
1017
1018static void check_pci_rom (char * pcipath, char * name)
1019{
1020 struct stat buf;
1021 int fd;
1022 int status;
1023
1024 if (0 == stat(pcipath, &buf))
1025 {
1026 /* Need to write "1" to the file to enable the ROM. Afterwards,
1027 * write "0" to disable it.
1028 */
1029 fd = open ( pcipath, O_RDWR );
1030 if (fd)
1031 {
1032 do {
1033 status = write( fd, "1", 1 );
1034 } while (status < 0 && errno == EINTR);
1035 sl_close_fd (FIL__, __LINE__, fd );
1036
1037 if (status > 0)
1038 {
1039 check_rom(pcipath, name);
1040
1041 fd = open ( pcipath, O_RDWR );
1042 if (fd)
1043 {
1044 do {
1045 status = write( fd, "0", 1 );
1046 } while (status < 0 && errno == EINTR);
1047 sl_close_fd (FIL__, __LINE__, fd );
1048 }
1049 }
1050 }
1051 }
1052 return;
1053}
1054
1055static void check_pci()
1056{
1057 char pci_dir[256];
1058 char * pcipath;
1059 DIR * df;
1060 struct dirent * entry;
1061
1062 if (ShKernPCI != S_TRUE)
1063 return;
1064
1065 sl_strlcpy(pci_dir, SYS_BUS_PCI, sizeof(pci_dir));
1066
1067 df = opendir(pci_dir);
1068 if (df)
1069 {
1070 while (1)
1071 {
1072 SH_MUTEX_LOCK(mutex_readdir);
1073 entry = readdir(df);
1074 SH_MUTEX_UNLOCK(mutex_readdir);
1075
1076 if (entry == NULL)
1077 break;
1078
1079 if (0 == strcmp(entry->d_name, ".") &&
1080 0 == strcmp(entry->d_name, ".."))
1081 continue;
1082
1083 pcipath = sh_util_strconcat(pci_dir, "/",
1084 entry->d_name, "/rom", NULL);
1085 check_pci_rom(pcipath, entry->d_name);
1086 SH_FREE(pcipath);
1087 }
1088
1089 closedir(df);
1090 }
1091 return;
1092}
1093
1094/* -- Check the proc_root inode.
1095 *
1096 * This will detect adore-ng.
1097 */
1098static void check_proc_root (struct sh_kernel_info * kinfo)
1099{
1100 struct proc_dir_entry proc_root_dir;
1101 struct inode_operations * proc_root_inode_op = NULL;
1102
1103/* 2.6.21 (((2) << 16) + ((6) << 8) + (21)) */
1104#if SH_KERNEL_NUMBER < KERNEL_VERSION(2,6,21)
1105 struct inode_operations proc_root_inode;
1106
1107 memcpy (&proc_root_inode, &(kinfo->proc_root_inode), sizeof(struct inode_operations));
1108
1109 /* Seems that the info does not relate anymore to proc_root_lookup(?)
1110 */
1111 if ( (unsigned int) *proc_root_inode.lookup != proc_root_lookup)
1112 {
1113 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
1114 _("proc_root_inode_operations.lookup != proc_root_lookup"));
1115 }
1116#endif
1117
1118 memcpy (&proc_root_dir, &(kinfo->proc_root_dir), sizeof(struct proc_dir_entry));
1119
1120 if (((unsigned long) * &proc_root_dir.proc_iops) == proc_root_iops)
1121 {
1122 proc_root_inode_op = (struct inode_operations *) &(proc_root_dir.proc_iops);
1123 }
1124 else if (proc_root_dir.size == proc_root_iops)
1125 {
1126 proc_root_inode_op = (struct inode_operations *) &(proc_root_dir.size);
1127 }
1128 else if ((unsigned long) * &proc_root_dir.proc_fops == proc_root_iops)
1129 {
1130 proc_root_inode_op = (struct inode_operations *) &(proc_root_dir.proc_fops);
1131 }
1132
1133 if (!proc_root_inode_op)
1134 {
1135 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC,
1136 _("proc_root.proc_iops != proc_root_inode_operations"));
1137 }
1138
1139 return;
1140}
1141
1142/* -- Check the system_call syscall gate.
1143 *
1144 * Stored(old) is system_call_code[]
1145 */
1146static void check_syscall_gate(int is_init, struct sh_kernel_info * kinfo)
1147{
1148 int i, j;
1149 unsigned long store0;
1150 unsigned int store1, store2;
1151 int datasize;
1152 int max_system_call = (SYS_CALL_LOC < 128) ? 128 : SYS_CALL_LOC;
1153 char msg[2*SH_BUFSIZE];
1154
1155 if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
1156 {
1157 store0 = 0; store1 = 0; store2 = 0;
1158 datasize = SH_KERN_SCC;
1159 sh_kern_db_syscall (0, _("system_call"),
1160 &(kinfo->new_system_call_code), &store0, &store1, &store2,
1161 &datasize, SH_KERN_DBPUSH);
1162 }
1163
1164 if ((sh.flag.checkSum != SH_CHECK_INIT) ||
1165 (sh.flag.update == S_TRUE && is_init == 1))
1166 {
1167 for (i = 0; i < (max_system_call + 4); ++i)
1168 {
1169 if (system_call_code[i] != kinfo->new_system_call_code[i])
1170 {
1171
1172 sh_kern_pathmsg (msg, sizeof(msg),
1173 0, _("system_call"),
1174 system_call_code, SH_KERN_SCC,
1175 kinfo->new_system_call_code, SH_KERN_SCC);
1176
1177 sh_error_handle (ShKernSeverity, FIL__, __LINE__,
1178 0, MSG_KERN_GATE,
1179 kinfo->new_system_call_code[i], 0,
1180 system_call_code[i], 0,
1181 0, _("system_call (interrupt handler)"),
1182 msg);
1183
1184 for (j = 0; j < (max_system_call + 4); ++j)
1185 system_call_code[j] = kinfo->new_system_call_code[j];
1186 break;
1187 }
1188 }
1189 }
1190 return;
1191}
1192
1193static void check_system_calls (int is_init, struct sh_kernel_info * kinfo)
1194{
1195 int i;
1196
1197#ifdef SH_USE_LKM
1198 static int check_getdents = 0;
1199 /* #ifdef __NR_getdents64 */
1200 static int check_getdents64 = 0;
1201 /* #endif */
1202 static int copy_if_next = -1;
1203 static int copy_if_next_64 = -1;
1204#endif
1205
1206 unsigned long store0;
1207 unsigned int store1, store2;
1208 int mod_syscall_addr = 0;
1209 int mod_syscall_code = 0;
1210 UINT64 size_old = 0, size_new = 0;
1211 UINT64 mtime_old = 0, mtime_new = 0;
1212 UINT64 ctime_old = 0, ctime_new = 0;
1213 char tmp[128];
1214 char msg[2*SH_BUFSIZE];
1215 char timstr_o[32];
1216 char timstr_n[32];
1217
1218 if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
1219 {
1220 for (i = 0; i < SH_MAXCALLS; ++i)
1221 {
1222 store0 = kinfo->kmem_call_table[i];
1223 store1 = kinfo->kmem_code_table[i][0]; store2 = kinfo->kmem_code_table[i][1];
1224 sh_kern_db_syscall (i, _("syscall"),
1225 NULL, &store0, &store1, &store2,
1226 0, SH_KERN_DBPUSH);
1227 }
1228 }
1229
1230 if ((sh.flag.checkSum != SH_CHECK_INIT) ||
1231 (sh.flag.update == S_TRUE && is_init == 1))
1232 {
1233 for (i = 0; i < SH_MAXCALLS; ++i)
1234 {
1235 if (sh_syscalls[i].name == NULL /* || sh_syscalls[i].addr == 0UL */)
1236 break;
1237
1238#ifdef SH_USE_LKM
1239 if (sh_syscalls[i].addr != kinfo->kmem_call_table[i])
1240 {
1241 if (check_getdents == 0 &&
1242 0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents")))
1243 {
1244 check_getdents = 1;
1245 sh_error_handle (SH_ERR_WARN, FIL__, __LINE__,
1246 0, MSG_E_SUBGEN,
1247 _("Modified kernel syscall (expected)."),
1248 _(sh_syscalls[i].name) );
1249 copy_if_next = i;
1250 sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1251 continue;
1252 }
1253 /* #ifdef __NR_getdents64 */
1254 else if (check_getdents64 == 0 &&
1255 0 == strcmp(_(sh_syscalls[i].name),
1256 _("sys_getdents64")))
1257 {
1258 check_getdents64 = 1;
1259 sh_error_handle (SH_ERR_WARN, FIL__, __LINE__,
1260 0, MSG_E_SUBGEN,
1261 _("Modified kernel syscall (expected)."),
1262 _(sh_syscalls[i].name) );
1263 copy_if_next_64 = i;
1264 sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1265 continue;
1266 }
1267 /* #endif */
1268 else
1269 {
1270 size_old = sh_syscalls[i].addr;
1271 size_new = kinfo->kmem_call_table[i];
1272 mod_syscall_addr = 1;
1273 }
1274 sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1275 }
1276#else
1277 if (sh_syscalls[i].addr != kinfo->kmem_call_table[i])
1278 {
1279 size_old = sh_syscalls[i].addr;
1280 size_new = kinfo->kmem_call_table[i];
1281 mod_syscall_addr = 1;
1282 sh_syscalls[i].addr = kinfo->kmem_call_table[i];
1283 }
1284#endif
1285
1286
1287 /* -- Check the code at syscall address
1288 *
1289 * Stored(old) is sh_syscalls[]
1290 */
1291 if ( (mod_syscall_addr == 0) &&
1292 ((sh_syscalls[i].code[0] != kinfo->kmem_code_table[i][0]) ||
1293 (sh_syscalls[i].code[1] != kinfo->kmem_code_table[i][1]))
1294 )
1295 {
1296 mtime_old = sh_syscalls[i].code[0];
1297 mtime_new = kinfo->kmem_code_table[i][0];
1298 ctime_old = sh_syscalls[i].code[1];
1299 ctime_new = kinfo->kmem_code_table[i][1];
1300 mod_syscall_code = 1;
1301
1302#ifdef SH_USE_LKM
1303 if (i == copy_if_next)
1304 {
1305 mod_syscall_code = 0;
1306 copy_if_next = -1;
1307 }
1308 if (i == copy_if_next_64)
1309 {
1310 mod_syscall_code = 0;
1311 copy_if_next_64 = -1;
1312 }
1313#endif
1314
1315 sh_syscalls[i].code[0] = kinfo->kmem_code_table[i][0];
1316 sh_syscalls[i].code[1] = kinfo->kmem_code_table[i][1];
1317 }
1318
1319 /* Build the error message, if something has been
1320 * detected.
1321 */
1322 if ((mod_syscall_addr != 0) || (mod_syscall_code != 0))
1323 {
1324#ifdef SH_USE_XML
1325 sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ",
1326 _("syscall"), i);
1327#else
1328 sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ",
1329 _("syscall"), i);
1330#endif
1331 sl_strlcpy(msg, tmp, SH_BUFSIZE);
1332
1333 if (mod_syscall_addr != 0)
1334 {
1335 sl_snprintf(tmp, 128, sh_hash_size_format(),
1336 size_old, size_new);
1337 sl_strlcat(msg, tmp, SH_BUFSIZE);
1338 }
1339 if (mod_syscall_code != 0)
1340 {
1341 (void) sh_unix_gmttime (ctime_old, timstr_o, sizeof(timstr_o));
1342 (void) sh_unix_gmttime (ctime_new, timstr_n, sizeof(timstr_n));
1343#ifdef SH_USE_XML
1344 sl_snprintf(tmp, 128,
1345 _("ctime_old=\"%s\" ctime_new=\"%s\" "),
1346 timstr_o, timstr_n);
1347#else
1348 sl_snprintf(tmp, 128,
1349 _("ctime_old=<%s>, ctime_new=<%s>, "),
1350 timstr_o, timstr_n);
1351#endif
1352 sl_strlcat(msg, tmp, SH_BUFSIZE);
1353 (void) sh_unix_gmttime (mtime_old, timstr_o, sizeof(timstr_o));
1354 (void) sh_unix_gmttime (mtime_new, timstr_n, sizeof(timstr_n));
1355#ifdef SH_USE_XML
1356 sl_snprintf(tmp, 128,
1357 _("mtime_old=\"%s\" mtime_new=\"%s\" "),
1358 timstr_o, timstr_n);
1359#else
1360 sl_snprintf(tmp, 128,
1361 _("mtime_old=<%s>, mtime_new=<%s> "),
1362 timstr_o, timstr_n);
1363#endif
1364 sl_strlcat(msg, tmp, SH_BUFSIZE);
1365 }
1366 sh_error_handle (ShKernSeverity, FIL__, __LINE__,
1367 0, MSG_KERN_SYSCALL,
1368 i, _(sh_syscalls[i].name), msg);
1369 mod_syscall_addr = 0;
1370 mod_syscall_code = 0;
1371 }
1372 }
1373 }
1374 return;
1375}
1376
1377int sh_kern_check_internal ()
1378{
1379 int kd;
1380 int is_init;
1381 pid_t mpid;
1382 int mpipe[2];
1383 int status = 0;
1384
1385 struct sh_kernel_info kinfo;
1386
1387
1388 SL_ENTER(_("sh_kern_check_internal"));
1389
1390 /* -- Check whether initialisation is required; if yes, initialize.
1391 */
1392
1393 if (0 != check_init(&is_init))
1394 {
1395 SL_RETURN( (-1), _("sh_kern_check_internal"));
1396 }
1397
1398
1399 /* -- Open /dev/kmem and fork subprocess to read from it.
1400 */
1401
1402 if (kaddr == (unsigned int) -1) /* kaddr = address of the sys_call_table */
1403 {
1404 sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN,
1405 _("no address for sys_call_table - switching off"),
1406 _("kern_check_internal") );
1407 ShKernActive = S_FALSE;
1408 SL_RETURN( (-1), _("sh_kern_check_internal"));
1409 }
1410
1411 kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/dev/kmem"), O_RDONLY, 0);
1412
1413 if (kd < 0)
1414 {
1415 kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/proc/kmem"), O_RDONLY, 0);
1416 }
1417
1418 if (kd < 0)
1419 {
1420 status = errno;
1421 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1422 _("error opening /dev/kmem"),
1423 _("kern_check_internal") );
1424 SL_RETURN( (-1), _("sh_kern_check_internal"));
1425 }
1426
1427 status = aud_pipe(FIL__, __LINE__, mpipe);
1428
1429 if (status == 0)
1430 {
1431 mpid = aud_fork(FIL__, __LINE__);
1432
1433 switch (mpid)
1434 {
1435 case -1:
1436 status = -1;
1437 break;
1438 case 0:
1439
1440 /* -- Child process reads /dev/kmem and writes to pipe
1441 */
1442 run_child(kd, mpipe);
1443 break;
1444
1445 /* -- Parent process reads from child via pipe
1446 */
1447 default:
1448 sl_close_fd(FIL__, __LINE__, kd);
1449 status = read_from_child(mpid, mpipe, &kinfo);
1450 break;
1451 }
1452 }
1453
1454 if ( status < 0)
1455 {
1456 char errmsg[SH_ERRBUF_SIZE];
1457 sl_snprintf(errmsg, SH_ERRBUF_SIZE,
1458 _("error reading from /dev/kmem: %d"), status);
1459 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1460 errmsg,
1461 _("kern_check_internal") );
1462 SL_RETURN( (-1), _("sh_kern_check_internal"));
1463 }
1464
1465 /* -- Check the proc_root inode.
1466 *
1467 * This will detect adore-ng.
1468 */
1469 check_proc_root( &kinfo );
1470
1471
1472 /* -- Check the system_call syscall gate.
1473 *
1474 * Stored(old) is system_call_code[]
1475 */
1476 check_syscall_gate( is_init, &kinfo );
1477
1478 /* -- Check the individual syscalls
1479 *
1480 * Stored(old) is sh_syscalls[] array.
1481 */
1482 check_system_calls ( is_init, &kinfo );
1483
1484 /* -- Check the Interrupt Descriptor Table
1485 */
1486 check_idt_table(is_init);
1487
1488 /* -- Check PCI ROM
1489 */
1490 check_pci();
1491
1492 SL_RETURN( (0), _("sh_kern_check_internal"));
1493}
1494/* ifdef HOST_IS_LINUX */
1495#else
1496
1497/********************************************************
1498 *
1499 * --- BSD ---
1500 *
1501 ********************************************************/
1502
1503#include <err.h>
1504#include <kvm.h>
1505#include <nlist.h>
1506
1507/* not OpenBSD */
1508#if defined(HOST_IS_FREEBSD)
1509#include <sys/sysent.h>
1510#endif
1511
1512#include <sys/syscall.h>
1513#ifndef SYS_MAXSYSCALL
1514#define SYS_MAXSYSCALL 512
1515#endif
1516
1517#ifdef __OpenBSD__
1518struct proc;
1519struct sysent {
1520 short sy_narg;
1521 short sy_argsize;
1522 int (*sy_call)(struct proc *, void *, register_t *);
1523};
1524#endif
1525
1526int sh_kern_data_init ()
1527{
1528 unsigned long store0 = 0;
1529 unsigned int store1 = 0, store2 = 0;
1530 int datasize, i;
1531 char * databuf = NULL;
1532
1533 /* syscall address and code
1534 */
1535 for (i = 0; i < SH_MAXCALLS; ++i)
1536 {
1537 databuf = sh_kern_db_syscall (i, _("syscall"),
1538 NULL, &store0, &store1, &store2,
1539 &datasize, SH_KERN_DBPOP);
1540 sh_syscalls[i].addr = store0;
1541 if (databuf != NULL) { SH_FREE(databuf); }
1542 if (store0 == 0) {
1543 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1544 _("syscall address not found in database"),
1545 _("sh_kern_data_init"));
1546 return -1;
1547 }
1548
1549 sh_syscalls[i].code[0] = (unsigned int) store1;
1550 sh_syscalls[i].code[1] = (unsigned int) store2;
1551 if ((store1 == 0) || (store2 == 0)) {
1552 sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1553 _("syscall code not found in database"),
1554 _("sh_kern_data_init"));
1555 return -1;
1556 }
1557
1558 }
1559
1560 return 0;
1561}
1562
1563int sh_kern_check_internal ()
1564{
1565 struct sysent sy;
1566 kvm_t * kd;
1567 int i;
1568 int status = -1;
1569 char errbuf[_POSIX2_LINE_MAX+1];
1570 struct nlist * sys_list;
1571 struct nlist list[2];
1572
1573 unsigned long offset = 0L;
1574 unsigned int syscall_code[2]; /* 8 bytes */
1575 unsigned long syscall_addr;
1576
1577 unsigned long store0 = 0;
1578 unsigned int store1 = 0, store2 = 0;
1579
1580 UINT64 size_old = 0, size_new = 0;
1581 UINT64 mtime_old = 0, mtime_new = 0;
1582 UINT64 ctime_old = 0, ctime_new = 0;
1583 char tmp[128];
1584 char msg[2*SH_BUFSIZE];
1585 char timstr_o[32];
1586 char timstr_n[32];
1587
1588 static int is_init = 0;
1589
1590 SL_ENTER(_("sh_kern_check_internal"));
1591
1592 if (is_init == 0)
1593 {
1594 if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE)
1595 {
1596 if (0 == sh_kern_data_init()) {
1597 is_init = 1;
1598 } else {
1599 sh_error_handle (ShKernSeverity, FIL__, __LINE__, status,
1600 MSG_E_SUBGEN,
1601 _("could not initialize - switching off"),
1602 _("kern_check_internal") );
1603 ShKernActive = S_FALSE;
1604 SL_RETURN( (-1), _("sh_kern_check_internal"));
1605 }
1606 }
1607 else if ((sh.flag.checkSum == SH_CHECK_INIT ||
1608 sh.flag.checkSum == SH_CHECK_CHECK) &&
1609 (sh.flag.update == S_TRUE))
1610 {
1611 if (0 == sh_kern_data_init()) {
1612 is_init = 1;
1613 } else {
1614 sh_error_handle (ShKernSeverity, FIL__, __LINE__, status,
1615 MSG_E_SUBGEN,
1616 _("no or incomplete data in baseline database"),
1617 _("kern_check_internal") );
1618 }
1619 }
1620 }
1621
1622 /* defined, but not used
1623 */
1624 ShKernDelay = 0;
1625
1626 list[0].n_name = "_sysent";
1627 list[1].n_name = NULL;
1628
1629 kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
1630 if (!kd)
1631 {
1632 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1633 errbuf,
1634 _("kvm_openfiles") );
1635 SL_RETURN( (-1), _("sh_kern_check_internal"));
1636 }
1637
1638 i = kvm_nlist(kd, list);
1639 if (i == -1)
1640 {
1641 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1642 kvm_geterr(kd),
1643 _("kvm_nlist (_sysent)") );
1644 kvm_close(kd);
1645 SL_RETURN( (-1), _("sh_kern_check_internal"));
1646 }
1647
1648 sys_list = SH_ALLOC((SYS_MAXSYSCALL+1) * sizeof(struct nlist));
1649
1650 for (i = 0; i < SH_MAXCALLS; ++i)
1651 sys_list[i].n_name = sh_syscalls[i].name;
1652 sys_list[SH_MAXCALLS].n_name = NULL;
1653
1654 i = kvm_nlist(kd, sys_list);
1655 if (i == -1)
1656 {
1657 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1658 kvm_geterr(kd),
1659 _("kvm_nlist (syscalls)") );
1660 kvm_close(kd);
1661 SH_FREE(sys_list);
1662 SL_RETURN( (-1), _("sh_kern_check_internal"));
1663 }
1664 else if (i > 0)
1665 {
1666 sl_snprintf(tmp, 128,
1667 _("%d invalid syscalls"), i);
1668 /*
1669 for (i = 0; i < SH_MAXCALLS; ++i) {
1670 if (sys_list[i].n_type == 0 && sys_list[i].n_value == 0)
1671 fprintf(stderr, "invalid: [%3d] %s\n", i, sh_syscalls[i].name);
1672 }
1673 */
1674 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1675 tmp,
1676 _("kvm_nlist (syscalls)") );
1677 }
1678
1679 /* Check the individual syscalls
1680 *
1681 * Stored(old) is sh_syscalls[] array.
1682 */
1683 if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE)
1684 {
1685 for (i = 0; i < SH_MAXCALLS; ++i)
1686 {
1687 if (sh_syscalls[i].name == NULL)
1688 {
1689 sl_snprintf(tmp, 128,
1690 _("too few entries in sh_syscalls[]: have %d, expect %d"),
1691 i, SH_MAXCALLS);
1692
1693 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1694 tmp,
1695 _("sh_kern_check_internal") );
1696 break;
1697 }
1698
1699 /* read address of syscall from sysent table
1700 */
1701 offset = list[0].n_value + (i*sizeof(struct sysent));
1702 if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0)
1703 {
1704 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1705 kvm_geterr(kd),
1706 _("kvm_read (syscall table)") );
1707 kvm_close(kd);
1708 SH_FREE(sys_list);
1709 SL_RETURN( (-1), _("sh_kern_check_internal"));
1710 }
1711 syscall_addr = (unsigned long) sy.sy_call;
1712 store0 = syscall_addr;
1713
1714 /* read the syscall code
1715 */
1716 if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]),
1717 2 * sizeof(unsigned int)) < 0)
1718 {
1719 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1720 kvm_geterr(kd),
1721 _("kvm_read (syscall code)") );
1722 kvm_close(kd);
1723 SH_FREE(sys_list);
1724 SL_RETURN( (-1), _("sh_kern_check_internal"));
1725 }
1726 store1 = syscall_code[0]; store2 = syscall_code[1];
1727
1728 sh_kern_db_syscall (i, _("syscall"),
1729 NULL, &store0, &store1, &store2,
1730 0, SH_KERN_DBPUSH);
1731 }
1732 }
1733
1734 if ((sh.flag.checkSum != SH_CHECK_INIT) ||
1735 (sh.flag.update == S_TRUE && is_init == 1))
1736 {
1737 for (i = 0; i < SH_MAXCALLS; ++i)
1738 {
1739 if (sh_syscalls[i].name == NULL)
1740 {
1741 sl_snprintf(tmp, 128,
1742 _("too few entries in sh_syscalls[]: have %d, expect %d"),
1743 i, SH_MAXCALLS);
1744
1745 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1746 tmp,
1747 _("sh_kern_check_internal") );
1748 break;
1749 }
1750
1751 /* read address of syscall from sysent table
1752 */
1753 offset = list[0].n_value + (i*sizeof(struct sysent));
1754 if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0)
1755 {
1756 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1757 kvm_geterr(kd),
1758 _("kvm_read (syscall table)") );
1759 kvm_close(kd);
1760 SH_FREE(sys_list);
1761 SL_RETURN( (-1), _("sh_kern_check_internal"));
1762 }
1763 syscall_addr = (unsigned long) sy.sy_call;
1764
1765 if (sh_syscalls[i].addr != syscall_addr)
1766 {
1767#ifdef SH_USE_XML
1768 sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ",
1769 _("syscall"), i);
1770#else
1771 sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ",
1772 _("syscall"), i);
1773#endif
1774 sl_strlcpy(msg, tmp, SH_BUFSIZE);
1775
1776 size_old = sh_syscalls[i].addr;
1777 size_new = syscall_addr;
1778 sl_snprintf(tmp, 128, sh_hash_size_format(),
1779 size_old, size_new);
1780 sl_strlcat(msg, tmp, SH_BUFSIZE);
1781
1782 sh_error_handle (ShKernSeverity, FIL__, __LINE__,
1783 status, MSG_KERN_SYSCALL,
1784 i, _(sh_syscalls[i].name),
1785 msg);
1786 sh_syscalls[i].addr = syscall_addr;
1787 }
1788 else
1789 {
1790 /* read the syscall code
1791 */
1792 if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]),
1793 2 * sizeof(unsigned int)) < 0)
1794 {
1795 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1796 kvm_geterr(kd),
1797 _("kvm_read (syscall code)") );
1798 kvm_close(kd);
1799 SH_FREE(sys_list);
1800 SL_RETURN( (-1), _("sh_kern_check_internal"));
1801 }
1802
1803 if (sh_syscalls[i].code[0] != syscall_code[0] ||
1804 sh_syscalls[i].code[1] != syscall_code[1])
1805 {
1806 mtime_old = sh_syscalls[i].code[0];
1807 mtime_new = syscall_code[0];
1808 ctime_old = sh_syscalls[i].code[1];
1809 ctime_new = syscall_code[1];
1810
1811#ifdef SH_USE_XML
1812 sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ",
1813 _("syscall"), i);
1814#else
1815 sl_snprintf(tmp, 128, "path=<K_%s_%04d>, ",
1816 _("syscall"), i);
1817#endif
1818 sl_strlcpy(msg, tmp, SH_BUFSIZE);
1819
1820 (void) sh_unix_gmttime (ctime_old, timstr_o, sizeof(timstr_o));
1821 (void) sh_unix_gmttime (ctime_new, timstr_n, sizeof(timstr_n));
1822#ifdef SH_USE_XML
1823 sl_snprintf(tmp, 128,
1824 _("ctime_old=\"%s\" ctime_new=\"%s\" "),
1825 timstr_o, timstr_n);
1826#else
1827 sl_snprintf(tmp, 128,
1828 _("ctime_old=<%s>, ctime_new=<%s>, "),
1829 timstr_o, timstr_n);
1830#endif
1831 sl_strlcat(msg, tmp, SH_BUFSIZE);
1832 (void) sh_unix_gmttime (mtime_old, timstr_o, sizeof(timstr_o));
1833 (void) sh_unix_gmttime (mtime_new, timstr_n, sizeof(timstr_n));
1834#ifdef SH_USE_XML
1835 sl_snprintf(tmp, 128,
1836 _("mtime_old=\"%s\" mtime_new=\"%s\" "),
1837 timstr_o, timstr_n);
1838#else
1839 sl_snprintf(tmp, 128,
1840 _("mtime_old=<%s>, mtime_new=<%s> "),
1841 timstr_o, timstr_n);
1842#endif
1843 sl_strlcat(msg, tmp, SH_BUFSIZE);
1844
1845 sh_error_handle (ShKernSeverity, FIL__, __LINE__,
1846 status, MSG_KERN_SYSCALL,
1847 i, _(sh_syscalls[i].name),
1848 msg);
1849 sh_syscalls[i].code[0] = syscall_code[0];
1850 sh_syscalls[i].code[1] = syscall_code[1];
1851 }
1852 }
1853 }
1854 }
1855 SH_FREE(sys_list);
1856 if(kvm_close(kd) < 0)
1857 {
1858 sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN,
1859 kvm_geterr(kd),
1860 _("kvm_close") );
1861 exit(EXIT_FAILURE);
1862 }
1863
1864 SL_RETURN( (0), _("sh_kern_check_internal"));
1865}
1866
1867#endif
1868
1869/*************
1870 *
1871 * module init
1872 *
1873 *************/
1874#if defined(HOST_IS_LINUX)
1875#include <sys/utsname.h>
1876#endif
1877
1878static int AddressReconf = 0;
1879
1880int sh_kern_init (struct mod_type * arg)
1881{
1882#if defined(HOST_IS_LINUX)
1883 struct utsname buf;
1884 char * str;
1885#endif
1886 (void) arg;
1887
1888 SL_ENTER(_("sh_kern_init"));
1889 if (ShKernActive == S_FALSE)
1890 SL_RETURN( (-1), _("sh_kern_init"));
1891
1892#if defined(HOST_IS_LINUX)
1893 uname(&buf);
1894
1895 if ((AddressReconf < 5) && (0 != strcmp(SH_KERNEL_VERSION, buf.release)))
1896 {
1897 str = SH_ALLOC(256);
1898 sl_snprintf(str, 256,
1899 "Compiled for kernel %s, but current kernel is %s, and kernel addresses have not been re-configured",
1900 SH_KERNEL_VERSION, buf.release);
1901 sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1902 str,
1903 _("kern_check") );
1904 SH_FREE(str);
1905 ShKernActive = S_FALSE;
1906 SL_RETURN( (-1), _("sh_kern_init"));
1907 }
1908#endif
1909
1910 lastcheck = time (NULL);
1911 if (sh.flag.checkSum != SH_CHECK_INIT)
1912 {
1913 sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1914 _("Checking kernel syscalls"),
1915 _("kern_check") );
1916 }
1917 sh_kern_check_internal ();
1918 SL_RETURN( (0), _("sh_kern_init"));
1919}
1920
1921/*************
1922 *
1923 * module cleanup
1924 *
1925 *************/
1926int sh_kern_end ()
1927{
1928 return (0);
1929}
1930
1931
1932/*************
1933 *
1934 * module timer
1935 *
1936 *************/
1937int sh_kern_timer (time_t tcurrent)
1938{
1939 if (ShKernActive == S_FALSE)
1940 return 0;
1941
1942 if ((int) (tcurrent - lastcheck) >= ShKernInterval)
1943 {
1944 lastcheck = tcurrent;
1945 return (-1);
1946 }
1947 return 0;
1948}
1949
1950/*************
1951 *
1952 * module check
1953 *
1954 *************/
1955int sh_kern_check ()
1956{
1957 sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN,
1958 _("Checking kernel syscalls"),
1959 _("kern_check") );
1960 return (sh_kern_check_internal ());
1961}
1962
1963/*************
1964 *
1965 * module setup
1966 *
1967 *************/
1968
1969int sh_kern_set_severity (const char * c)
1970{
1971 char tmp[32];
1972 tmp[0] = '='; tmp[1] = '\0';
1973 sl_strlcat (tmp, c, 32);
1974 sh_error_set_level (tmp, &ShKernSeverity);
1975 return 0;
1976}
1977
1978int sh_kern_set_timer (const char * c)
1979{
1980 long val;
1981
1982 SL_ENTER(_("sh_kern_set_timer"));
1983
1984 val = strtol (c, (char **)NULL, 10);
1985 if (val <= 0)
1986 sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1987 _("kern timer"), c);
1988
1989 val = (val <= 0 ? 60 : val);
1990
1991 ShKernInterval = (time_t) val;
1992 SL_RETURN( 0, _("sh_kern_set_timer"));
1993}
1994
1995int sh_kern_set_activate (const char * c)
1996{
1997 int i;
1998 SL_ENTER(_("sh_kern_set_activate"));
1999 i = sh_util_flagval(c, &ShKernActive);
2000 SL_RETURN(i, _("sh_kern_set_activate"));
2001}
2002
2003int sh_kern_set_idt (const char * c)
2004{
2005 int i;
2006 SL_ENTER(_("sh_kern_set_idt"));
2007 i = sh_util_flagval(c, &ShKernIDT);
2008 SL_RETURN(i, _("sh_kern_set_idt"));
2009}
2010
2011int sh_kern_set_pci (const char * c)
2012{
2013 int i;
2014 SL_ENTER(_("sh_kern_set_pci"));
2015 i = sh_util_flagval(c, &ShKernPCI);
2016 SL_RETURN(i, _("sh_kern_set_pci"));
2017}
2018
2019int sh_kern_set_sc_addr (const char * c)
2020{
2021 char * endptr;
2022 unsigned long value;
2023
2024 SL_ENTER(_("sh_kern_set_sc_addr"));
2025 errno = 0;
2026 value = strtoul(c, &endptr, 16);
2027 if ((ULONG_MAX == value) && (errno == ERANGE))
2028 {
2029 SL_RETURN((-1), _("sh_kern_set_sc_addr"));
2030 }
2031 if ((*c == '\0') || (*endptr != '\0'))
2032 {
2033 SL_RETURN((-1), _("sh_kern_set_sc_addr"));
2034 }
2035 system_call_addr = value;
2036 ++AddressReconf;
2037 SL_RETURN((0), _("sh_kern_set_sc_addr"));
2038}
2039
2040int sh_kern_set_sct_addr (const char * c)
2041{
2042 char * endptr;
2043 unsigned long value;
2044
2045 SL_ENTER(_("sh_kern_set_sct_addr"));
2046 errno = 0;
2047 value = strtoul(c, &endptr, 16);
2048 if ((ULONG_MAX == value) && (errno == ERANGE))
2049 {
2050 SL_RETURN((-1), _("sh_kern_set_sct_addr"));
2051 }
2052 if ((*c == '\0') || (*endptr != '\0'))
2053 {
2054 SL_RETURN((-1), _("sh_kern_set_sct_addr"));
2055 }
2056 kaddr = (unsigned int) value;
2057 ++AddressReconf;
2058 SL_RETURN((0), _("sh_kern_set_sct_addr"));
2059}
2060
2061int sh_kern_set_proc_root (const char * c)
2062{
2063 char * endptr;
2064 unsigned long value;
2065
2066 SL_ENTER(_("sh_kern_set_proc_root"));
2067 errno = 0;
2068 value = strtoul(c, &endptr, 16);
2069 if ((ULONG_MAX == value) && (errno == ERANGE))
2070 {
2071 SL_RETURN((-1), _("sh_kern_set_proc_root"));
2072 }
2073 if ((*c == '\0') || (*endptr != '\0'))
2074 {
2075 SL_RETURN((-1), _("sh_kern_set_proc_root"));
2076 }
2077
2078 proc_root = value;
2079 ++AddressReconf;
2080 SL_RETURN((0), _("sh_kern_set_proc_root"));
2081}
2082
2083int sh_kern_set_proc_root_iops (const char * c)
2084{
2085 char * endptr;
2086 unsigned long value;
2087
2088 SL_ENTER(_("sh_kern_set_proc_root_iops"));
2089 errno = 0;
2090 value = strtoul(c, &endptr, 16);
2091 if ((ULONG_MAX == value) && (errno == ERANGE))
2092 {
2093 SL_RETURN((-1), _("sh_kern_set_proc_root_iops"));
2094 }
2095 if ((*c == '\0') || (*endptr != '\0'))
2096 {
2097 SL_RETURN((-1), _("sh_kern_set_proc_root_iops"));
2098 }
2099
2100 proc_root_iops = value;
2101 ++AddressReconf;
2102 SL_RETURN((0), _("sh_kern_set_proc_root_iops"));
2103}
2104
2105int sh_kern_set_proc_root_lookup (const char * c)
2106{
2107 char * endptr;
2108 unsigned long value;
2109
2110 SL_ENTER(_("sh_kern_set_proc_root_lookup"));
2111 errno = 0;
2112 value = strtoul(c, &endptr, 16);
2113 if ((ULONG_MAX == value) && (errno == ERANGE))
2114 {
2115 SL_RETURN((-1), _("sh_kern_set_proc_root_lookup"));
2116 }
2117 if ((*c == '\0') || (*endptr != '\0'))
2118 {
2119 SL_RETURN((-1), _("sh_kern_set_proc_root_lookup"));
2120 }
2121 proc_root_lookup = value;
2122 ++AddressReconf;
2123 SL_RETURN((0), _("sh_kern_set_proc_root_lookup"));
2124}
2125
2126#endif
2127
2128/* #ifdef SH_USE_KERN */
2129#endif
Note: See TracBrowser for help on using the repository browser.