系统调用日志收集系统

1,系统调用日志收集系统的意义。
       系统调用是用户获取系统服务的唯一入口,因此对系统调用的安全调用直接关系到系统
的安全,假如有用户恶意不断地调用系统调用,将会导致系统负载增加,所以如果能收集到时谁
调用了一些危险的系统调用,以及调用系统调用的时间和其他信息,将有助于系统管理员进行事
后追踪,从而提高系统的安全性。
--------------------------------------------------------------
2,系统调用日志收集系统总体框架图。
 
-----------------------------------------------------------
3,系统调用日志收集系统的实现。(以linux-2.6..39.4为例)

        3.1,添加系统调用号.
         位置:arch/x86/include/asm/unistd_32.h
        #define  __NR_syscall_audit   345
        #define  __NR_myaudit         346
        #ifdef   __KERNEL__

        #define  NR_syscalls    347
---------------------------------------------------------- 
       3.2,在系统调用表中添加相应的表项。
        .long    sys_syscall_audit
        .long    sys_myaudit
-----------------------------------------------------------
       3.3,修改系统调用入口。(有两个入口,syscall_call和sysenter)
        位置:arch/x86/kernel/entry_32.S
        主要是在系统调用的两个入口进行监控,发现调用了如下四个系统调用(getpid,sysinfo,fork,execv)
将会执行 sys_syscall_audit函数

  1. syscall_call:
  2.     call *sys_call_table(,%eax,4)
  3.     movl %eax,PT_EAX(%esp)        # store the return value
  4. #如下位添加代码
  5. #----------------------------------------------------
  6.     cmpl $20,0x2c(%esp) #getpid()
  7.     je myauditsys
  8.     cmpl $116,0x2c(%esp) #sysinfo()
  9.     je myauditsys
  10.     cmpl $2,0x2c(%esp) #fork
  11.     je myauditsys
  12.     cmpl $11,0x2c(%esp) #execv
  13.     je myauditsys
  14. #-----------------------------------------------
  1. syscall_exit:
  2.     LOCKDEP_SYS_EXIT
  3.     ...
  4.     jne syscall_exit_work
  5. #如下位添加代码
  6. #------------------------------------------------
  7.     jmp restore_all
  8. myauditsys:
  9.     pushl %eax
  10.     pushl 0x30(%esp)
  11.     call sys_syscall_audit
  12.     popl %eax
  13.     popl %eax
  14.     jmp syscall_exit
  15. #------------------------------------------------
  16. restore_all:
  17.     TRACE_IRQS_IRET
  1. sysenter_do_call:
  2.     ...
  3.     movl %eax,PT_EAX(%esp)
  4.    #如下为添加代码
  5. /*--------------------------------------------------------*/
  6.     cmpl $20,0x2c(%esp) #getpid()
  7.     je enter_audit 
  8.     cmpl $116,0x2c(%esp) #sysinfo()
  9.     je enter_audit
  10.     cmpl $2,0x2c(%esp) #fork
  11.     je enter_audit
  12.     cmpl $11,0x2c(%esp) #execv
  13.     je enter_audit
  14. come_back:
  15. /*--------------------------------------------------------*/
  1. sysenter_exit:
  2.     ....
  3.     ENABLE_INTERRUPTS_SY***IT
  4. /*--------------------------------------------------------*/
  5.     jmp sysenter_audit 
  6. enter_audit:
  7.     pushl %eax
  8.     pushl 0x30(%esp)
  9.     call sys_syscall_audit
  10.     popl %eax
  11.     popl %eax
  12.     jmp come_back
  13. /*--------------------------------------------------------*/
--------------------------------------------------------------------------------------------
       3.4,添加系统调用的服务例程。
      在arch/x86/kernel/下面添加文件myaudit.c
    该文件中实现了系统调用的服务例程,但这儿实现的服务例程都只有一个接口,
真正的实现将在模块中实现,这样是为了方便调试,避免了多次编译内核。这儿主要
是通过两个全局变量( my_audit my_sysaudit )与内核模块之间建立了联系。

  1. /**
  2.  * myaudit.
  3.  */

  4. #include <linux/proc_fs.h>
  5. #include <linux/init.h>
  6. #include <linux/types.h>
  7. #include <linux/sched.h>
  8. #include <asm/current.h>

  9. void (*my_audit)(int, int) = 0;

  10. asmlinkage void sys_syscall_audit(int syscall_number, int return_value)
  11. {
  12.     if (my_audit) {
  13.         return (*my_audit)(syscall_number, return_value);
  14.         printk("IN KERNEL: %s(%d), syscall: %d, return: %d\n", current->comm, (int)current->pid, syscall_number, return_value);
  15.         //printk("IN KERNEL: %s\n", current);
  16.     } else {
  17.         printk("my_audit is empty!\n");
  18.     }
  19.     return ;
  20. }

  21. int (*my_sysaudit)(u8, u8*, u16, u8) = 0;

  22. asmlinkage int sys_myaudit(u8 type, u8 *us_buf, u16 us_buf_size, u8 reset)
  23. {
  24.     if (my_sysaudit) {
  25.         return (*my_sysaudit)(type, us_buf, us_buf_size, reset);
  26.         printk("IN KERNEL: my system call sys_myaudit() working...\n");
  27.     } else {
  28.         printk("my_sysaudit is empty!\n");
  29.     }
  30.     return 0;
  31. }
----------------------------------------------------------------------------------------------
       3.5,修改makefile。位置:arch/x86/kernel/Makefile
 
  1. obj-y            := process_$(BITS).o signal.o entry_$(BITS).myaudit.o
----------------------------------------------------------------------------------------------
       3.6,导出全局变量。(不导出的话,内核模块将对其不可见)
            修改arch/x86/kernel/i386_ksyms_32.c文件,在其末尾追加:

  1. EXPORT_SYMBOL(my_audit);
  2. EXPORT_SYMBOL(my_sysaudit);
----------------------------------------------------------------------------------------------
        3.7,声明全局变量。
             修改:include/linux/module.h 添加:

  1. extern void (*my_audit)(int,int);
  2. extern int (*my_sysaudit)(u8,u8*,u16,u8);



接系统调用日志收集系统 (1)
---------------------------------------------------------------
3.8重新编译内核。
     如何编译内核就不再说了。
----------------------------------------------------------------
3.9插入模块。

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/kernel.h>
  4. #include <linux/types.h>
  5. #include <asm/current.h>
  6. #include <linux/sched.h>
  7. #include <asm/uaccess.h>

  8. #define COMM_SIZE 16

  9. struct syscall_buf {
  10.     u32 serial;
  11.     u32 ts_sec;
  12.     u32 syscall;
  13.     u32 status;
  14.     pid_t pid;
  15.     uid_t uid;
  16.     u8 comm[COMM_SIZE];
  17. };

  18. //初始化一个队列buffer_wait
  19. DECLARE_WAIT_QUEUE_HEAD(buffer_wait);

  20. #define AUDIT_BUF_SIZE 100
  21. //长度为100的缓冲区。
  22. static struct syscall_buf audit_buf[AUDIT_BUF_SIZE];
  23. static int current_pos = 0;//缓冲区中的位置.
  24. static u32 serial = 0;//序列号

  25. void write_buf_audit(int syscall,int return_value)
  26. {
  27.     struct syscall_buf *ppb_tmp;
  28.     printk("write_buf_audit is execing!\n");
  29.     if (current_pos < AUDIT_BUF_SIZE) {
  30.         ppb_tmp = &audit_buf[current_pos];
  31.         ppb_tmp->serial = serial++;
  32.         ppb_tmp->ts_sec = 1;
  33.         ppb_tmp->syscall = syscall;
  34.         ppb_tmp->status = return_value;
  35.         ppb_tmp->pid = current->pid;
  36.         ppb_tmp->uid = current->tgid;
  37.         memcpy(ppb_tmp->comm,current->comm,COMM_SIZE);

  38.         if (++current_pos == AUDIT_BUF_SIZE *1/10) {
  39.          printk("in syscall_audit,it near full!\n");
  40.                 wake_up_interruptible(&buffer_wait);
  41.         }
  42.     }
  43.     return ;
  44. }

  45. int read_buf_audit(u8 type,u8 *us_buf,u16 us_buf_size,u8 reset)
  46. {
  47.     int ret = 0;
  48.     printk("read_buf_audit is execving!\n");
  49.     if (!type) {
  50.         if (clear_user((void *)us_buf, (unsigned long)us_buf_size)) {
  51.             printk("error:clear_user!\n");
  52.             return 0;
  53.         }
  54.         ret= wait_event_interruptible(buffer_wait,current_pos >= AUDIT_BUF_SIZE*1/10);
  55.         if (copy_to_user((void *)us_buf,audit_buf,(current_pos)*sizeof(struct syscall_buf))) {
  56.             printk("error:copy error!\n");
  57.             return 0;
  58.         }
  59.         ret = current_pos;
  60.         current_pos = 0;
  61.     }
  62.     return ret;
  63. }

  64. static int __init audit_init(void)
  65. {
  66.     my_audit = write_buf_audit;
  67.     my_sysaudit = read_buf_audit;
  68.     printk("starting syscall audit!\n");
  69.     return 0;
  70. }

  71. static void __exit audit_exit(void)
  72. {
  73.     my_audit = NULL;
  74.     my_sysaudit = NULL;
  75.     printk("exiting syscall audit!\n");
  76.     return ;
  77. }

  78. module_init(audit_init);
  79. module_exit(audit_exit);
  80. MODULE_LICENSE("GPL");
------------------------------------------------------------------------------------------------------
3.10,启动用户测试程序。
 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <errno.h>
  4. #include <signal.h>
  5. #include <unistd.h>
  6. #include <sys/syscall.h>
  7. #include <sys/types.h>

  8. typedef unsigned char u8;
  9. typedef unsigned int u32;

  10. #define COMM_SIZE 16

  11. struct syscall_buf {
  12.     u32 serial;
  13.     u32 ts_sec;
  14.     u32 syscall;
  15.     u32 status;
  16.     pid_t pid;
  17.     uid_t uid;
  18.     u8 comm[COMM_SIZE];
  19. };

  20. #define AUDIT_BUF_SIZE 100*sizeof(struct syscall_buf)

  21. int main(int argc, char *argv[])
  22. {
  23.     u8 col_buf[AUDIT_BUF_SIZE];
  24.     unsigned char reset = 1;
  25.     int num = 0;
  26.     struct syscall_buf *= NULL;
  27.     u8 j = 0;
  28.     int i;

  29.     while (1) {
  30.         num = syscall(346, 0, col_buf, AUDIT_BUF_SIZE, reset);
  31.         printf("num is: %d\n", num);
  32.         p = (struct syscall_buf *)col_buf;
  33.         for (= 0; i < num; i++) {
  34.             printf("serial: %d ", p[i].serial);
  35.             printf("syscall: %d ", p[i].syscall);
  36.             printf("ts_sec: %d ", ((struct syscall_buf *)col_buf)[i].ts_sec);
  37.             printf("status: %d ", p[i].status);
  38.             printf("pid: %d ", ((struct syscall_buf *)col_buf)[i].pid);
  39.             printf("uid: %d ", ((struct syscall_buf *)col_buf)[i].uid);
  40.             printf("comm: %s\n", ((struct syscall_buf *)col_buf)[i].comm);
  41.         }

  42.         putchar('\n');
  43.     }

  44.     return 0;
  45. }
--------------------------------------------------------------------------------------------------------
3.11,其中用户触发程序。(向内核不断地申请系统调用)

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/sysinfo.h>

  4. int main(void)
  5. {
  6.     struct sysinfo info;
  7.     unsigned long value = 0;
  8.     int i = 0;

  9.     while (1) {
  10.     sysinfo(&info);
  11.     printf("sysinfo is execving!\n");
  12.     value = (unsigned long)getpid(); 
  13.     printf("pid = %lu\n",value);
  14.     sleep(1);
  15.     }
  16.     return 0;
  17. }
----------------------------------------------------------------------------------------------------------------
感想:
          经过几天的时间调试这个程序,最终还是调试通过了,收获还是蛮大的,这个程序中
既要内核编程,还有编写内核模块,还要编写用户态程序。内核态和用户态协调合作。当然
在其中也出现了不少问题,开始我们就没有考虑到sysenter,结果导致使用库函数,对内核
就没有触发,只能使用int 0x80,直接在用户态使用汇编或嵌入汇编才能对其触发。后来把
sysenter这条路“堵死”就好了。
------------------------------------------------------------------------------------------------------------------


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值