红联Linux门户
Linux帮助

Linux内核入侵检测安全增强实现(下)

发布时间:2006-10-24 09:49:36来源:红联作者:coolentboy
  四.实现

  这一段我们来实现我们刚才提出的在linux系统下建立参考监视器的设想。开始我们将描述一个访问控制功能函数,这个功能函数包括增加到内核的访问控制数据库(ACD)的数据结构定义。这个新的系统调用来读,写和升级ACD和参考功能函数。还会附有check_rootproc的代码。

  4.1 认证功能函数

  访问控制数据库包括一个关于每一个系统调用的参考监视器。在这里,只有两个主要的数据结构起作用,一个叫做setuid_acd用来检查对setuid的系统调用,一个是execve_acd来检查对execve的系统调用。这两个结构都在下面的图2中列出。

[code]/*setuid_acd*/

  static char rpasswd[LEN_PWD];

  /*execve_acd*/

  typedef struct setuid_proc_id{

  char comm[16];

  unsigned long count;

  }suidpid_t;

  typedef struct setuid_program{

  suidpid_t suidp_id;

  suidp_t *next;/*下一个程序*/

  }suidp_t;

  typedef struct exe_file_id{

  __kernel_dev_t device; /*设备号码r*/

  unsigned long inode; /*inode结点号码*/

  __kernel_off_t size; /*大小*/

  __kernel_time_t modif: /*修改时间*/

  }efid_t;

  typedef struct executable_file{

  efid_t efid;/*文件鉴定时间信息*/

  int prog_nr; /*可以调用exe的程序数量*/

  suidp_t *programs; /*认证程序列表*/

  }efile_t;

  typedef struct executable_file_list{

  efile_t lst[NR_EXE];

  unsigned int total; /*在列表里的exe的总数*/

  }eflst_t;[/code]

  Setuid_acd只包括串rpasswd,用来保存在内核存储的加密root密码。这是用来健壮性的对setuid系统调用认证进行实现的。Execve_acd包括两个eflst_t结构的数组:

  Admitted:在这个结构里提供了一个入口给可执行的文件F,一个setuid程序需要通过执行F来调用execve。在入口里存储了所有的调用F的setuid程序的列表。

  Failure:这里保存了一些没有得到认证的利用setuid进程来调用execve尝试的日志。
文章评论

共有 2 条评论

  1. coolentboy 于 2006-10-24 09:51:02发表:

      系统管理员(root用户)可以通过一些新的命令来管理访问控制数据库汇写到sys_setuid_aclm系统调用中,它叫做aclmng,它有以下的功能选项:

      -l 列出保存在内核区域的访问控制数据库的内容。

      -L 从文件/etc/bop/acd中引导数据到访问控制数据库,大多数都用在启动时刻。

      -w从文件/etc/bop/acd中写数据到访问控制数据库,大多数都用在系统关闭的时刻。

      -h 显示功能信息;efault 如果没有选项,默认执行-l选项。

      五.后语

      这篇文章的整个补丁代码我没有找到,可能是因为这个人关于这个东西的开发已经放弃了吧。呵呵,如果谁能找到。这篇文章和以前发表的LIDS文章都是关于内核模块级的系统安全的。这篇主要是对缓冲区溢出的漏洞进行防范。虽然没有代码的原形,但是它给出的几个代码事例能够帮助我们更好的理解Linux的内核模块如何截获系统调用,或是如何对进程运行权分析的实现。对于我们理解Linux和其他操作系统的内核有一定的帮助。希望大家能通过这篇文章能多提高点理解认识,对以后自己开发系统安全软件能有一定理论上的帮助作用。下面是check_rootproc函数的代码:

    [code]/*check_rootproc.c*/

       int check_rootproc(struct inode *ino){

       int cont=0,iproc=0,error=0;

       suidp_t * suidproc;

       efile_t f;

       suidp_t p;


       if ((IS_SETUID_TO_ROOT(current))||(IS_A_ROOT_DAEMON(current))) {

       for (;cont

       if ((permitted.lst[cont].efid.device==ino->i_dev&&

       permitted.lst[cont].efid.inode==ino->i_ino)){

       if ((permitted.lst[cont].efid.size==ino->i_size)&&

       permitted.lst[cont].efid.modif==ino->i_mtime)){

       suidproc=permitted.lst[cont].processes;

       for(iproc=1;iproc<=permitted.lst[cont].proc_nr;iproc++){

       if(!strcmp(suidproc->suidp_id.comm,current->comm)){

       suidproc->suidp_id.count++;

       return PSA;

       }

       if (iproc

       suidproc=suidproc->next;

       }

       }

       }else{

       error=EFNA;

       goto file_exe_unauthorized;

       }

       }

       }

       error=EXENA;/*EXE is not in the database*/

       goto file_exe_unauthorized;

       }

       return PNS;/*the process is not setuid to root or root daemon*/


       file_exe_unauthorized:

       f.efid.device=ino->i_dev;

       f.efid.inode=ino->i_ino;

       f.efid.size=ino->i_size;

       f.efid.modif=ino->i_mtime;

       strncpy(p.suidp_id.comm,current->comm,

       sizeof(p.suidp_id.comm));

       p.suidp_id.count=1;

       do{

       while(writer_pid!=0){

       cli();/*interrupt disabled*/

       if (writer_pid!=0)

       interruptible_sleep_on(&pid_queue);

       sti();

       }

       }

       while(!atomic_access(&writer_pid,current->pid));

       /*start of critical section*/

       do_setuid_put(&(f.efid),&(p.suidp_id),FAILURE);

       writer_pid=0;/*end of critical section*/

       atomic_access(&writer_pid,0);/*release of the lock*/

       return error;


       }[/code]

  2. coolentboy 于 2006-10-24 09:50:19发表:

      下面列出了一个admitted数据结构,这个结构是一个有关于可执行文件的列表和指向一系列setuid程序的数组。Failure数据结构没有在这里列出,它和admitted数据结构差不多,但是它会动态的增长,记录那些非授权的setuid程序的访问。每一个admitted数据结构的元素包括下面三个域:efid,proc_nr和programs. Device 这个是F的文件系统的设备号码;Inode 文件F的inode号码;Size 文件F的字节长度;Modif 这里保存了对文件F的最后修改时间;这里的device和inode能够唯一独立的标明一个系统文件F。size和modif允许来检测非授权的文件内容修改。Proc_nr:这个域来标明程序列表的长度,这个列表是可调用文件F的setuid程序的列表数量。Programs:是一个指向setuid程序的一个指针,每一个元素,叫做suidp_id,包含两个域:comm和count。Comm保存了在setuid程序的名称的一个备份。域count是用来统计和指出在F文件上的调用数量的。

      在下面的阶段里,我们描述sys_setuid_aclm,这是个新的系统调用,只能被UID=0和EUID=0的root级进程才可以调用的系统调用。Sys_setuid_aclm的目的是用来实现对存储在ACD里面的信息进行读和修改的功能的。

      由于root进程可以访问ACD数据库,这样就会出现冲突。因此我们的定义了一个原始的增强程序来处理这些冲突的程序。一般情况下,一个叫做write_pid来实现这个互斥。为了避免对write_pid自身的竞争,这个变量必须可以检测和自动升级。这个功能可以借助调用atomic_access,这个调用是来实现intel体系结构的自动改变的:xchg。实际上,sys_setuid_aclm系统调用从头到尾经历了六个不同的操作,以下就是对这六个操作的描述:

      PUT(exe-file,suid-prog,list)增加(exe-file,suid-prog)组合对到特定的ACD列表中,可能返回的值有:

      PUTEP (exe-file,suid-prog)组合对已经成功的加入;

      PUTPI exe-file已经在ACD中出现,只有suid-prog被加进ACD中。

      PUTAE (exe-file,suid-prog)组合对已经在ACD中出现,没有任何的操作执行。

      PUTFULL 数据结构已经满;对NR-SUID-EXE的限制已经溢出,升级终止退出。

      PUTBUSY ACD数据库忙,另外一个进程正在升级。

      GET(exe-file,suid-prog,param)从param-list中读出(param-file-nr,param-proc-nr)组合对。可能的返回值为。

      GETOK 这个对已经成功的读出,并且不是列表中的最后一个。

      GETL最后一对组合已经关联文件param.file-nr;

      GETLACL最后的在ACD中的对已经读出。

      GETOB越出边界,没有这样的组合对(param.file-nr,param.proc-nr);

      GETBUSY ACD数据库忙,另外一个升级进程正在运行。

      PUTHEADERACL(header-acl)在内核内存区存储ACD的头部。这个对于在补丁安装后系统的第一次启动运行很重要。如果这个服务不可行,就会返回PUTBUSY。

      GETHEADERACL(local-header-acl)在内核区域重新找访问控制数据库的头部,并且存储在变量local-header-cal中。

      DELETE(exe-file,suid-prog,list)在特定的列表中删除(exe-file,suid-prog)组合对。如果exe-file为NULL,就会删除在(*,suid-prog)中所有的组合对,就是用它来阻止suid-prog执行其他的文件。

      PUT-PWD(param)写密码文件param->passwd到内核内存区域。它会删除在内核区域和用户区域的密码拷贝。