Linux操作系统的权限代码分析【转】

转自: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

时间: 2024-09-24 07:50:16

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

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

转自:http://linux.chinaunix.net/doc/kernel/2001-07-30/637.shtml 启动早就读完,现在为了写笔记再从启动之后粗略的大体读一遍,基本就是几个大模块:启动和初始化,中断信号, 进程及调度,内存管理,文件系统,网络,驱动和模块等,我主要也从这几块入手.由于启动部分在start_kernel之 前牵涉到大量的x86体系相关的汇编知识,需要大量的时间,于是我跳过,先把握整个系统的大体脉络,然后做二次, 三次分析.网络部分的分析,我会从4.4BSD-L

红星Linux操作系统的大部分代码处于被管控的状态

红星(Red Star)操作系统是一款基于 Fedora 的 Linux 衍生版本,其实现了该国前领导人的"国产操作系统"之梦,也表明了该国拥抱互联网的一种态度.据外媒报道,德国安全公司 ERNW 在探索这款操作系统后发现,其在加密代码等诸多方面都有控制.研究人员 Florian Grunow 和 Niklaus Schiess 在接受路透社采访时表示: "因担心西方国家的影响和间谍活动,其并没有像大多数人所知的那样去拥抱互联网,而是提供官方认可的网站的基础访问".

浅谈对Linux系统内核源代码的分析

Linux的最大的好处之一就是它的源码公开.同时,公开的核心源码也吸引着无数的电脑爱好者和程序员:他们把解读和分析Linux的核心源码作为自己的最大兴趣,把修改Linux源码和改造Linux系统作为自己对计算机技术追求的最大目标. Linux内核源码是很具吸引力的,特别是当你弄懂了一个分析了好久都没搞懂的问题:或者是被你修改过了的内核,顺利通过编译,一切运行正常的时候.那种成就感真是油然而生!而且,对内核的分析,除了出自对技术的狂热追求之外,这种令人生畏的劳动所带来的回报也是非常令人着迷的,这也

php中mkdir()函数的权限问题分析_php技巧

问题描述: 使用以下php代码创建了一个目录,期望目录的权限是0777,实际结果是0755 mkdir('./aa/',0777); 分析与测试结果: 1.mkdir()函数指定的目录权限只能小于等于系统umask设定的默认权限.如linux默认的umask一般0022, 即创建目录的默认权限是0755, 所以这时php mkdir('./aa/',0777) 得到目录的权限是0755. xw@xw-X201:~/Desktop/dd/aa$ umask 0022 xw@xw-X201:~/De

insmod模块加载过程代码分析1【转】

转自:http://blog.chinaunix.net/uid-27717694-id-3966290.html 一.概述模块是作为ELF对象文件存放在文件系统中的,并通过执行insmod程序链接到内核中.对于每个模块,系统都要分配一个包含以下数据结构的内存区.一个module对象,表示模块名的一个以null结束的字符串,实现模块功能的代码.在2.6内核以前,insmod模块过程主要是通过modutils中的insmod加载,大量工作都是在用户空间完成.但在2.6内核以后,系统使用busybo

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja  转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html     前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并

C++反汇编代码分析–函数调用

转载:http://shitouer.cn/2010/06/method-called/ 代码如下:#include "stdlib.h" int sum(int a,int b,int m,int n){ return a+b; } void main(){ int result = sum(1,2,3,4); system("pause"); } 有四个参数的sum函数,接着在main方法中调用sum函数.在debug环境下,单步调试如下: 11:   void

微软发布2万行Linux设备驱动程序代码

[新浪科技讯]7月21日凌晨消息,微软公司宣布首次直接面向Linux社区发布2万行Linux设备驱动程序代码,以增加其在虚拟化市场的竞争力. 首次发布2万行Linux驱动代码 北京时间7月21日凌晨,微软公司对外宣布,面向Linux内核社区发布2万行的设备驱动程序代码.这是微软首次直接面向Linux社区发布Linux设备驱动程序代码.这些代码的许可证类型是GPLV2(GNU通用公共授权第二版),这是目前Linux社区最受欢迎的许可方式. 微软发布的2万行设备驱动程序代码可供Linux社区和客户使

如何提高Linux操作系统的安全性

Linux系统不论在功能上.价格上或性能上都有很多优点,但作为开放式操作系统,它不可避免地存在一些安全隐患.关于如何解决这些隐患,为应用提供一个安全的操作平台,本文会告诉你一些最基本.最常用,同时也是最有效的招数,如果是企业用户,这些安全策略应该制定为公司内部的规范,并要求系统管理员或运维人员对其进行有效监控. Linux是一种类Unix的操作系统.从理论上讲,Unix本身的设计并没有什么重大的安全缺陷.多年来,绝大多数在Unix操作系统上发现的安全问题主要存在于个别程序中,所以大部分Unix厂