source: trunk/src/sh_kern.c@ 319

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

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

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