source: trunk/src/sh_kern.c@ 284

Last change on this file since 284 was 279, checked in by katerina, 15 years ago

Fix for tickets #200 to #206 (kernel check, login checks, bugfixes).

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