linux security model (LSM)加载实现顺序

转载 2013年12月05日 16:27:35

Linux Security Module的注册层次

 

===================================================

作者:ietf AT doit.com.cn

所有源文件来自于linux kernel 2.6.20

请在GNU Library General Public License下参考。

引用请注明出处。

===================================================

selinux的出现着实扰乱了文件系统的进度,不过送算慢慢搞清楚了其中的来龙去脉。下面将通过2.6.20内核中的security代码进行一番简单的分析。该版本的security系统在capabilityrootplug之间还存在一些问题,有很多新的补丁程序,具体可以参考下列邮件列表。

 

http://lists.jammed.com/linux-security-module/2005/08/

 

初次接触LSM时,其间复杂的模块加载方式和顺序很是让人头疼。光其中的ops操作就有security_ops, capability_ops, secondary_ops, selinux_ops, rootplug_ops, selinux_ops, original_ops,再有init函数security_init, capability_init, rootplug_init, selinux_init中的注册关系register_secrity反反复复的来回赋值,最后究竟ops操作都是什么,已经成了一团乱麻。为此,不得不从系统的启动过程开始,寻找其间的因果顺序,事情的经过是这样的:

 

一、LSM的初始化

 

LSM系统的初始化发生在系统内核初始化阶段,在src/init/main.cstart_kernel()里,其位置如下所示:

      fork_init(num_physpages);

      proc_caches_init();

      buffer_init();

      unnamed_dev_init();

      key_init();

      security_init();

      vfs_caches_init(num_physpages);

      radix_tree_init();

      signals_init();

unnamed_dev_init(), key_init()之后,vfs_caches_init之前,其在内核中的位置层次也基本上如此。

 

security_init()的具体实现在/src/security/security.c中,

/**

 * security_init - initializes the security framework

 *

 * This should be called early in the kernel initialization sequence.

 */

int __init security_init(void)

{

      printk(KERN_INFO "Security Framework v" SECURITY_FRAMEWORK_VERSION

            " initialized\n");

 

      if (verify(&dummy_security_ops)) {

             printk(KERN_ERR "%s could not verify "

                   "dummy_security_ops structure.\n", __FUNCTION__);

             return -EIO;

      }

 

      security_ops = &dummy_security_ops;

      do_security_initcalls();

 

      return 0;

}

在此,很有必要了解一下dummy_security_ops的定义,在src/security/dummy.c中,给出了其定义

 

struct security_operations dummy_security_ops;

 

定义后的dummy_security_ops并没有初始化,也就是说,它是security_operations的一个结构,该结构里是一系列的指针,每个指针都指向一个函数,而这些函数,就是security框架所能覆盖的领域,通过修改函数指针,可以达到为原先的系统通过钩子增加一个安全过滤层的目的。即,系统的这些调用,先通过你设计的函数过滤相关操作,再有你的函数调用原先的实现,实现增加一层的目的,这和NT中注册操作的回调函数相似。

 

struct security_operations {.......

dummy_security_ops的初始化是在上面给出的security_initverify(&dummy_security_ops)函数实现的,它将参数XXX_ops中的所有空指针的函数,初始化为dummy.c中定义的dummy_XXX类型对应函数体,每个函数体只提供一个表示成功的返回值,而不执行任何操作。具体参见src/security/dummy.c

 

dummy_security_ops初始化完成后,通过security_ops=&dummy_security_ops,使得security_ops指向一个不做任何操作的过滤层。再通过do_security_initcalls()加载具体配置的安全过滤模块。

 

在来看看do_security_initcalls()函数是怎么实现的:

 

static void __init do_security_initcalls(void)

{

      initcall_t *call;

      call = __security_initcall_start;

      while (call < __security_initcall_end) {

             (*call) ();

             call++;

      }

}

 

在系统中,security_initcall.init的函数总共有三个,分别为:capability_init(), rootplug_init()selinux_init()。其中,selinux只能第一个注册(即作为security_ops上的第一个过滤层),否则注册会失败。selinux注册后,original_ops=secondary_ops=dummy_ops; securuty_ops=selinux_ops。前两者的注册方式完全一致,并且,在当前代码实现中,两者只能注册一个,另外一个在第一个注册成功后,即使以模块方式加载也会失败。例如,capability_init()注册后,secondary_ops=capability_ops; original_ops=dummy_ops; security_ops=selinux_ops。此时如果再调用rootplug_init(),将因为security_ops!=dummy_security_ops而调用register_security失败,然后因为secondary_ops != original_ops而在调用security_ops->register_securityselinux_register_security函数中返回出错,原因为几经存在了一个第二层模块。

 

具体代码不在这里列出,有兴趣者可以到src/security/目录下分别查看capability.c, root_plug.cselinux/hooks.c

 

因此可见,主要得代码实现都是在selinux中实现的。以我所感兴趣的selinux_mountselinux_umount为例,其代码如下:

 

static int selinux_mount(char * dev_name,

                        struct nameidata *nd,

                        char * type,

                        unsigned long flags,

                        void * data)

{

      int rc;

 

      rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data);

      if (rc)

             return rc;

 

      if (flags & MS_REMOUNT)

             return superblock_has_perm(current, nd->mnt->mnt_sb,

                                       FILESYSTEM__REMOUNT, NULL);

      else

             return dentry_has_perm(current, nd->mnt, nd->dentry,

                                   FILE__MOUNTON);

}

 

static int selinux_umount(struct vfsmount *mnt, int flags)

{

      int rc;

 

      rc = secondary_ops->sb_umount(mnt, flags);

      if (rc)

             return rc;

 

      return superblock_has_perm(current,mnt->mnt_sb,

                                FILESYSTEM__UNMOUNT,NULL);

}

 

由上面的ops赋值关系可知,secondary_ops->sb_mountsecondary_ops->sb_umount无论capabilityroot_plug是否加载,因为其在这两者中都没有定义实现,所以,为dummy_XXX函数,相关的代码如下:

 

static int dummy_sb_mount (char *dev_name, struct nameidata *nd, char *type,

                      unsigned long flags, void *data)

{

      return 0;

}

 

static int dummy_sb_check_sb (struct vfsmount *mnt, struct nameidata *nd)

{

      return 0;

}

 

static int dummy_sb_umount (struct vfsmount *mnt, int flags)

{

      return 0;

}

 

static void dummy_sb_umount_close (struct vfsmount *mnt)

{

      return;

}

 

static void dummy_sb_umount_busy (struct vfsmount *mnt)

{

      return;

}

 

static void dummy_sb_post_remount (struct vfsmount *mnt, unsigned long flags,

                             void *data)

{

      return;

}

 

 

static void dummy_sb_post_mountroot (void)

{

      return;

}

 

然后给出一定的pemmision的判断。permmision判断通过查找avchash表实现,它是以数据库的形式在内核维护的。在selinux中,ss目录下的文件负责维护security所有安全检查需要的数据库,对于数据库的详细操作和保存和加载,请参考src/security/selinux/ss/policydb.c中的相关函数。

 

相关文章推荐

linux的lsm--简单高效并且周到(机制和策略)

lsm是linux可加载的安全模块,它非常简单,这个机制又一次体现了linux内核的高度可定制特性,它的效率很高,不会带来很大的开销,这一切归功于内核考虑的周到以及内核架构的高级 如果你了解lin...
  • dog250
  • dog250
  • 2010-02-09 22:19
  • 4107

Linux 内核安全模块学习总结

Linux安全模块(LSM) LSM是Linux Secrity Module的简称,即linux安全模块。其是一种轻量级通用访 问控制框架,适合于多种访问控制模型在它上面以内核可加载模块的形实现...

linux中设置CUPS打印机

这两天花了些时间研究了一下cups的打印设置,发现网上的资料说得不清不楚,于是决定把我的设置记录下来供大家将来参考。 我的LINUX是 redhat enterprise 3 在这篇文章中,假设C...

SELinux架构和Flask安全体系结构的一些认识

首先,总的说来:整个安全性体系结构称为Flask,在 Flask 体系结构中,安全性策略的逻辑和通用接口一起封装在与操作系统独立的组件中,通用接口是用于获得安全性策略决策的。这个单独的组件称为安全性服...

linux中动态库的编译和加载的查找顺序

Glibc安装的库中有一个名为ld-Linux.so.X其中X为一个数字(版本), 在不同的平台上可以通过ldd查看 $ldd /bin/cat linux-vdso.so.1 =>  (0x0...

linux动态链接库的加载顺序:

linux动态链接库的加载顺序: 它有5个地方会查找, 1. 编译时指定的run path 2. LD_LIBRARY_PATH 指定的地方 3. ldconfig 指定的地方 4. /lib 5. ...

Linux内核驱动加载顺序 3

【问题】 背光驱动初始化先于LCD驱动初始化,导致LCD驱动初始化时出现闪屏的现象。 【解决过程】 1 mach-xxx.c中platform devices列表如下 /* platform ...

Linux驱动加载顺序

Linux内核为不同驱动的加载顺序对应不同的优先级,定义了一些宏: include\linux\init.h #define pure_initcall(fn)   __define_initca...

Linux 设备和驱动加载的先后顺序 2

Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢。 Linux系统使用两种方式去加载系统中的模块:动态和静态。 静态加载:将所有模块的程序...

linux设备和驱动加载的先后顺序

Linux驱动先注册总线,总线上可以先挂device,也可以先挂driver,那么究竟怎么控制先后的顺序呢。 Linux系统使用两种方式去加载系统中的模块:动态和静态。 静态加载:将所有模块的程序...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)