source: trunk/src/sh_kern.c@ 288

Last change on this file since 288 was 286, checked in by katerina, 14 years ago

Fix for ticket #211 (samhain_kmem compile problems) and ticket #210 (line length, filename quoting in config file).

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