Linux内核即时入侵检测安全增强-实现

  四.实现 冰块   这一段我们来实现我们刚才提出的在linux系统下建立参考监视器的设想。开始我们将描述一个访问控制功能函数,这个功能函数包括增加到内核的访问控制数据库(ACD)的数据结构定义。这个新的系统调用来读,写和升级ACD和参考功能函数。还会附有check_rootproc的代码。4.1 认证功能函数  访问控制数据库包括一个关于每一个系统调用的参考监视器。在这里,只有两个主要的数据结构起作用,一个叫做setuid_acd用来检查对setuid的系统调用,一个是execve_acd来检查对execve的系统调用。这两个结构都在下面的图2中列出。  /*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;  图2  Setuid_acd只包括串rpasswd,用来保存在内核存储的加密root密码。这是用来健壮性的对  setuid系统调用认证进行实现的。  Execve_acd包括两个eflst_t结构的数组:  Admitted:在这个结构里提供了一个入口给可执行的文件F,一个setuid程序需要通过执行F来调用execve。在入口里存储了所有的调用F的setuid程序的列表。  Failure:这里保存了一些没有得到认证的利用setuid进程来调用execve尝试的日志。  下面列出了一个admitted数据结构,这个结构是一个有关于可执行文件的列表和指向一系列setuid程序的数组。  Failure数据结构没有在这里列出,它和admitted数据结构差不多,但是它会动态的增长,记录那些非授权的setuid程序的访问。  每一个admitted数据结构的元素包括下面三个域:efid,proc_nr和programs.  Efid标明可执行文件F。存储在efid的信息为:  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到内核内存区域。它会删除在内核区域和用户区域的密码拷贝。  系统管理员(root用户)可以通过一些新的命令来管理访问控制数据库汇写到sys_setuid_aclm系统调用中,它叫做aclmng,它有以下的功能选项:  -l 列出保存在内核区域的访问控制数据库的内容。  -L 从文件/etc/bop/acd中引导数据到访问控制数据库,大多数都用在启动时刻。  -w从文件/etc/bop/acd中写数据到访问控制数据库,,大多数都用在系统关闭的时刻。  -h 显示功能信息;  efault 如果没有选项,默认执行-l选项。4.2 函数参考  /*  *sys_execve() executes a new program.  */  int do_execve  (char * filename,char **argv,char **envp,struct pt_regs *regs){  ……  dentry=open_namei(filename,0,0);  retval=PRT_ERR(dentry);  if (IS_ERR(dentry))  return retval;  ……  retval=prepare_binprm(&bprm);  /*************BUFF OWERFLOW PATCH**********************/  rc=check_rootproc(bprm.dentry->d_inode);  if ((rc==EXENA)||(rc==EFNA)){  printk(BOP_LEVEL”BOP kernel:do_execve psuid %s no  authorized to exec file %sn”,current->comm,filename);  printk(BOP_LEVEL”by euid %d uid %dn”,  current->euid,current->uid);  if (rc==EXENA)  printk(BOP_LEVEL”EXE NO AUTHORIZEDn”);  else printk(BOP_LEVEL”EXE NO AUTHENTICATEDn”);  return rc;  }  /*****************************************************/  …….  if (retval>=0)  retval=search_binary_handler(&bprm,regs);  if (retval>=)  /*execve success*/  return retval;  …….  }  图3  /*  *kernel/sys.c  */  int setuid(uid_t uid){  if (suser()) { /*if euid==0*/  #define IS_SETUID_TO_ROOT(current)){  read(unencrypted);  get_pw(correct);  encrypted=crypt(unencrypted,correct);  memset(unencrypted,0,strlen(unencrypted));  if(strcmp(encrypted,correct)){  printk(BOP_LEVEL”Error in setuid from uid %d n”,current->uid);  return -EPERM;  }else /* ok auth .User root,set uids*/  }else /*non setuid-root*/  ……….  }  图4  这一节我们介绍图3中的系统调用的函数功能。  Execve 在图3,我们加了一段程序代码到里面。Check_rootproc()函数检查调用execve这个系统调用的进程是否符合访问控制数据库定义的规则。系统调用会在check_rootproc返回下面两个值的时候终止:  EXENA:调用的进程不能得到调用该系统调用的请求认证。就是说,请求调用的进程没有得到在访问控制数据库规则允许的列表中。  EFNA:调用的进程得到运行的认证,但是文件没有得到认证,如,修改时间或是文件大小不匹配。  在后语里我们会提供一个check_rootproc函数的细节。如果调用的进程没有用root级别运行EUID=0的话,就不对进程的进行其他的检查了。除非这个进程可以通过访问控制数据库的认证。  Setuid 图4显示了setuid的系统调用的代码。这个调用的认证和execve差不多。一个运行要想调用setuid(0)来得到uid=0的程序,必须要键入root的密码。这个密码保存在访问控制数据库中。如果密码不匹配,进程就会被禁止。就象我们经常用的su命令一样,必须键入root密码才可以获得一个root级别的shell。  /*  *fs/open.c  */  asmlinkage int sys_chmod(const char *filename,mode_t mode)  {struct dentry *dentry;  struct inode *inode;  int error;  struct iattr newattrs;  lock_kernel();  dentry=namei(filename);  /****************BUFFER OWERFLOW PATCH**************/  #define IS_SETUID_TO_ROOT(proc) !((proc)->euid)&&(proc)->uid  #define S_ISREG(dentry->d_inode->i_mode)||S_ISDIR(dentry->d_inode->i_mode))){  printk(BOP_LEVEL”BOP proc %s failed changing mode:n”,current->comm);  printk(BOP_LEVEL”inode %d device %dn”,  (int) dentry->d_inode->i_ino,(int) dentry->d_inode->i_dev);  printk(BOP_LEVEL”uid %d gid %dn”,  dentry->d_inode->i_uid,dentry->d_inode->i_gid);  printk(BOP_LEVEL”from %d to %dn”,dentry->d_inode->i_mode,mode);  return -EPERM;  }  /**********************************************/  图5  图5显示了在chmod系统调用中另外加的一段代码。这里和setuid的区别就是这里不需要root密码的认证。  代码chown()和chgrp系统调用的增加和chmod类似。穿越茫茫人海,寻找属于我们的那一份宁静。

Linux内核即时入侵检测安全增强-实现

相关文章:

你感兴趣的文章:

标签云: