source: trunk/src/sh_kern.c@ 134

Last change on this file since 134 was 132, checked in by rainer, 17 years ago

Make utility functions thread-safe.

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