1. 程式人生 > >linux安全模組學習之LSM的介紹實現

linux安全模組學習之LSM的介紹實現

相關背景介紹

近年來Linux系統由於其出色的效能和穩定性,開放原始碼特性帶來的靈活性和可擴充套件性,以及較低廉的成本,而受到計算機工業界的廣泛關注和應用。

但在安全性方面,Linux核心只提供了經典的UNIX自主訪問控制(root使用者,使用者ID,模式位安全機制),以及部分的支援了POSIX.1e標準草案中的capabilities安全機制,這對於Linux系統的安全性是不足夠的,影響了Linux系統的進一步發展和更廣泛的應用。

Linux安全模組(LSM)是Linux核心的一個輕量級通用訪問控制框架。它使得各種不同的安全訪問控制模型能夠以Linux可載入核心模組的形式實現出來,使用者可以根據其需求選擇適合的安全模組載入到Linux核心中,從而大大提高了Linux安全訪問控制機制的靈活性和易用性。

Linux安全模組(LSM)的設計必須儘量滿足兩方面人的要求:讓不需要它的人儘可能少的因此得到麻煩;同時讓需要它的人因此得到有用和高效的功能。

以Linus Torvalds為代表的核心開發人員對Linux安全模組(LSM)提出了三點要求:


• 真正的通用,當使用一個不同的安全模型的時候,只需要載入一個不同的核心模組
• 概念上簡單,對Linux核心影響最小,高效,
• 能夠支援現存的POSIX.1e capabilities邏輯,作為一個可選的安全模組

另一方面,各種不同的Linux安全增強系統對Linux安全模組(LSM)提出的要求是:能夠允許他們以可載入核心模組的形式重新實現其安全功能,並且不會在安全性方面帶來明顯的損失,也不會帶來額外的系統開銷。

為了滿足這些設計目標,Linux安全模組(LSM)採用了通過在核心原始碼中放置鉤子的方法,來仲裁對核心內部物件進行的訪問,這些物件有:任務,inode結點,開啟的檔案等等。

使用者程序執行系統呼叫,首先遊歷Linux核心原有的邏輯找到並分配資源,進行錯誤檢查,並經過經典的UNIX自主訪問控制,恰好就在Linux核心試圖對內部物件進行訪問之前,一個Linux安全模組(LSM)的鉤子對安全模組所必須提供的函式進行一個呼叫,從而對安全模組提出這樣的問題”是否允許訪問執行?”,安全模組根據其安全策略進行決策,作出回答:允許,或者拒絕進而返回一個錯誤。

Linux安全模組(LSM)現在主要支援”限制型”的訪問控制決策:當Linux核心給予訪問許可權時,Linux安全模組(LSM)可能會拒絕,而當Linux核心拒絕訪問時,就直接跳過Linux安全模組(LSM);而對於相反的”允許型”的訪問控制決策只提供了少量的支援。

對於模組功能合成,Linux安全模組(LSM)允許模組堆疊,但是把主要的工作留給了模組自身:由第一個載入的模組進行模組功能合成的最終決策。

實現方法介紹:對Linux核心的修改

Linux安全模組(LSM)目前作為一個Linux核心補丁的形式實現。其本身不提供任何具體的安全策略,而是提供了一個通用的基礎體系給安全模組,由安全模組來實現具體的安全策略。其主要在五個方面對Linux核心進行了修改: 

• 在特定的核心資料結構中加入了安全域
• 在核心原始碼中不同的關鍵點插入了對安全鉤子函式的呼叫
• 加入了一個通用的安全系統呼叫
• 提供了函式允許核心模組註冊為安全模組或者登出
• 將capabilities邏輯的大部分移植為一個可選的安全模組

對這五個方面的修改的簡要介紹

安全域是一個void*型別的指標,它使得安全模組把安全資訊和核心內部物件聯絡起來。下面列出被修改加入了安全域的核心資料結構,以及各自所代表的核心內部物件:

• task_struct結構:代表任務(程序)
• linux_binprm結構:代表程式
• super_block結構:代表檔案系統
• inode結構:代表管道,檔案,或者Socket套接字
• file結構:代表開啟的檔案
• sk_buff結構:代表網路緩衝區(包)
• net_device結構:代表網路裝置
• kern_ipc_perm結構:代表Semaphore訊號,共享記憶體段,或者訊息佇列
• msg_msg:代表單個的訊息

   另外,msg_msg結構,msg_queue結構,shmid_kernel結構被移到include/linux/msg.h和include/linux/shm.h這兩個標頭檔案中,使得安全模組可以使用這些定義。

Linux安全模組(LSM)提供了兩類對安全鉤子函式的呼叫:一類管理核心物件的安全域,另一類仲裁對這些核心物件的訪問。

對安全鉤子函式的呼叫通過鉤子來實現,鉤子是全域性表security_ops中的函式指標,這個全域性表的型別是security_operations結構,這個結構定義在include/linux/security.h這個標頭檔案中。

這個結構中包含了按照核心物件或核心子系統分組的鉤子組成的子結構,以及一些用於系統操作的頂層鉤子。在核心原始碼中很容易找到對鉤子函式的呼叫:其字首是security_ops->。

Linux安全模組(LSM)提供了一個通用的安全系統呼叫,允許安全模組為安全相關的應用編寫新的系統呼叫,其風格類似於原有的Linux系統呼叫socketcall(),是一個多路的系統呼叫。

這個系統呼叫為security(),其引數為(unsigned int id, unsigned int call, unsigned long *args),其中id代表模組描述符,call代表呼叫描述符,args代表引數列表。

這個系統呼叫提供了一個sys_security()入口函式:其簡單的以引數呼叫sys_security()鉤子函式。

如果安全模組不提供新的系統呼叫,就可以定義返回-ENOSYS的sys_security()鉤子函式,但是大多數安全模組都可以自己定義這個系統呼叫的實現。

在核心引導的過程中,Linux安全模組(LSM)框架被初始化為一系列的虛擬鉤子函式,以實現傳統的UNIX超級使用者機制。

當載入一個安全模組時,必須使用register_security()函式向Linux安全模組(LSM)框架註冊這個安全模組:這個函式將設定全域性表security_ops,使其指向這個安全模組的鉤子函式指標,從而使核心向這個安全模組詢問訪問控制決策。

一旦一個安全模組被載入,就成為系統的安全策略決策中心,而不會被後面的register_security()函式覆蓋,直到這個安全模組被使用unregister_security()函式向框架登出:這簡單的將鉤子函式替換為預設值,系統回到UNIX超級使用者機制。

另外,Linux安全模組(LSM)框架還提供了函式mod_reg_security()和函式mod_unreg_security(),使其後的安全模組可以向已經第一個註冊的主模組註冊和登出,但其策略實現由主模組決定:是提供某種策略來實現模組堆疊從而支援模組功能合成,還是簡單的返回錯誤值以忽略其後的安全模組。這些函式都提供在核心原始碼檔案security/security.c中。

Linux核心現在對POSIX.1e capabilities的一個子集提供支援Linux安全模組(LSM)設計的一個需求就是把這個功能移植為一個可選的安全模組。POSIX.1e capabilities提供了劃分傳統超級使用者特權並賦給特定的程序的功能。

Linux安全模組(LSM)保留了用來在核心中執行capability檢查的現存的capable()介面,但把capable()函式簡化為一個Linux安全模組(LSM)鉤子函式的包裝,從而允許在安全模組中實現任何需要的邏輯。

Linux安全模組(LSM)還保留了task_struck結構中的程序capability集(一個簡單的位向量),而並沒有把它移到安全域中去。Linux核心對capabilities的支援還包括兩個系統呼叫:capset()和capget()。

Linux安全模組(LSM)同樣保留了這些系統呼叫但將其替換為對鉤子函式的呼叫,使其基本上可以通過security()系統呼叫來重新實現。

Linux安全模組(LSM)已經開發並且移植了相當部分的capabilities邏輯到一個capabilities安全模組中,但核心中仍然保留了很多原有capabilities的殘餘。

這些實現方法都最大程度的減少了對Linux核心的修改影響,並且最大程度保留了對原有使用capabilities的應用程式的支援,同時滿足了設計的功能需求。

以後要使capabilities模組完全獨立,剩下要做的主要步驟是:把位向量移到task_struct結構中合適的安全域中,以及重新定位系統呼叫介面。