Username: Password:

LIDS精通和进阶(一)
来源:作者: 发布时间:2007-12-05 06:21:58

 
一、系统入侵
冰块


   随着Internet上的Linux主机的增加,越来越多的安全漏洞在当前的GNU/Linux系统上发现。您也许在Internet上听说过在Linux下发现Bug,他会导致系统很容易的被黑客攻击。

   因为Linux是个开放源代码的系统,漏洞很容易发现,并且也会很快的有补丁出来。但是当漏洞没有公开的时候,并且管理员很懒,没有去打补丁。黑客就会很容易的攻击这个系统,取得root权限,在现有的GNU/Linux下,他就能够做任何他想做的事情。现在您能够问,我们现在到底能够做些什么呢?

1、现在的GNU/Linux错误在哪里?

终极用户会滥用职权,他能够做任何他要做的事情。作为root。他会改变任何的东西。
许多系统文档很容易被更改。这些文档可能是很重要的文档,如/bin/login,假如一个黑客进入,他能够上传一个login程式来覆盖/bin/login,这样他就能够不用登陆名和密码来登陆系统。但是这些文档无需经常改变,除非您要升级系统。
模块modules很容易用来中断内核。模块是为了让Linux内核更模块话和更高效而设计的。但是当模块加入到内核,他就会成为内核的一部分并且能做原始内核能做的工作。因此,一些不友好的代码能够写成模块来加入到内核里,这些代码就会重定向系统调用并且作为一个病毒来运行。
进程是不受保护的,一些进程,如后台的Web服务器,一直都认为是没有严格保护的程式。因此,他们就会很容易被黑客攻击。
2、LIDS的设想是什么。

保护重要文档。因为文档很容易被root更改,为什么不严格文档操作呢?因此,LIDS改变了文档系统在内核里的安全系统调用。假如某个时候一些人访问一个文档,他就会进入系统调用然后我们就能够检查文档名并且看她们是否被保护。假如他已被保护,我们就能够拒绝这个访问者的需要。
保护重要的进程。这个和上面的保护进程的想法不是相同的。当一个系统里运行一个进程,他会在/proc 文档系统里有一个用pid作为路径名的入口。所以,假如您用"ps -axf"您就能够显示出当前运行的进程。您能够问假如保护这些进程。假如您要杀死一个进程的话,首先,您键入"ps"来得到进程的PID,然后,您键入"kill 〈pid〉"来杀死他。但是,假如我不让您看到进程,您怎么来杀死这个进程呢?因此,LIDS是用隐藏进程来保护他的。 另外一个重要的方法就是不让任何人能够杀死进程,包括root用户。LIDS能够保护父进程是init(pid=1)的任何进程 。
封装内核。有时候我们需要要把一些必要的模块加入到内核里来使用,另外,我们也要拒绝任何人包括root用户向内核插入模块。那么怎样来平衡这个矛盾的问题呢?我们能够只允许在系统启动的时候插入模块,然后我们封装模块,在封装后,内核不允许任何人插入模块到内核里。通过这种封装功能,我们能用他来保护重要的文档,进程,我们能够在系统启动的时候只允许必要的进程,只改变必要的文档。在封装内核后,我们就不能在对文档有任何的修改。

二、保护文档系统
冰块


1、保护文档系统是LIDS的重要功能之一。这个功能是在内核的VFS(虚拟文档系统)层实现的,我们能够保护任何种类的文档系统,如EXT2,FAT。 在LIDS,保护的文档按种类分为以下几种:

只读的文档或目录。只读文档意味着他们不被允许改写,如,在目录/usr/bin,/sbin。这些类型的文档大多数都是二进制系统程式或是系统配置文档,除了在升级系统的时候,我们无需改变他们。
只可增加文档或目录。这些文档是那些只能够增加大小的文档。大多数是系统的日值文档,如在/var/log里的只可增加文档。
额外的文档或目录,这些文档没有被保护。一般来说,您想要保护目录下的任何文档,但是,还需要有一些特别的文档不要被保护。所以我们能够定义这些文档作为额外的其他的只读文档。
保护挂载或卸载文档系统。当您在启动的时候挂载文档系统的时候,您能够禁止任何人,甚至是root,去卸载文档系统。您也能够禁止任何人在当前文档系统下挂载文档系统来覆盖他。
2、LIDS怎样在内核保护文档

在这部分,我们会看到一些内核的代码来理解LIDS是怎样保护文档的。

(1)、Linux文档系统数据结构程式

首先,我们必须了解Linux的虚拟文档系统。

在Linux里的每一个文档,不管是什么样子的,都有一个结点inode数,文档系统提供了以下数据结构。

在/usr/src/linux/include/linux/fs.h

struct inode {
struct list_head     i_hash;
struct list_head     i_list;
struct list_head     i_dentry;

unsigned long       i_ino; ----> inode number.
unsigned int       i_count;
kdev_t          i_dev; ----> device number.
umode_t          i_mode;
nlink_t          i_nlink;
uid_t           i_uid;
......
}

注意: 用来鉴定一个结点inode。这个意思是您能够用一对 来得到一个系统里独一无二的inode。

在/ur/src/linux/cinclude/linux/dcache.h里

struct dentry {
     int d_count;
     unsigned int d_flags;
     struct inode * d_inode;       /* Where the name belongs to - NULL is negative */
     struct dentry * d_parent;     /* parent directory */
     struct dentry * d_mounts;     /* mount information */
     struct dentry * d_covers; struct list_head d_hash;   /* lookup hash list */
     struct list_head d_lru;      /* d_count = 0 LRU list */
     struct list_head d_child;     /* child of parent list */
     struct list_head d_subdirs;    /* our
     ......
}

dentry是个目录文档的入口。通过这个入口,我们能够很容易的在文档的父目录下移动。

例如,假如您一文档的inode是(struct inode*)file_inode,假如您能够用file_inode->d_entry来得到他的目录入口并且用file_inode->d_entry->d_parent来得到父目录的目录入口。

(2)、LIDS保护数据结构

在分析完linux文档系统后,让我们来看看LIDS是怎样容VFS来保护文档和目录的。

在/usr/src/linux/fs/lids.c

struct secure_ino {
     unsigned long int ino;     /* the inode number */
     kdev_t dev;           /* the dev number /*
     int type;            /* the file type */
     };

上面的结构用一对 来存储保护文档或目录的结点。"type"是用来标明保护结点文档类型的。

LIDS有4种类型:

在/usr/src/linux/include/linux/fs.h

#define LIDS_APPEND    1    /* APPEND ONLY FILE */
#define LIDS_READONLY   2    /* Read Only File */
#define LIDS_DEVICE    3    /* Protect MBR Writing to device */
#define LIDS_IGNORE    4    /* Ignore the protection */

通过secure_ino结构,我们能很容易的初使化保护的文档或是在内核里执行以下函数。

在/usr/src/linux/fs/lids.c

int lids_add_inode(unsigned long int inode ,kdev_t dev , int type)
{

      if ( last_secure == (LIDS_MAX_INODE-1))
      return 0;

      secure[last_secure].ino = inode;
      secure[last_secure].dev = dev;
      secure[last_secure].type = type;
      secure[++last_secure].ino = 0;

#ifdef VFS_SECURITY_DEBUG
      printk("lids_add_inode : return %dn",last_secure);
#endif
      return last_secure;
}

就象您在上面代码上能够看到的,给secure_ino加到一个结点上是很容易的。被保护的结点会在系统启动的时候初使化。初使化程式在/usr/src/linux/fs/lids.c的init_vfs_security()里。

现在,让我们看看LIDS是怎样来检查是否一个结点已受到保护。

在/usr/src/linux/fs/open.c

int do_truncate(struct dentry *dentry, unsigned long length)
{
      struct inode *inode = dentry->d_inode;
      int error;
      struct iattr newattrs;
      /* Not pretty: "inode->i_size" shouldn really be "off_t". But it is. */
      if ((off_t) length < 0)
      return -EINVAL;

#ifdef CONFIG_LIDS
      if (lids_load && lids_local_load) {
      error =
      lids_check_base(dentry,LIDS_READONLY);
      if (error) {
               lids_security_alert("Try to truncate a protected file (dev %d %d,inode %ld)",
               MAJOR(dentry->d_inode->i_dev),
               MINOR(dentry->d_inode->i_dev),
               dentry->d_inode->i_ino);
.....................

这个是LIDS加到内核里做检测的一个例子。您会看到lids_check_base()是LIDS保护方法的一个核心函数。

您能够在LIDS要保护的地方看到很多LIDS保护方法用到lids_check_base()函数,特别是在linux内核的子目录下。

在/usr/src/linux/fs/lids.c

int lids_check_base(struct dentry *base, int flag)
{
..................
inode = base->d_inode;     /* get the inode number */
parent = base->d_parent; /* get the parent diretory */
.................
---->  do {
          if ( inode == parent->d_inode)
          break;
          if ((retval = lids_search_inode(inode))) {
            if ( retval == LIDS_IGNORE || (retval == LIDS_DEVICE && flag != LIDS_DEVICE)) break;
            if ( flag == LIDS_READONLY || ( flag == LIDS_APPEND && retval >flag ) || ( flag == LIDS_DEVICE && flag == retval )) {
                          return -EROFS;
                       } break; }
                       inode = parent->d_inode;
                   } while( ((parent = parent->d_parent ) != NULL) );
             return 0;
      }

lids_check_base()会检查一个给定文档的dentry和他的父目录是否被保护。

注意:假如他的父目录被保护,他下面的文档也会被保护。

例如,假如"/etc/"被保护,"/etc/passwd"也相同被保护。

(3)、在内核保护系统调用

为了保护系统,LIDS会在一些检查临界的系统调用的时候做检查。因此,我们能够保护系统调用和限制文档系统的用户调用。

这些是一些例子:

open(),open是通过禁止一些权利来保护文档的打开。您能够在打开调用open_namei()调用的时候LIDS在检测他。
mknod(),mknod是用来在指定目录下保护mknod。
unlink(),在内核代码检查do_unlink()。

三、保护设备
冰块


Linux的设备会在/dev/目录下以文档的形式列出,我们能够用上面保护文档的方法来保护设备。但是在一些情况下,用户也能够用IO操作来旁路文档系统来读写设备,我们必须注意这个问题。

1、设备,内核I/O

在GNU/Linux系统下的设备会以文档的形式表达,所以我们能够用保护文档系统那样来保护设备。

用户的I/O访问是通过系统调用sys_operm和sys_iopl来实现的。您能够看看/usr/src/linux/arch/i386/kernel/ioport.。这个是要基于系统结构的,要是到其他平台,就需要注意他们的变化。

2、怎样用LIDS来保护

大多数情况下,程式无需通过在/dev的设备文档名称来访问设备。但是,一些特别的程式需要直接访问,如X Server,这个会写到/dev/mem和甚至是I/O设备。我们需要一些额外的东西来保护设备。LIDS会在配置内核的时候来定义这个功能。

CONFIG_LIDS_ALLOW_DEV_MEM,假如您选择了开启这个功能,您就能够允许一些特别程式来访问/dev/men和/dev/kmen这些内核临界的设备。假如您想要用内核的X Server,选择这个功能就会在配置内核的时候提供整个路径和文档名。
CONFIG_LIDS_ALLOW_RAW_DISKS,假如选择这个开启,您就能够允许一些特别的程式来访问物理磁盘。
CONFIG_LIDS_ALLOW_IO_PORTS,假如您选择了开启这个功能,您就能够允许一些特别的程式来访I/O端口。
当系统运行fs/lids.c里的init_vfs_security()的时候初使化就被调用。

#ifdef CONFIG_LIDS_ALLOW_DEV_MEM

lids_fill_table(allow_dev_mem,&last_dev_mem,LIDS_MAX_ALLOWED,CONFIG_LIDS_DEV_MEM_PROGS);

#endif

#ifdef CONFIG_LIDS_ALLOW_RAW_DISKS

lids_fill_table(allow_raw_disks,&last_raw_disks,LIDS_MAX_ALLOWED,CONFIG_LIDS_RAW_DISKS_PROGS);

#endif

#ifdef CONFIG_LIDS_ALLOW_IO_PORTS

lids_fill_table(allow_io_ports,&last_io_ports,LIDS_MAX_ALLOWED,CONFIG_LIDS_IO_PORTS_PROGS);

#endif

假如一个进程或是程式要直接访问ip端口或是磁盘设备,LIDS就会检查他在数组allow_raw_disk,last_io_ports,等)。这个检查是通过调用lids_check_base()里的lids_search_inode(inode)来实现的。

如,让我们看看CONFIG_LIDS_ALLOW_DEV_MEM

/* in lids_search_inode() */

#ifdef CONFIG_LIDS_ALLOW_DEV_MEM

for( i = 0 ; i < last_dev_mem ;i++ ) {

if ( allow_dev_mem[i].ino == ino && allow_dev_mem[i].dev == dev) {

return LIDS_READONLY;

}

}

#endif

#ifdef CONFIG_LIDS_ALLOW_RAW_DISKS

在allow_dev_mem包括了哪一个程式结点在系统启动的时候在init_vfs_security()里初使化。用同样的方法,除了一些特别程式,我们能够保护设备,I/O访问等等。
    
  

喜欢本文,那就收藏到:

    Del.icio.us Google书签 Digg Live Bookmark Technorati Furl Yahoo书签 Facebook 百度搜藏 新浪ViVi 365Key网摘 天极网摘 和讯网摘 博拉网 POCO网摘 添加到饭否 QQ书签 Digbuzz我挖网
相关评论  我也要评论
还没有关于此文章的相关评论!
  • 昵称: (为空则显示guest)
  • 评论分数: ★ ★ ★★★ ★★★★ ★★★★★
  • 评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
  • 导航
    赞助商
    文章类别
    订阅