Linux作業系統的許可權程式碼分析【轉】

桃子紅了吶發表於2017-11-15

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


本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sky-heaven/p/5599674.html,如需轉載請自行聯絡原作者


相關文章