天天看點

将要加入linux-2.6.29核心的cred

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

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

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

     在新核心中,将要加入的一個新機制就是cachefs,這很顯然是個和緩存相關聯的檔案系統,其實它的出現是為了平衡各種底層檔案系統的速率的差異,衆所周知,nfs的資料來自遠端,另外一台機器上可以并存告訴磁盤和低速錄音帶,這些底層檔案系統的差異要求核心提供一個适配層來平衡這些差異,當然這個适配層是可選的,如果你不嫌一些檔案系統慢,那麼完全可以不用,這裡的平衡僅僅針對慢速檔案系統緩存資料,而不會将本來就很快的檔案系統的速率降低,它實際上就是在快速磁盤上劃分一塊區域,這塊區域專門用來緩存慢速檔案系統的資料,這樣的話如需讀寫慢速檔案系統的資料就直接可以操作緩存檔案系統了,然後的同步操作就是核心機制的事情了,其實就是緩存檔案系統的事情,到了這一步就沒有使用者空間程序的什麼事情了,注意緩存檔案系統和核心中的address_space實作的頁高速緩存是兩碼事,它們根本就不是一個層次的,緩存檔案系統是頁高速緩存的下層,它們其實沒有交集。現在看看實際情況,cachefs的管理很複雜,牽扯到許多使用者的政策,于是在使用者空間就要有一個守護程序來實作cachefs的管理,畢竟涉及政策的問題還是讓使用者空間來實作吧,既然使用者守護程序實作了管理,cachefs中緩存的檔案就是由這個守護程序來建立,删除,修改了,那麼該cachefs中的檔案的uid,gid以及安全字段就是這個守護程序的了,但是這些檔案雖然由守護程序建立卻不是讓守護程序通路,而是讓所有和慢速檔案系統互動的程序來通路用以提高速度的,于是問出來了,普通程序可以通路cachefs中的檔案嗎?畢竟它們的uid,gid,通路令牌不同啊,不是一個程序的,那該怎麼辦?于是将程序的安全元素抽象出來的需求被提了出來,這樣的話就可以做到随時更新替換安全元素了而不用為了通路一個檔案在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完全可以做到,你可以用兩種方式實作,第一就是使用者空間的方式,這個涉及到安全配置管理,另一個就是核心的方式,這個涉及到linux的LSM機制,在最新的2.6.29核心上,cred機制可以更加簡單的實作這一點,因為作為一個整體struct cred中可以隻更改某些字段而不必觸及所有,當然實作這個需要LSM的幫忙,總之,linux就是十分靈活,十分棒。

人長得醜了真的很好

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

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

繼續閱讀