source: trunk/src/sh_kern.c@ 204

Last change on this file since 204 was 192, checked in by katerina, 16 years ago

Fixes for cygwin, and improved error diagnostics (tickets #126, #127, #128).

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