October 09, 2006

寫程式的呆瓜

單字 "goofs" 的意思就是「呆瓜」、「傻子」,多數的人應該都希望這個用詞不要套用在自身,而在我閱讀 Embedded.com 上一篇由 Ben Chelf 發表的文章 [Avoiding the most common software development goofs] 後,卻不由自主地反省起來。

之前的 blog [software validation 小記] 提過現在隨便一個知名的軟體專案,程式碼都已經跨越百萬行的門檻,面對這些大怪物,要如何證明並在有限條件內檢驗,就是當今最重要的課題之一,並且引用具有二十多年歷史的 X Window System 是如何遇到安全性的缺陷,[Coverity Inc.] 對此提出的因應方式,而剛剛那篇文章的作者就是 [Coverity Inc.] 的技術長,長期著墨於軟體品質的驗證與分析。說了這麼多,到底什麼行為稱得上是 "goofs",而這樣的愚昧又釀造什麼悲劇呢?[Avoiding the most common software development goofs] 給了一個明確的例子,試看以下程式碼片段:
    /* First the options that are only allowed for root */
    if (getuid() == 0 || geteuid != 0)                                                              
    {
      ...
出處為 Xorg xserver 的 hw/xfree86/common/xf86Init.c 原始程式,最近的版本已經做了安全性修正,所以跟以上列表不同。看起來沒什麼錯誤,順便複習一下 POSIX API,以下是 man page 內容:
    DESCRIPTION
           getuid() returns the real user ID of the current process.
           geteuid() returns the effective user ID of the current process.
    
X server 會佔據相關的系統資源並確保 UID = 0 以作最大程度的操作,以上兩個 API 即是判斷執行時期的權限。不過,這不是重點,[Coverity Inc.] 指出這是導致安全性缺陷的發生點,為什麼?注意到 geteuid 後面缺了 "()",這導致我們是以 0 去跟 geteuid 的 function pointer 去比較,而非其傳回值,恰好這個缺陷在某些情況下,會引發非預期的表現,在之前的 blog [software validation 小記] 已經引用說明,這裡不再贅述。所以,解決方式就是在 geteuid 多加個 "()",這樣的錯誤果然「呆瓜」,不是嗎?對比 X11 的眾多 Release 程式碼,可以發現這個缺陷存在多年。

Ben Chelf 整理了幾個開發者犯錯的因素:
  • Ignorance.
  • Stress.
  • Boredom.
  • Human Frailties.
字彙簡單,也容易理解,不過錯誤就這樣釀成。今天是 UNIX Desktop,或許只是導致伺服器出現安全性漏洞,修補一下即可,但如果明天是波音飛航系統、居家保全設施、醫療系統、... 又會如何?或許,[技術本身與道德無關;它沒有是非對錯],但無可否認的是,這些缺失往往造成道德問題,卻多肇因於這些 "goofs" 的行徑,Ben Chelf 的文章相當精彩,也讓我對自己不能精準的掌握類似問題的焦點並提出具體的解決方式,感到不安與歉意。

唉,雖然參與過好幾個軟體專案,不過至今還只是個會寫程式的呆瓜罷了。
由 jserv 發表於 October 9, 2006 01:13 AM
迴響

geteuid != 0 是不是 geteuid() != 0 呢

鳥毅 發表於 October 11, 2006 08:55 AM

剛才看錯了,請刪除吧

鳥毅 發表於 October 11, 2006 08:57 AM

感恩你這篇的提醒..
Jserv 兄想要更精進,更開竅..
歡迎來找我們聽課..
雖不是技術課程,卻能得人生智慧喔^^
所謂一竅通竅竅通..

jaderabbit 發表於 October 12, 2006 01:42 PM