/* SAMHAIN file system integrity testing */ /* Copyright (C) 2001 Rainer Wichmann */ /* */ /* This program is free software; you can redistribute it */ /* and/or modify */ /* it under the terms of the GNU General Public License as */ /* published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software */ /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "config_xor.h" #define SH_SYSCALL_CODE #ifdef HOST_IS_I86LINUX #define SH_IDT_TABLE #define SH_PROC_CHECK #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SH_USE_KERN #undef FIL__ #define FIL__ _("sh_kern.c") #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE) #if TIME_WITH_SYS_TIME #include #include #else #if HAVE_SYS_TIME_H #include #else #include #endif #endif #include "samhain.h" #include "sh_utils.h" #include "sh_error.h" #include "sh_modules.h" #include "sh_kern.h" #include "sh_ks_xor.h" #include "sh_unix.h" #include "sh_hash.h" sh_rconf sh_kern_table[] = { { N_("severitykernel"), sh_kern_set_severity }, { N_("kernelcheckactive"), sh_kern_set_activate }, { N_("kernelcheckinterval"), sh_kern_set_timer }, { N_("kernelcheckidt"), sh_kern_set_idt }, { N_("kernelsystemcall"), sh_kern_set_sc_addr }, { N_("kernelsyscalltable"), sh_kern_set_sct_addr }, { N_("kernelprocrootlookup"), sh_kern_set_proc_root_lookup }, { N_("kernelprocrootiops"), sh_kern_set_proc_root_iops }, { N_("kernelprocroot"), sh_kern_set_proc_root }, { NULL, NULL }, }; static time_t lastcheck; static int ShKernActive = S_TRUE; static int ShKernInterval = 300; static int ShKernSeverity = SH_ERR_SEVERE; static int ShKernDelay = 100; /* milliseconds */ static int ShKernIDT = S_TRUE; /* The address of system_call */ #ifdef SH_SYS_CALL_ADDR static unsigned long system_call_addr = SH_SYS_CALL_ADDR; #else static unsigned long system_call_addr = 0; #endif /* The address of the sys_call_table */ #ifdef SH_SYS_CALL_TABLE static unsigned int kaddr = SH_SYS_CALL_TABLE; #else static unsigned int kaddr = 0; #endif #ifdef PROC_ROOT_LOC static unsigned long proc_root = PROC_ROOT_LOC; #else static unsigned long proc_root = 0; #endif #ifdef PROC_ROOT_IOPS_LOC static unsigned long proc_root_iops = PROC_ROOT_IOPS_LOC; #else static unsigned long proc_root_iops = 0; #endif #ifdef PROC_ROOT_LOOKUP_LOC static unsigned long proc_root_lookup = PROC_ROOT_LOOKUP_LOC; #else static unsigned long proc_root_lookup = 0; #endif int sh_kern_null() { return 0; } #ifdef SH_IDT_TABLE #include #define SH_MAXIDT 256 unsigned char sh_idt_table[SH_MAXIDT * 8]; char * sh_strseg(unsigned short segment) { switch (segment) { case __KERNEL_CS: return _("KERNEL_CS"); case __KERNEL_DS: return _("KERNEL_DS"); case __USER_CS: return _("USER_CS"); case __USER_DS: return _("USER_DS"); default: return _("unknown"); } } /* ifdef SH_IDT_TABLE */ #endif static char * sh_kern_charhex( unsigned char i ) { static char i2h[2]; int j, k; j = i / 16; k = i - (j*16); if (j < 10) i2h[0] = '0'+j; else i2h[0] = 'A'+(j-10); if (k < 10) i2h[1] = '0'+k; else i2h[1] = 'A'+(k-10); return i2h; } static void sh_kern_push2db (char * name, unsigned long addr, unsigned long code1, unsigned long code2, unsigned char * code, int size) { file_type tmpFile; int i = 0; char * p; tmpFile.attr_string = NULL; sl_strlcpy(tmpFile.fullpath, name, PATH_MAX); tmpFile.size = addr; tmpFile.mtime = code1; tmpFile.ctime = code2; tmpFile.atime = 0; tmpFile.mode = 0; tmpFile.owner = 0; tmpFile.group = 0; sl_strlcpy(tmpFile.c_owner, _("root"), 5); sl_strlcpy(tmpFile.c_group, _("root"), 5); if ((code != NULL) && (size < (PATH_MAX/2)-1)) { tmpFile.c_mode[0] = 'l'; tmpFile.c_mode[1] = 'r'; tmpFile.c_mode[2] = 'w'; tmpFile.c_mode[3] = 'x'; tmpFile.c_mode[4] = 'r'; tmpFile.c_mode[5] = 'w'; tmpFile.c_mode[6] = 'x'; tmpFile.c_mode[7] = 'r'; tmpFile.c_mode[8] = 'w'; tmpFile.c_mode[9] = 'x'; tmpFile.c_mode[10] = '\0'; for (i = 0; i < size; ++i) { p = sh_kern_charhex (code[i]); tmpFile.linkpath[2*i] = p[0]; tmpFile.linkpath[2*i+1] = p[1]; tmpFile.linkpath[2*i+2] = '\0'; } } else { tmpFile.c_mode[0] = '-'; tmpFile.c_mode[1] = '-'; tmpFile.c_mode[2] = '-'; tmpFile.c_mode[3] = '-'; tmpFile.c_mode[4] = '-'; tmpFile.c_mode[5] = '-'; tmpFile.c_mode[6] = '-'; tmpFile.c_mode[7] = '-'; tmpFile.c_mode[8] = '-'; tmpFile.c_mode[9] = '-'; tmpFile.c_mode[10] = '\0'; tmpFile.linkpath[0] = '-'; tmpFile.linkpath[1] = '\0'; } if (sh.flag.checkSum == SH_CHECK_CHECK && sh.flag.update == S_TRUE) sh_hash_pushdata_memory (&tmpFile, _("000000000000000000000000000000000000000000000000")); else sh_hash_pushdata (&tmpFile, _("000000000000000000000000000000000000000000000000")); return; } extern int sh_util_hextobinary (char * binary, const char * hex, int bytes); static char * sh_kern_db2pop (char * name, unsigned long * addr, unsigned long * code1, unsigned long * code2, int * size) { file_type tmpFile; char * p; int i; if (0 == sh_hash_get_it (name, &tmpFile)) { *addr = tmpFile.size; *code1 = tmpFile.mtime; *code2 = tmpFile.ctime; if (tmpFile.linkpath[0] != '-') { p = SH_ALLOC(PATH_MAX); i = sh_util_hextobinary (p, tmpFile.linkpath, strlen(tmpFile.linkpath)); if (i == 0) { *size = (strlen(tmpFile.linkpath)/2); p[*size] = '\0'; return p; } else { SH_FREE(p); *size = 0; return NULL; } } else { *size = 0; return NULL; } } else { *size = 0; *addr = 0; return NULL; } } char * sh_kern_db_syscall (int num, char * prefix, void * in_name, unsigned long * addr, unsigned int * code1, unsigned int * code2, int * size, int direction) { char path[128]; char * p = NULL; unsigned long x1, x2; char * name = (char *) in_name; sl_snprintf(path, 128, "K_%s_%04d", prefix, num); if (direction == 0) { x1 = *code1; x2 = *code2; sh_kern_push2db (path, *addr, x1, x2, name, (name == NULL) ? 0 : (*size)); } else { p = sh_kern_db2pop (path, addr, &x1, &x2, size); *code1 = (unsigned int) x1; *code2 = (unsigned int) x2; } return p; } #ifdef HOST_IS_LINUX int sh_kern_data_init () { unsigned long store0 = 0; unsigned int store1 = 0, store2 = 0; int datasize, i, j; char * databuf; #ifdef SH_SYSCALL_CODE /* system_call code */ databuf = sh_kern_db_syscall (0, _("system_call"), NULL, &store0, &store1, &store2, &datasize, 1); if (datasize == sizeof(system_call_code)) { memcpy (system_call_code, databuf, sizeof(system_call_code)); SH_FREE(databuf); } else { sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, _("system_call_code not found in database"), _("sh_kern_data_init")); return -1; } #endif /* syscall address and code */ for (i = 0; i < SH_MAXCALLS; ++i) { databuf = sh_kern_db_syscall (i, _("syscall"), NULL, &store0, &store1, &store2, &datasize, 1); sh_syscalls[i].addr = store0; if (store0 == 0) { sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, i, MSG_E_SUBGEN, _("syscall address not found in database"), _("sh_kern_data_init")); return -1; } #ifdef SH_SYSCALL_CODE sh_syscalls[i].code[0] = (unsigned int) store1; sh_syscalls[i].code[1] = (unsigned int) store2; if ((store1 == 0) || (store2 == 0)) { sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, i, MSG_E_SUBGEN, _("syscall code not found in database"), _("sh_kern_data_init")); /* fprintf(stderr, "Syscall #%d\n", i); */ /* return -1; */ } #endif if (databuf != NULL) { SH_FREE(databuf); } } #ifdef SH_IDT_TABLE if (ShKernIDT == S_TRUE) { for (j = 0; j < SH_MAXIDT; ++j) { databuf = sh_kern_db_syscall (j, _("idt_table"), NULL, &store0, &store1, &store2, &datasize, 1); if (datasize == 8) { memcpy(&idt_table[j*8], databuf, 8); SH_FREE(databuf); } else { sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, j, MSG_E_SUBGEN, _("idt table not found in database"), _("sh_kern_data_init")); return -1; } } } #endif return 0; } #ifdef SH_PROC_CHECK struct inode_operations { int (*create) (int *,int *,int); int * (*lookup) (int *,int *); int (*link) (int *,int *,int *); int (*unlink) (int *,int *); int (*symlink) (int *,int *,const char *); int (*mkdir) (int *,int *,int); int (*rmdir) (int *,int *); int (*mknod) (int *,int *,int,int); int (*rename) (int *, int *, int *, int *); /* flawfinder: ignore */ int (*readlink) (int *, char *,int); int (*follow_link) (int *, int *); void (*truncate) (int *); int (*permission) (int *, int); int (*revalidate) (int *); /* int (*setattr) (int *, int *); int (*getattr) (int *, int *); int (*setxattr) (int *, const char *, void *, size_t, int); ssize_t (*getxattr) (int *, const char *, void *, size_t); ssize_t (*listxattr) (int *, char *, size_t); int (*removexattr) (int *, const char *); */ }; /* this one is just for dummy purposes */ struct file_operations { int (*create) (int *,int *,int); }; struct proc_dir_entry { unsigned short low_ino; unsigned short namelen; const char * name; mode_t mode; nlink_t nlink; uid_t uid; gid_t gid; #if defined TWO_SIX_SEVENTEEN_PLUS /* size is loff_t in 2.6.17+ kernels */ unsigned long dummy; #endif unsigned long size; struct inode_operations * proc_iops; struct file_operations * proc_fops; /* get_info_t *get_info; struct module *owner; struct proc_dir_entry *next, *parent, *subdir; void *data; read_proc_t *read_proc; write_proc_t *write_proc; atomic_t count; int deleted; */ }; #endif static int sh_kern_kmem_read (int fd, unsigned long addr, unsigned char * buf, int len) { if (lseek(fd, addr, SEEK_SET) == (off_t) (-1)) { return -1; } if (read(fd, buf, len) < 0) { return -1; } return 0; } static int sh_kern_read_data (int fd, unsigned long addr, unsigned char * buf, size_t len) { size_t moff, roff; size_t sz; char * kmap; /* first, try read() */ if (0 == sh_kern_kmem_read (fd, addr, buf, len)) return 0; /* next, try mmap() */ sz = getpagesize(); /* unistd.h */ moff = ((size_t)(addr/sz)) * sz; /* lower page boundary */ roff = addr - moff; /* off relative to lower address of mmapped area */ kmap = mmap(0, len+sz, PROT_READ, MAP_PRIVATE, fd, moff);/* sys/mman.h */ if (kmap == MAP_FAILED) { return -1; } memcpy (buf, &kmap[roff], len); return munmap(kmap, len+sz); } int sh_kern_check_internal () { static int is_init = 0; int kd; int res; pid_t mpid; int mpipe[2]; int i, j, status = 0; /* unsigned int kaddr; */ unsigned long kmem_call_table[512]; #ifdef SH_PROC_CHECK struct inode_operations proc_root_inode; struct proc_dir_entry proc_root_dir; #endif #ifdef SH_SYSCALL_CODE unsigned int kmem_code_table[512][2]; #endif #ifdef SH_IDT_TABLE unsigned char buf[6]; unsigned short idt_size; unsigned long idt_addr; /* int k, curr_keep = 0; */ unsigned short idt_offset_lo, idt_offset_hi, idt_selector; unsigned char idt_reserved, idt_flag; unsigned short sh_idt_offset_lo, sh_idt_offset_hi, sh_idt_selector; unsigned char sh_idt_reserved, sh_idt_flag; int dpl; unsigned long idt_iaddr; int sh_dpl; unsigned long sh_idt_iaddr; char idt_type, sh_idt_type; #endif unsigned char new_system_call_code[256]; #ifdef SH_USE_LKM static int check_getdents = 0; /* #ifdef __NR_getdents64 */ static int check_getdents64 = 0; /* #endif */ static int copy_if_next = -1; static int copy_if_next_64 = -1; #endif unsigned long store0; unsigned int store1, store2; int datasize; int mod_syscall_addr = 0; int mod_syscall_code = 0; UINT64 size_old = 0, size_new = 0; UINT64 mtime_old = 0, mtime_new = 0; UINT64 ctime_old = 0, ctime_new = 0; char tmp[128]; char msg[2*SH_BUFSIZE]; char timstr_o[32]; char timstr_n[32]; char * p; int k; char * linkpath_old; char * linkpath_new; int max_system_call = (SYS_CALL_LOC < 128) ? 128 : SYS_CALL_LOC; SL_ENTER(_("sh_kern_check_internal")); if (is_init == 0) { if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE) { if (0 == sh_kern_data_init()) { is_init = 1; } else { sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN, _("could not initialize - switching off"), _("kern_check_internal") ); ShKernActive = S_FALSE; SL_RETURN( (-1), _("sh_kern_check_internal")); } } else if ((sh.flag.checkSum == SH_CHECK_INIT || sh.flag.checkSum == SH_CHECK_CHECK) && (sh.flag.update == S_TRUE)) { if (0 == sh_kern_data_init()) { is_init = 1; } else { sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_SUBGEN, _("no or incomplete data in baseline database"), _("kern_check_internal") ); } } } /* * kaddr is the address of the sys_call_table */ if (kaddr == (unsigned int) -1) { sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN, _("no address for sys_call_table - switching off"), _("kern_check_internal") ); ShKernActive = S_FALSE; SL_RETURN( (-1), _("sh_kern_check_internal")); } kd = aud_open(FIL__, __LINE__, SL_YESPRIV, _("/dev/kmem"), O_RDONLY, 0); if (kd < 0) { status = errno; sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, _("error opening /dev/kmem"), _("kern_check_internal") ); SL_RETURN( (-1), _("sh_kern_check_internal")); } status = aud_pipe(FIL__, __LINE__, mpipe); if (status == 0) { mpid = aud_fork(FIL__, __LINE__); switch (mpid) { case -1: status = -1; break; case 0: /* child */ status = close(mpipe[0]); setpgid(0, 0); /* Seek to the system call table (at kaddr) and read it into * the kmem_call_table array */ if(status == 0) { retry_msleep (0, ShKernDelay); /* milliseconds */ if (sh_kern_read_data (kd, kaddr, (unsigned char *) &kmem_call_table, sizeof(kmem_call_table))) { status = -2; } } #ifdef SH_SYSCALL_CODE /* * Seek to the system call address (at sh_syscalls[j].addr) and * read first 8 bytes into kmem_code_table[j][] (2 * unsigned int) */ if(status == 0) { memset(kmem_code_table, 0, sizeof(kmem_code_table)); for (j = 0; j < SH_MAXCALLS; ++j) { if (sh_syscalls[j].addr == 0UL) { sh_syscalls[j].addr = kmem_call_table[j]; } if (sh_syscalls[j].name == NULL || sh_syscalls[j].addr == 0UL) break; if ((sh.flag.checkSum == SH_CHECK_INIT || sh.flag.checkSum == SH_CHECK_CHECK) && (sh.flag.update == S_TRUE)) { sh_kern_read_data (kd, kmem_call_table[j], (unsigned char *) &(kmem_code_table[j][0]), 2 * sizeof(unsigned int)); } else { sh_kern_read_data (kd, sh_syscalls[j].addr, (unsigned char *) &(kmem_code_table[j][0]), 2 * sizeof(unsigned int)); } } } #endif #ifdef SH_IDT_TABLE if(status == 0) { /* * Get the address and size of Interrupt Descriptor Table, * and read the content into sh_idt_table[] */ __asm__ volatile ("sidt %0": "=m" (buf)); idt_size = *((unsigned short *) &buf[0]); idt_addr = *((unsigned long *) &buf[2]); idt_size = (idt_size + 1)/8; if (idt_size > SH_MAXIDT) idt_size = SH_MAXIDT; memset(sh_idt_table, '\0', SH_MAXIDT*8); sh_kern_read_data (kd, idt_addr, (unsigned char *) sh_idt_table, idt_size*8); } #endif /* * Seek to the system_call address (at system_call_addr) and * read first 256 bytes into new_system_call_code[] * * system_call_addr is defined in the include file. */ if(status == 0) { sh_kern_read_data (kd, system_call_addr, (unsigned char *) new_system_call_code, 256); } /* * Seek to proc_root and read the structure. * Seek to proc_root_inode_operations and get the structure. */ #ifdef SH_PROC_CHECK if(status == 0) { sh_kern_read_data (kd, proc_root, (unsigned char *) &proc_root_dir, sizeof(proc_root_dir)); sh_kern_read_data (kd, proc_root_iops, (unsigned char *) &proc_root_inode, sizeof(proc_root_inode)); } #endif if(status == 0) { status = write(mpipe[1], &kmem_call_table, sizeof(kmem_call_table)); #ifdef SH_SYSCALL_CODE if(status > 0) { status = write(mpipe[1], &kmem_code_table, sizeof(kmem_code_table)); } #endif #ifdef SH_IDT_TABLE if(status > 0) { status = write(mpipe[1], &sh_idt_table, sizeof(sh_idt_table)); } #endif if(status > 0) { status = write(mpipe[1], new_system_call_code, 256); } #ifdef SH_PROC_CHECK if(status > 0) { status = write(mpipe[1], &proc_root_dir, sizeof(proc_root_dir)); } if(status > 0) { status = write(mpipe[1], &proc_root_inode, sizeof(proc_root_inode)); } #endif } _exit( (status >= 0) ? 0 : status); break; default: close (mpipe[1]); close (kd); retry_msleep (0, ShKernDelay); /* milliseconds */ if (sizeof(kmem_call_table) != read(mpipe[0], &kmem_call_table, sizeof(kmem_call_table))) status = -4; else status = 0; #ifdef SH_SYSCALL_CODE if(status == 0) { if (sizeof(kmem_code_table) != read(mpipe[0], &kmem_code_table, sizeof(kmem_code_table))) status = -5; else status = 0; } #endif #ifdef SH_IDT_TABLE if(status == 0) { memset(sh_idt_table, '\0', SH_MAXIDT*8); if (sizeof(sh_idt_table) != read(mpipe[0], &sh_idt_table, sizeof(sh_idt_table))) status = -5; else status = 0; } #endif if(status == 0) { if (256 != read(mpipe[0], new_system_call_code, 256)) status = -6; else status = 0; } #ifdef SH_PROC_CHECK if(status == 0) { if (sizeof(proc_root_dir) != read(mpipe[0], &proc_root_dir, sizeof(proc_root_dir))) status = -7; else status = 0; } if(status == 0) { if (sizeof(proc_root_inode) != read(mpipe[0], &proc_root_inode, sizeof(proc_root_inode))) status = -8; else status = 0; } #endif if (status < 0) res = waitpid(mpid, NULL, WNOHANG|WUNTRACED); else { res = waitpid(mpid, &status, WNOHANG|WUNTRACED); if (res == 0 && 0 != WIFEXITED(status)) status = WEXITSTATUS(status); } close (mpipe[0]); if (res <= 0) { aud_kill(FIL__, __LINE__, mpid, 9); waitpid(mpid, NULL, 0); } break; } } if ( status < 0) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, _("error reading from /dev/kmem"), _("kern_check_internal") ); SL_RETURN( (-1), _("sh_kern_check_internal")); } /* Check the proc_root inode. * * This will detect adore-ng. */ if ( (unsigned int) *proc_root_inode.lookup != proc_root_lookup) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC, _("proc_root_inode_operations.lookup != proc_root_lookup")); } else if ( ( ((unsigned int) * &proc_root_dir.proc_iops) != proc_root_iops) && (proc_root_dir.size != proc_root_iops)) { sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_KERN_PROC, _("proc_root.proc_iops != proc_root_inode_operations")); } /* Check the system_call syscall gate. * * Stored(old) is system_call_code[] */ if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE) { store0 = 0; store1 = 0; store2 = 0; datasize = sizeof(system_call_code); sh_kern_db_syscall (0, _("system_call"), new_system_call_code, &store0, &store1, &store2, &datasize, 0); } if ((sh.flag.checkSum != SH_CHECK_INIT) || (sh.flag.update == S_TRUE && is_init == 1)) { for (i = 0; i < (max_system_call + 4); ++i) { if (system_call_code[i] != new_system_call_code[i]) { #ifdef SH_USE_XML sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", _("system_call"), 0); #else sl_snprintf(tmp, 128, "path=, ", _("system_call"), 0); #endif sl_strlcpy(msg, tmp, SH_BUFSIZE); linkpath_old = SH_ALLOC(520); linkpath_new = SH_ALLOC(520); for (k = 0; k < 256; ++k) { p = sh_kern_charhex (system_call_code[k]); linkpath_old[2*k] = p[0]; linkpath_old[2*k+1] = p[1]; linkpath_old[2*k+2] = '\0'; } for (k = 0; k < 256; ++k) { p = sh_kern_charhex (new_system_call_code[k]); linkpath_new[2*k] = p[0]; linkpath_new[2*k+1] = p[1]; linkpath_new[2*k+2] = '\0'; } #ifdef SH_USE_XML sl_strlcat(msg, _("link_old=\""), 2*SH_BUFSIZE); sl_strlcat(msg, linkpath_old, 2*SH_BUFSIZE); sl_strlcat(msg, _("\" link_new=\""), 2*SH_BUFSIZE); sl_strlcat(msg, linkpath_new, 2*SH_BUFSIZE); sl_strlcat(msg, _("\""), 2*SH_BUFSIZE); #else sl_strlcat(msg, _("link_old=<"), 2*SH_BUFSIZE); sl_strlcat(msg, linkpath_old, 2*SH_BUFSIZE); sl_strlcat(msg, _(">, link_new=<"), 2*SH_BUFSIZE); sl_strlcat(msg, linkpath_new, 2*SH_BUFSIZE); sl_strlcat(msg, _(">"), 2*SH_BUFSIZE); #endif sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_GATE, new_system_call_code[i], 0, system_call_code[i], 0, 0, _("system_call (interrupt handler)"), msg); SH_FREE(linkpath_old); SH_FREE(linkpath_new); for (j = 0; j < (max_system_call + 4); ++j) system_call_code[j] = new_system_call_code[j]; break; } } } /* Check the individual syscalls * * Stored(old) is sh_syscalls[] array. */ if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE) { for (i = 0; i < SH_MAXCALLS; ++i) { store0 = kmem_call_table[i]; #ifdef SH_SYSCALL_CODE store1 = kmem_code_table[i][0]; store2 = kmem_code_table[i][1]; #else store1 = 0; store2 = 0; #endif sh_kern_db_syscall (i, _("syscall"), NULL, &store0, &store1, &store2, 0, 0); } } if ((sh.flag.checkSum != SH_CHECK_INIT) || (sh.flag.update == S_TRUE && is_init == 1)) { for (i = 0; i < SH_MAXCALLS; ++i) { if (sh_syscalls[i].name == NULL /* || sh_syscalls[i].addr == 0UL */) break; #ifdef SH_USE_LKM if (sh_syscalls[i].addr != kmem_call_table[i]) { if (check_getdents == 0 && 0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents"))) { check_getdents = 1; sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_SUBGEN, _("Modified kernel syscall (expected)."), _(sh_syscalls[i].name) ); copy_if_next = i; sh_syscalls[i].addr = kmem_call_table[i]; continue; } /* #ifdef __NR_getdents64 */ else if (check_getdents64 == 0 && 0 == strcmp(_(sh_syscalls[i].name), _("sys_getdents64"))) { check_getdents64 = 1; sh_error_handle (SH_ERR_WARN, FIL__, __LINE__, status, MSG_E_SUBGEN, _("Modified kernel syscall (expected)."), _(sh_syscalls[i].name) ); copy_if_next_64 = i; sh_syscalls[i].addr = kmem_call_table[i]; continue; } /* #endif */ else { size_old = sh_syscalls[i].addr; size_new = kmem_call_table[i]; mod_syscall_addr = 1; /* sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_POLICY, kmem_call_table[i], sh_syscalls[i].addr, i, _(sh_syscalls[i].name) ); */ } sh_syscalls[i].addr = kmem_call_table[i]; } #else if (sh_syscalls[i].addr != kmem_call_table[i]) { size_old = sh_syscalls[i].addr; size_new = kmem_call_table[i]; mod_syscall_addr = 1; /* sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_POLICY, kmem_call_table[i], sh_syscalls[i].addr, i, _(sh_syscalls[i].name) ); */ sh_syscalls[i].addr = kmem_call_table[i]; } #endif /* Check the code at syscall address * * Stored(old) is sh_syscalls[] */ #ifdef SH_SYSCALL_CODE if ( (mod_syscall_addr == 0) && ((sh_syscalls[i].code[0] != kmem_code_table[i][0]) || (sh_syscalls[i].code[1] != kmem_code_table[i][1])) ) { mtime_old = sh_syscalls[i].code[0]; mtime_new = kmem_code_table[i][0]; ctime_old = sh_syscalls[i].code[1]; ctime_new = kmem_code_table[i][1]; mod_syscall_code = 1; #ifdef SH_USE_LKM if (i == copy_if_next) { mod_syscall_code = 0; copy_if_next = -1; } if (i == copy_if_next_64) { mod_syscall_code = 0; copy_if_next_64 = -1; } #endif /* sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_POL_CO, kmem_code_table[i][0], kmem_code_table[i][1], sh_syscalls[i].code[0], sh_syscalls[i].code[1], i, _(sh_syscalls[i].name) ); */ sh_syscalls[i].code[0] = kmem_code_table[i][0]; sh_syscalls[i].code[1] = kmem_code_table[i][1]; } #endif /* * Build the error message, if something has been * detected. */ if ((mod_syscall_addr != 0) || (mod_syscall_code != 0)) { #ifdef SH_USE_XML sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", _("syscall"), i); #else sl_snprintf(tmp, 128, "path=, ", _("syscall"), i); #endif sl_strlcpy(msg, tmp, SH_BUFSIZE); if (mod_syscall_addr != 0) { sl_snprintf(tmp, 128, sh_hash_size_format(), size_old, size_new); sl_strlcat(msg, tmp, SH_BUFSIZE); } if (mod_syscall_code != 0) { sl_strlcpy (timstr_o, sh_unix_gmttime (ctime_old), 32); sl_strlcpy (timstr_n, sh_unix_gmttime (ctime_new), 32); #ifdef SH_USE_XML sl_snprintf(tmp, 128, _("ctime_old=\"%s\" ctime_new=\"%s\" "), timstr_o, timstr_n); #else sl_snprintf(tmp, 128, _("ctime_old=<%s>, ctime_new=<%s>, "), timstr_o, timstr_n); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr_o, sh_unix_gmttime (mtime_old), 32); sl_strlcpy (timstr_n, sh_unix_gmttime (mtime_new), 32); #ifdef SH_USE_XML sl_snprintf(tmp, 128, _("mtime_old=\"%s\" mtime_new=\"%s\" "), timstr_o, timstr_n); #else sl_snprintf(tmp, 128, _("mtime_old=<%s>, mtime_new=<%s> "), timstr_o, timstr_n); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); } sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_SYSCALL, i, _(sh_syscalls[i].name), msg); mod_syscall_addr = 0; mod_syscall_code = 0; } } } #ifdef SH_IDT_TABLE if (ShKernIDT == S_TRUE) { if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE) { datasize = 8; for (j = 0; j < SH_MAXIDT; ++j) { sh_kern_db_syscall (j, _("idt_table"), &sh_idt_table[j*8], &store0, &store1, &store2, &datasize, 0); } } if ((sh.flag.checkSum != SH_CHECK_INIT) || (sh.flag.update == S_TRUE && is_init == 1)) { /* Check the Interrupt Descriptor Table * * Stored(old) is idt_table[] */ for (j = 0; j < SH_MAXIDT; ++j) { i = j * 8; sh_idt_offset_lo = *((unsigned short *) &sh_idt_table[i]); sh_idt_selector = *((unsigned short *) &sh_idt_table[i+2]); sh_idt_reserved = (unsigned char) sh_idt_table[i+4]; sh_idt_flag = (unsigned char) sh_idt_table[i+5]; sh_idt_offset_hi = *((unsigned short *) &sh_idt_table[i+6]); sh_idt_iaddr = (unsigned long)(sh_idt_offset_hi << 16) + sh_idt_offset_lo; if (sh_idt_iaddr == 0) { sh_idt_table[i+2] = '\0'; sh_idt_table[i+3] = '\0'; sh_idt_table[i+5] = '\0'; idt_offset_lo = *((unsigned short *) &idt_table[i]); idt_offset_hi = *((unsigned short *) &idt_table[i+6]); idt_iaddr = (unsigned long)(idt_offset_hi << 16) + idt_offset_lo; if (idt_iaddr == 0) { idt_table[i+2] = '\0'; idt_table[i+3] = '\0'; idt_table[i+5] = '\0'; } } if (memcmp(&sh_idt_table[i], &idt_table[i], 8) != 0) { idt_offset_lo = *((unsigned short *) &idt_table[i]); idt_selector = *((unsigned short *) &idt_table[i+2]); idt_reserved = (unsigned char) idt_table[i+4]; idt_flag = (unsigned char) idt_table[i+5]; idt_offset_hi = *((unsigned short *) &idt_table[i+6]); idt_iaddr = (unsigned long)(idt_offset_hi << 16) + idt_offset_lo; if (idt_iaddr != 0) { if (idt_flag & 64) { dpl = 3; } else { dpl = 0; } if (idt_flag & 1) { if (dpl == 3) idt_type = 'S'; else idt_type = 'T'; } else { idt_type = 'I'; } } else { dpl = -1; idt_type = 'U'; } if (sh_idt_iaddr != 0) { if (sh_idt_flag & 64) { sh_dpl = 3; } else { sh_dpl = 0; } if (sh_idt_flag & 1) { if (sh_dpl == 3) sh_idt_type = 'S'; else sh_idt_type = 'T'; } else { sh_idt_type = 'I'; } } else { sh_dpl = -1; sh_idt_type = 'U'; } #ifdef SH_USE_XML sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", _("idt_table"), j); #else sl_snprintf(tmp, 128, "path= ", _("idt_table"), j); #endif sl_strlcpy(msg, tmp, SH_BUFSIZE); linkpath_old = SH_ALLOC(32); linkpath_new = SH_ALLOC(32); for (k = 0; k < 8; ++k) { p = sh_kern_charhex (idt_table[i+k]); linkpath_old[2*k] = p[0]; linkpath_old[2*k+1] = p[1]; linkpath_old[2*k+2] = '\0'; } for (k = 0; k < 8; ++k) { p = sh_kern_charhex (sh_idt_table[i+k]); linkpath_new[2*k] = p[0]; linkpath_new[2*k+1] = p[1]; linkpath_new[2*k+2] = '\0'; } #ifdef SH_USE_XML sl_snprintf(tmp, 128, _("link_old=\"%s\" link_new=\"%s\" "), linkpath_old, linkpath_new); #else sl_snprintf(tmp, 128, _("link_old=<%s> link_new=<%s> "), linkpath_old, linkpath_new); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_IDT, j, sh_idt_iaddr, sh_strseg(sh_idt_selector), (int) sh_dpl, sh_idt_type, idt_iaddr, sh_strseg(idt_selector), (int) dpl, idt_type, msg); SH_FREE(linkpath_old); SH_FREE(linkpath_new); memcpy(&idt_table[i], &sh_idt_table[i], 8); } } } } #endif SL_RETURN( (0), _("sh_kern_check_internal")); } /* ifdef HOST_IS_LINUX */ #else #include #include #include /* not OpenBSD */ #if defined(HOST_IS_FREEBSD) #include #endif #include #ifndef SYS_MAXSYSCALL #define SYS_MAXSYSCALL 512 #endif #ifdef __OpenBSD__ struct proc; struct sysent { short sy_narg; short sy_argsize; int (*sy_call)(struct proc *, void *, register_t *); }; #endif int sh_kern_data_init () { unsigned long store0 = 0; unsigned int store1 = 0, store2 = 0; int datasize, i; char * databuf = NULL; /* syscall address and code */ for (i = 0; i < SH_MAXCALLS; ++i) { databuf = sh_kern_db_syscall (i, _("syscall"), NULL, &store0, &store1, &store2, &datasize, 1); sh_syscalls[i].addr = store0; if (databuf != NULL) { SH_FREE(databuf); } if (store0 == 0) { sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, _("syscall address not found in database"), _("sh_kern_data_init")); return -1; } sh_syscalls[i].code[0] = (unsigned int) store1; sh_syscalls[i].code[1] = (unsigned int) store2; if ((store1 == 0) || (store2 == 0)) { sh_error_handle(SH_ERR_ERR, FIL__, __LINE__, 0, MSG_E_SUBGEN, _("syscall code not found in database"), _("sh_kern_data_init")); return -1; } } return 0; } int sh_kern_check_internal () { struct sysent sy; kvm_t * kd; int i; int status = -1; char errbuf[_POSIX2_LINE_MAX+1]; struct nlist * sys_list; struct nlist list[2]; unsigned long offset = 0L; unsigned int syscall_code[2]; /* 8 bytes */ unsigned long syscall_addr; unsigned long store0 = 0; unsigned int store1 = 0, store2 = 0; UINT64 size_old = 0, size_new = 0; UINT64 mtime_old = 0, mtime_new = 0; UINT64 ctime_old = 0, ctime_new = 0; char tmp[128]; char msg[2*SH_BUFSIZE]; char timstr_o[32]; char timstr_n[32]; static int is_init = 0; SL_ENTER(_("sh_kern_check_internal")); if (is_init == 0) { if (sh.flag.checkSum != SH_CHECK_INIT && sh.flag.update != S_TRUE) { if (0 == sh_kern_data_init()) { is_init = 1; } else { sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN, _("could not initialize - switching off"), _("kern_check_internal") ); ShKernActive = S_FALSE; SL_RETURN( (-1), _("sh_kern_check_internal")); } } else if ((sh.flag.checkSum == SH_CHECK_INIT || sh.flag.checkSum == SH_CHECK_CHECK) && (sh.flag.update == S_TRUE)) { if (0 == sh_kern_data_init()) { is_init = 1; } else { sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_E_SUBGEN, _("no or incomplete data in baseline database"), _("kern_check_internal") ); } } } /* defined, but not used */ ShKernDelay = 0; list[0].n_name = "_sysent"; list[1].n_name = NULL; kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); if (!kd) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, errbuf, _("kvm_openfiles") ); SL_RETURN( (-1), _("sh_kern_check_internal")); } i = kvm_nlist(kd, list); if (i == -1) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_nlist (_sysent)") ); kvm_close(kd); SL_RETURN( (-1), _("sh_kern_check_internal")); } sys_list = SH_ALLOC((SYS_MAXSYSCALL+1) * sizeof(struct nlist)); for (i = 0; i < SH_MAXCALLS; ++i) sys_list[i].n_name = sh_syscalls[i].name; sys_list[SH_MAXCALLS].n_name = NULL; i = kvm_nlist(kd, sys_list); if (i == -1) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_nlist (syscalls)") ); kvm_close(kd); SH_FREE(sys_list); SL_RETURN( (-1), _("sh_kern_check_internal")); } else if (i > 0) { sl_snprintf(tmp, 128, _("%d invalid syscalls"), i); /* for (i = 0; i < SH_MAXCALLS; ++i) { if (sys_list[i].n_type == 0 && sys_list[i].n_value == 0) fprintf(stderr, "invalid: [%3d] %s\n", i, sh_syscalls[i].name); } */ sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN, tmp, _("kvm_nlist (syscalls)") ); } /* Check the individual syscalls * * Stored(old) is sh_syscalls[] array. */ if (sh.flag.checkSum == SH_CHECK_INIT || sh.flag.update == S_TRUE) { for (i = 0; i < SH_MAXCALLS; ++i) { if (sh_syscalls[i].name == NULL) { sl_snprintf(tmp, 128, _("too few entries in sh_syscalls[]: have %d, expect %d"), i, SH_MAXCALLS); sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, tmp, _("sh_kern_check_internal") ); break; } /* read address of syscall from sysent table */ offset = list[0].n_value + (i*sizeof(struct sysent)); if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_read (syscall table)") ); kvm_close(kd); SH_FREE(sys_list); SL_RETURN( (-1), _("sh_kern_check_internal")); } syscall_addr = (unsigned long) sy.sy_call; store0 = syscall_addr; /* read the syscall code */ if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]), 2 * sizeof(unsigned int)) < 0) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_read (syscall code)") ); kvm_close(kd); SH_FREE(sys_list); SL_RETURN( (-1), _("sh_kern_check_internal")); } store1 = syscall_code[0]; store2 = syscall_code[1]; sh_kern_db_syscall (i, _("syscall"), NULL, &store0, &store1, &store2, 0, 0); } } if ((sh.flag.checkSum != SH_CHECK_INIT) || (sh.flag.update == S_TRUE && is_init == 1)) { for (i = 0; i < SH_MAXCALLS; ++i) { if (sh_syscalls[i].name == NULL) { sl_snprintf(tmp, 128, _("too few entries in sh_syscalls[]: have %d, expect %d"), i, SH_MAXCALLS); sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, tmp, _("sh_kern_check_internal") ); break; } /* read address of syscall from sysent table */ offset = list[0].n_value + (i*sizeof(struct sysent)); if (kvm_read(kd, offset, &sy, sizeof(struct sysent)) < 0) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_read (syscall table)") ); kvm_close(kd); SH_FREE(sys_list); SL_RETURN( (-1), _("sh_kern_check_internal")); } syscall_addr = (unsigned long) sy.sy_call; if (sh_syscalls[i].addr != syscall_addr) { #ifdef SH_USE_XML sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", _("syscall"), i); #else sl_snprintf(tmp, 128, "path=, ", _("syscall"), i); #endif sl_strlcpy(msg, tmp, SH_BUFSIZE); size_old = sh_syscalls[i].addr; size_new = syscall_addr; sl_snprintf(tmp, 128, sh_hash_size_format(), size_old, size_new); sl_strlcat(msg, tmp, SH_BUFSIZE); sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_SYSCALL, /* syscall_addr, sh_syscalls[i].addr, */ i, _(sh_syscalls[i].name), msg); sh_syscalls[i].addr = syscall_addr; } else { /* read the syscall code */ if(kvm_read(kd, (unsigned int) sy.sy_call, &(syscall_code[0]), 2 * sizeof(unsigned int)) < 0) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_read (syscall code)") ); kvm_close(kd); SH_FREE(sys_list); SL_RETURN( (-1), _("sh_kern_check_internal")); } if (sh_syscalls[i].code[0] != syscall_code[0] || sh_syscalls[i].code[1] != syscall_code[1]) { mtime_old = sh_syscalls[i].code[0]; mtime_new = syscall_code[0]; ctime_old = sh_syscalls[i].code[1]; ctime_new = syscall_code[1]; #ifdef SH_USE_XML sl_snprintf(tmp, 128, "path=\"K_%s_%04d\" ", _("syscall"), i); #else sl_snprintf(tmp, 128, "path=, ", _("syscall"), i); #endif sl_strlcpy(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr_o, sh_unix_gmttime (ctime_old), 32); sl_strlcpy (timstr_n, sh_unix_gmttime (ctime_new), 32); #ifdef SH_USE_XML sl_snprintf(tmp, 128, _("ctime_old=\"%s\" ctime_new=\"%s\" "), timstr_o, timstr_n); #else sl_snprintf(tmp, 128, _("ctime_old=<%s>, ctime_new=<%s>, "), timstr_o, timstr_n); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); sl_strlcpy (timstr_o, sh_unix_gmttime (mtime_old), 32); sl_strlcpy (timstr_n, sh_unix_gmttime (mtime_new), 32); #ifdef SH_USE_XML sl_snprintf(tmp, 128, _("mtime_old=\"%s\" mtime_new=\"%s\" "), timstr_o, timstr_n); #else sl_snprintf(tmp, 128, _("mtime_old=<%s>, mtime_new=<%s> "), timstr_o, timstr_n); #endif sl_strlcat(msg, tmp, SH_BUFSIZE); sh_error_handle (ShKernSeverity, FIL__, __LINE__, status, MSG_KERN_SYSCALL, /* syscall_code[0], syscall_code[1], sh_syscalls[i].code[0], sh_syscalls[i].code[1], */ i, _(sh_syscalls[i].name), msg); sh_syscalls[i].code[0] = syscall_code[0]; sh_syscalls[i].code[1] = syscall_code[1]; } } } } SH_FREE(sys_list); if(kvm_close(kd) < 0) { sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_SUBGEN, kvm_geterr(kd), _("kvm_close") ); exit(EXIT_FAILURE); } SL_RETURN( (0), _("sh_kern_check_internal")); } #endif /************* * * module init * *************/ #if defined(HOST_IS_LINUX) #include #endif static int AddressReconf = 0; int sh_kern_init () { #if defined(HOST_IS_LINUX) struct utsname buf; char * str; #endif SL_ENTER(_("sh_kern_init")); if (ShKernActive == S_FALSE) SL_RETURN( (-1), _("sh_kern_init")); #if defined(HOST_IS_LINUX) uname(&buf); if ((AddressReconf < 5) && (0 != strcmp(SH_KERNEL_VERSION, buf.release))) { str = SH_ALLOC(256); sl_snprintf(str, 256, "Compiled for kernel %s, but current kernel is %s, and kernel addresses have not been re-configured", SH_KERNEL_VERSION, buf.release); sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN, str, _("kern_check") ); SH_FREE(str); ShKernActive = S_FALSE; SL_RETURN( (-1), _("sh_kern_init")); } #endif lastcheck = time (NULL); if (sh.flag.checkSum != SH_CHECK_INIT) { sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN, _("Checking kernel syscalls"), _("kern_check") ); } sh_kern_check_internal (); SL_RETURN( (0), _("sh_kern_init")); } /************* * * module cleanup * *************/ int sh_kern_end () { return (0); } /************* * * module timer * *************/ int sh_kern_timer (time_t tcurrent) { if (ShKernActive == S_FALSE) return 0; if ((int) (tcurrent - lastcheck) >= ShKernInterval) { lastcheck = tcurrent; return (-1); } return 0; } /************* * * module check * *************/ int sh_kern_check () { sh_error_handle (SH_ERR_INFO, FIL__, __LINE__, EINVAL, MSG_E_SUBGEN, _("Checking kernel syscalls"), _("kern_check") ); return (sh_kern_check_internal ()); } /************* * * module setup * *************/ int sh_kern_set_severity (const char * c) { char tmp[32]; tmp[0] = '='; tmp[1] = '\0'; sl_strlcat (tmp, c, 32); sh_error_set_level (tmp, &ShKernSeverity); return 0; } int sh_kern_set_timer (const char * c) { long val; SL_ENTER(_("sh_kern_set_timer")); val = strtol (c, (char **)NULL, 10); if (val <= 0) sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, _("kern timer"), c); val = (val <= 0 ? 60 : val); ShKernInterval = (time_t) val; SL_RETURN( 0, _("sh_kern_set_timer")); } int sh_kern_set_activate (const char * c) { int i; SL_ENTER(_("sh_kern_set_activate")); i = sh_util_flagval(c, &ShKernActive); SL_RETURN(i, _("sh_kern_set_activate")); } int sh_kern_set_idt (const char * c) { int i; SL_ENTER(_("sh_kern_set_idt")); i = sh_util_flagval(c, &ShKernIDT); SL_RETURN(i, _("sh_kern_set_idt")); } int sh_kern_set_sc_addr (const char * c) { char * endptr; unsigned long value; SL_ENTER(_("sh_kern_set_sc_addr")); errno = 0; value = strtoul(c, &endptr, 16); if ((ULONG_MAX == value) && (errno == ERANGE)) { SL_RETURN((-1), _("sh_kern_set_sc_addr")); } if ((*c == '\0') || (*endptr != '\0')) { SL_RETURN((-1), _("sh_kern_set_sc_addr")); } system_call_addr = value; ++AddressReconf; SL_RETURN((0), _("sh_kern_set_sc_addr")); } int sh_kern_set_sct_addr (const char * c) { char * endptr; unsigned long value; SL_ENTER(_("sh_kern_set_sct_addr")); errno = 0; value = strtoul(c, &endptr, 16); if ((ULONG_MAX == value) && (errno == ERANGE)) { SL_RETURN((-1), _("sh_kern_set_sct_addr")); } if ((*c == '\0') || (*endptr != '\0')) { SL_RETURN((-1), _("sh_kern_set_sct_addr")); } kaddr = (unsigned int) value; ++AddressReconf; SL_RETURN((0), _("sh_kern_set_sct_addr")); } int sh_kern_set_proc_root (const char * c) { char * endptr; unsigned long value; SL_ENTER(_("sh_kern_set_proc_root")); errno = 0; value = strtoul(c, &endptr, 16); if ((ULONG_MAX == value) && (errno == ERANGE)) { SL_RETURN((-1), _("sh_kern_set_proc_root")); } if ((*c == '\0') || (*endptr != '\0')) { SL_RETURN((-1), _("sh_kern_set_proc_root")); } proc_root = value; ++AddressReconf; SL_RETURN((0), _("sh_kern_set_proc_root")); } int sh_kern_set_proc_root_iops (const char * c) { char * endptr; unsigned long value; SL_ENTER(_("sh_kern_set_proc_root_iops")); errno = 0; value = strtoul(c, &endptr, 16); if ((ULONG_MAX == value) && (errno == ERANGE)) { SL_RETURN((-1), _("sh_kern_set_proc_root_iops")); } if ((*c == '\0') || (*endptr != '\0')) { SL_RETURN((-1), _("sh_kern_set_proc_root_iops")); } proc_root_iops = value; ++AddressReconf; SL_RETURN((0), _("sh_kern_set_proc_root_iops")); } int sh_kern_set_proc_root_lookup (const char * c) { char * endptr; unsigned long value; SL_ENTER(_("sh_kern_set_proc_root_lookup")); errno = 0; value = strtoul(c, &endptr, 16); if ((ULONG_MAX == value) && (errno == ERANGE)) { SL_RETURN((-1), _("sh_kern_set_proc_root_lookup")); } if ((*c == '\0') || (*endptr != '\0')) { SL_RETURN((-1), _("sh_kern_set_proc_root_lookup")); } proc_root_lookup = value; ++AddressReconf; SL_RETURN((0), _("sh_kern_set_proc_root_lookup")); } #endif /* #ifdef SH_USE_KERN */ #endif