將要加入linux-2.6.29核心的cred

科技小能手發表於2017-11-12

2.6.29核心我認為最重要的就是規整了核心結構,規整了程式碼結構,使得核心看起來更加自然,更加清晰,正如第二代rcu做到的那樣,原先核心中的很多機制在2.6.29核心中都得到了規整,可以說得到了屬於自己的實現,而不必再依賴核心中其它機制的實現,其中我認為最吸引我的就是cred的實現,在簡述什麼是cred之前先看一下cred這個機制背後的思想,就是“使得主體和客體分離”。

     這個思想是很自然的,主體和客體分離總是一件好事,這樣可以不至於使事情變得不可控制,但是在設計一個系統的時候,我們往往不能一開始就做到這一點,必然經過一次次地篩選過濾之後,才可以將留下來的東西重新組合,最終做到主體和客體分離,就好比我們蓋一座房子,必然的一開始我們不能將房子一塊一塊的運過來只要組合就行,而是必須運過來水泥,沙子,鋼筋,然後融入設計師的思想,這樣房子才可以成型。在linux核心的演變中,如果說一個機制引入了核心,那麼在實現該機制的最開始的幾個版本中,該機制的角色就是水泥,沙子,鋼筋,到了後面的版本,這些機制才得以脫俗,成為linux核心中的藝術,linux核心就是這麼發展起來的,到如今,裡面的很多機制都是藝術。

     我們都知道,linux中程式的重要性,幾乎所有的任務都要給它一個程式上下文,即使現在還沒有給,linux核心的設計者也有這樣的想法,既然程式如此重要,那麼就有必要給它一些限制欄位用來進行一些安全上的限制,畢竟你可以讓程式做好事也可以讓程式做壞事。其實多工,多使用者都是用程式實現的。linux自原始以來就繼承了unix的良好基因,在程式控制結構即task_struct中就擁有了uidgid等資訊用來區分使用者和組從而實現基本的安全控制,進一步,uidgid機制加上unix/linuxfork/exec機制一起實現了真正的多使用者/多工機制,咋看起來,uidgid等理應是一個程式的屬性,理應在task_struct裡面存在,可是我們能否將之向更高的高度抽象一下呢?想象一下我們為何可以用uidgid等實現多使用者,多使用者最基本的是什麼?這些問題可以歸結為安全,信任,所謂的多使用者最基本的就是信任問題,因此完全可以為uidgid,以及諸多安全信任相關欄位設定一個新的獨立的結構,這個結構就是struct cred,這樣看來task_struct就更加規整了,抽象程度更高了,而不像以前那樣所有東西都往裡面堆積了。前面是從設計上來說的,那麼這麼做是否必要呢?有這方面的需求嗎?值得注意的是,如果沒有需求,linux核心很難僅僅從設計上進行更改,這就是linux核心的風格。

     在新核心中,將要加入的一個新機制就是cachefs,這很顯然是個和快取相關聯的檔案系統,其實它的出現是為了平衡各種底層檔案系統的速率的差異,眾所周知,nfs的資料來自遠端,另外一臺機器上可以並存告訴磁碟和低速磁帶,這些底層檔案系統的差異要求核心提供一個適配層來平衡這些差異,當然這個適配層是可選的,如果你不嫌一些檔案系統慢,那麼完全可以不用,這裡的平衡僅僅針對慢速檔案系統快取資料,而不會將本來就很快的檔案系統的速率降低,它實際上就是在快速磁碟上劃分一塊區域,這塊區域專門用來快取慢速檔案系統的資料,這樣的話如需讀寫慢速檔案系統的資料就直接可以操作快取檔案系統了,然後的同步操作就是核心機制的事情了,其實就是快取檔案系統的事情,到了這一步就沒有使用者空間程式的什麼事情了,注意快取檔案系統和核心中的address_space實現的頁快取記憶體是兩碼事,它們根本就不是一個層次的,快取檔案系統是頁快取記憶體的下層,它們其實沒有交集。現在看看實際情況,cachefs的管理很複雜,牽扯到許多使用者的策略,於是在使用者空間就要有一個守護程式來實現cachefs的管理,畢竟涉及策略的問題還是讓使用者空間來實現吧,既然使用者守護程式實現了管理,cachefs中快取的檔案就是由這個守護程式來建立,刪除,修改了,那麼該cachefs中的檔案的uidgid以及安全欄位就是這個守護程式的了,但是這些檔案雖然由守護程式建立卻不是讓守護程式訪問,而是讓所有和慢速檔案系統互動的程式來訪問用以提高速度的,於是問出來了,普通程式可以訪問cachefs中的檔案嗎?畢竟它們的uidgid,訪問令牌不同啊,不是一個程式的,那該怎麼辦?於是將程式的安全元素抽象出來的需求被提了出來,這樣的話就可以做到隨時更新替換安全元素了而不用為了訪問一個檔案在task_struct中更改那麼多東西了,這樣的話,如果普通程式訪問了cachefs的中快取的檔案,那麼就把該程式的安全信用元素替換成負責cachefs管理的守護程式的安全信任元素以獲得cachefs中檔案的訪問權,完事之後再替換過來,這是不是很簡潔的解決了這個問題啊?現在看一下核心補丁的實現,其中這個補丁中最重要的就是get_kernel_cred了:

struct cred *get_kernel_cred(const char *service, struct task_struct *daemon)

{

       struct cred *cred, *dcred;

       int ret;

       cred = kzalloc(sizeof *cred, GFP_KERNEL);

       if (!cred)

              return ERR_PTR(-ENOMEM);

       if (daemon) {

              rcu_read_lock();

              dcred = task_cred(daemon);

              cred->uid = dcred->uid;

              cred->gid = dcred->gid;

              cred->group_info = dcred->group_info;

              atomic_inc(&cred->group_info->usage);

              rcu_read_unlock();

       } else {

              cred->group_info = &init_groups;

              atomic_inc(&init_groups.usage);

       }

       ret = security_cred_kernel_act_as(cred, service, daemon);

       if (ret < 0) {

              put_cred(cred);

              return ERR_PTR(ret);

       }

       return cred;

}

引數daemon代表一個程式,在任何一個程式上下文中呼叫這個函式,將需要擁有需要的安全信任元素的程式作為daemon傳入函式,得到的就是包含該daemon安全信任元素的一個新結構,把這個結構設定進呼叫上下文的程式的task_struct,則呼叫上下文的程式就擁有了daemon的安全信任元素,就可以做一部分只有daemon才可以做的事情了,其實此時可以認為是呼叫上下文在代表daemon做事,結合上面提到的cachefs的例子,不是說任意程式可能無法都獲得cachefs的檔案的訪問權嗎,那麼在cachefs的核心程式碼中呼叫上述的get_kernel_cred和另外的一個函式set_current_cred,這樣的話事情就成了。最後值得注意的就是,新核心的cred結構體其實就是將原先task_struct中的一些涉及安全和信任的欄位包裝成了一個結構,該結構可以動態的設定和替換,在程式碼細節上運用到了RCU鎖,其實這個新機制的本質就是利用了RCU,這個的原因就是為了防止過多的競爭,新核心規定,cred中的欄位在cred沒有脫離task_struct的時候不能改變,也就是說如果你想改變當前程式的cred中的欄位,你就必須先將它搞一個副本下來,然後只能改副本,最後再把副本放上去,這就是RCU的機制,就不多說了。

     早在去年我就聽說了windows vista可以實現動態的能力賦予,也就是說不必為了刪除一個重要檔案而獲得整個管理員的許可權,而是隻獲得刪除這個檔案的許可權就可以了,開始的時候我對這個機制十分感興趣,心想linux為何就不能呢,實際上linux完全可以做到,你可以用兩種方式實現,第一就是使用者空間的方式,這個涉及到安全配置管理,另一個就是核心的方式,這個涉及到linuxLSM機制,在最新的2.6.29核心上,cred機制可以更加簡單的實現這一點,因為作為一個整體struct cred中可以只更改某些欄位而不必觸及所有,當然實現這個需要LSM的幫忙,總之,linux就是十分靈活,十分棒。

人長得醜了真的很好

我老婆總說我長得醜,不過我承認,我不在乎我長得怎樣,那實在沒有意思,老婆有的時候也說我長得帥,不過我同樣不在乎,但是那天在火車站有個小女孩在要錢,伸出手給每個人要,快到我這裡的時候我很慌,因為我脾氣不好我怕跟人家小女孩急了不好,可是我萬萬沒有想到的是,那個小女孩到我這裡的時候竟然隔過去了,這個事情證明我長得確實很醜,把人家嚇住了。


 本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1274304



相關文章