转自:http://blog.csdn.net/lixuyuan/article/details/6217502

现在关于内核的书很少涉及到Linux内核的安全,内核安全大概包括了密码学实现(crypto)和访问控制(security)两个部分。安全系 统作为Linux内核的一个重要的子系统,已经为我们提供了很多的相关接口,这里我们就对安全访问控制做一个简要的分析和介绍。 
       访问控制的原理注定要和虚拟文件系统和进程管理有着非常紧密的联系,因为作为用户主体的表现形式就是进程,而作为资源客体对象的表现形式就是文件,而访问 控制就是如何实现正确的用户可以访问正确的资源。Linux能够提供给我们许多可信的方式来处理这样的问题。

初始化工作

这个初始化工作在init/main.c中的start_kernel()中security_init()定义了,其具体的实现是在security/security.c中:

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;
}

这个函数首先用verify来验证所指定的访问控制策略(dummy_security_ops)是否为空,如果为空就按“保持默认”的方式进行分 配,这里的“保持沉默”就是对于任何的访问控制采取不管不问的方式处理了。然后就是把dummy_security_ops指定给系统全局安全策略 security_ops。

访问控制策略的相关接口

关于这些接口就是定义在了include/linux/security.h中的security_operations,包括如下一些操作:当父 进程trace子进程时进行的权限检查,对权能的获取、设置检查、设置、有效性检查,对进程做审计的检查,当某个操作使用一般系统接口表时需要的权限检 查,当使用内核消息环或改变登录终端时需要的权限检查,当改变系统时间需要的检查,当分配一个新的虚拟内存页需要的权限检查,当执行二进制程序时需要的各 种权限分配和检查,对文件系统操作时需要的各种访问控制操作,对inode索引节点操作时需要的各种访问控制操作,对文件操作时的各种访问控制操作,对进 程操作的需要的各种访问控制操作,对进程间通信信号灯的权限控制,对消息队列的控制,对进程间通信的共享内存区域的控制,对网络消息处理需要的各种控制, 注册与撤销访问控制策略,对网络连接的控制,对套接字的各种控制,对IPSEC中xfrm用户自定义策略的分配,密钥管理的控制等等,几乎囊括了系统各种 行为的控制。

权限管理

虚拟文件系统为各种类型的文件系统提供统一的操作接口,同时这样的做法也可以简化文件权限的管理。那么Linux时如何巧妙地实现这种想法呢?Linux 采用的是基于列的ACL自主访问控制,即在每个文件里存储对本文件的访问权限信息,这里我们采用索引节点inode(定义在 include/linux/fs.h)作为切入点进行分析。在inode结构体中有i_uid和i_gid元素,还有一个i_mode元素。这个 i_mode是16位的无符号整数表示,由9位权限方式位、3位“粘滞”标志位和4位文件类型标志位,它们的具体的定义在 include/linux/stat.h中:

#define S_IFMT   00170000     /* 用于抽取i_mode域中类型部分的屏蔽位 */
#define S_IFSOCK 0140000     /* 套接字类型码 */
#define S_IFLNK    0120000    /* 符号连接类型码 */
#define S_IFREG   0100000    /* 普通文件类型码 */
#define S_IFBLK   0060000    /* 块特别文件类型码 */
#define S_IFDIR   0040000     /* 目录文件类型码 */
#define S_IFCHR   0020000    /* 字符特别文件类型码 */
#define S_IFIFO   0010000     /* 管道或FIFO类型码 */
#define S_ISUID   0004000    /* 用户粘滞位 */
#define S_ISGID   0002000    /* 用户组粘滞位 */
#define S_ISVTX   0001000   /* 粘滞位 */
#define S_IRWXU 00700     /* 用户读写执行 */
#define S_IRUSR 00400      /* 用户读 */
#define S_IWUSR 00200     /* 用户写 */
#define S_IXUSR 00100     /* 用户执行 */
#define S_IRWXG 00070    /* 用户组读写执行 */
#define S_IRGRP 00040    /* 用户组读 */
#define S_IWGRP 00020    /* 用户组写 */
#define S_IXGRP 00010    /* 用户组执行 */
#define S_IRWXO 00007   /* 其他用户读写执行 */
#define S_IROTH 00004    /* 其他用户读 */
#define S_IWOTH 00002   /* 其他用户写 */
#define S_IXOTH 00001   /* 其他用户执行 */
#define S_IRWXUGO     (S_IRWXU|S_IRWXG|S_IRWXO)   /* 全部用户读写执行 */
#define S_IALLUGO      (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO )/* 全部用户全部权限 */
#define S_IRUGO          (S_IRUSR|S_IRGRP|S_IROTH)    /* 全部用户读 */
#define S_IWUGO         (S_IWUSR|S_IWGRP|S_IWOTH)   /* 全部用户写 */
#define S_IXUGO          (S_IXUSR|S_IXGRP|S_IXOTH)    /* 全部用户执行 */

同时,每个进程的task_struct中也有对应的uid,euid,suid,fsuid, gid,egid,sgid,fsgid等元素,当用户登录系统就创建了一个shell进程,它从/etc/passwd中取得对应用户的uid和gid 来唯一标志这个用户,以后所有的进程就代代相传。当内核在执行用户进程访问文件的请求时就要对比进程的uid、gid与文件的访问模式位,由此决定该进程 是否有对文件的操作权限。uid为零的用户为超级用户,可以对任何资源进行管理,当然这也导致了系统安全的不完备性。

判定一个进程是否有对某个文件有某种访问的主要工作是由fs/namei.c中的permission函数决定的,具体的实现方式如下,其中的mask参数是所要求的访问方式位的标志位:

int permission(struct inode *inode, int mask, struct nameidata *nd)
{
        umode_t mode = inode->i_mode;
        int retval, submask;
        if (mask & MAY_WRITE) {
               //假如加载的文件系统是只读的就不允许写,比如是磁盘设备
               if (IS_RDONLY(inode) &&
                   (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
                      return -EROFS;
               //假如加载的文件系统是不可变的就不允许写
               if (IS_IMMUTABLE(inode))
                      return -EACCES;
        }
        //是否满足可执行
        if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) ||
                      (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC))))
               return -EACCES;
        submask = mask & ~MAY_APPEND;
        //返回适应的权限位
        if (inode->i_op && inode->i_op->permission)
               //交给了具体文件系统实现,比如说ext3文件系统
               retval = inode->i_op->permission(inode, submask, nd);
        else
               //如果当前进程的fsuid与文件uid相同要比对文件属主的权限,否则比对用户组
               retval = generic_permission(inode, submask, NULL);
        if (retval)
               return retval;
        //返回适应的访问控制策略的权限位,比如说selinux
        return security_inode_permission(inode, mask, nd);
}

转载自:http://blog.csdn.net/nhczp/archive/2008/04/29/2341194.aspx

Linux操作系统的权限代码分析【转】的更多相关文章

  1. Linux内核启动代码分析二之开发板相关驱动程序加载分析

    Linux内核启动代码分析二之开发板相关驱动程序加载分析 1 从linux开始启动的函数start_kernel开始分析,该函数位于linux-2.6.22/init/main.c  start_ke ...

  2. Linux中断 - GIC代码分析

    一.前言 GIC(Generic Interrupt Controller)是ARM公司提供的一个通用的中断控制器,其architecture specification目前有四个版本,V1-V4(V ...

  3. Linux进程切换代码分析

    朱宇轲 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这次我们来分析L ...

  4. linux系统调用实现代码分析【转】

    转自:http://linux.chinaunix.net/doc/kernel/2001-07-30/637.shtml 启动早就读完,现在为了写笔记再从启动之后粗略的大体读一遍,基本就是几个大模块 ...

  5. Linux 操作系统的权限为什么是1,2,4 而不是 1,2,3?如何用二进制来做权限管理

    1.二进制做权限的优点 大家都知道,在Linux操作系统中,x - 可执行权限,w - 可写权限 , r - 可读权限.其权限值分别是1,2,4,但是有没有想过为什么是1,2,4 而不是 1,2,3 ...

  6. linux操作系统的目录以及用户权权限的管理

    linux操作系统的目录以及对目录的操作 一: linux操作系统的目录结构   bin #可执行程序的安装目录 , 命令 boot #系统启动引导目录 dev #设备目录 etc #软件配置文件目录 ...

  7. 《linux 内核全然剖析》sched.c sched.h 代码分析笔记

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u011368821/article/details/25129835 sched.c sched.h ...

  8. ARM Linux启动代码分析

    前言 在学习.分析之前首先要弄明白一个问题:为什么要分析启动代码? 因为启动代码绝大部分都是用汇编语言写的,对于没学过或者不熟悉汇编语言的同学确实有一定难度,但是如果你想真正深入地学习Linux,那么 ...

  9. Linux内核中的GPIO系统之(3):pin controller driver代码分析

    一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...

随机推荐

  1. 机器学习实战 -- 决策树(ID3)

    机器学习实战 -- 决策树(ID3)   ID3是什么我也不知道,不急,知道他是干什么的就行   ID3是最经典最基础的一种决策树算法,他会将每一个特征都设为决策节点,有时候,一个数据集中,某些特征属 ...

  2. 9.2python操作redis

    Redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...

  3. [bzoj1552][Cerc2007]robotic sort&&[bzoj3506][Cqoi2014]排序机械臂

    非常垃圾的一道平衡树,结果被日了一天.很难受嗷嗷嗷 首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受——并不好理解. 还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法. 题 ...

  4. JSP---JSTL核心标签库的使用

    JSTL 核心标签库标签共有13个,功能上分为4类: 1.表达式控制标签:out.set.remove.catch 2.流程控制标签:if.choose.when.otherwise 3.循环标签:f ...

  5. 2599: [IOI2011]Race

    2599: [IOI2011]Race 链接 分析 被memset卡... 点分治,对于重心,遍历子树,记录一个数组T[i],表示以重心为起点的长度为i的路径中最少的边数是多少.然后先遍历子树,更新答 ...

  6. Android stadio Switch repository Android stadio切换仓库

    Android stadio 有时候,有很多module. 这些module 都有自己的仓库.也就是不在一块.那么,Android stadio 默认管理的就是根git. 如图,画对号的就是默认的. ...

  7. 腾讯课堂之前端开发html5css3javascriptjQueryJS年薪20万

    第一章 网页制作零基础 第一节 什么是HTML 第二节 HTML基本语法 第三节 HTML结构标签 第四节 HTML常用标签及属性 第五节 HTML无序列表UL标签 第六节 HTML定义列表DL标签 ...

  8. split array

    public boolean splitArray(int[] nums) { return dividSameSumGroup(0,nums, 0,0); } public boolean divi ...

  9. Spring进阶—如何用Java代码实现邮件发送(一)

    相关文章: <Spring进阶—如何用Java代码实现邮件发送(二)> 在一些项目里面如进销存系统,对一些库存不足发出预警提示消息,招聘网站注册用户验证email地址等都需要用到邮件发送技 ...

  10. 自动化测试(三)如何用python写一个函数,这个函数的功能是,传入一个数字,产生N条邮箱,产生的邮箱不能重复。

    写一个函数,这个函数的功能是,传入一个数字,产生N条邮箱,产生的邮箱不能重复.邮箱前面的长度是6-12之间,产生的邮箱必须包含大写字母.小写字母.数字和特殊字符 和上一期一样 代码中间有段比较混沌 有 ...