宋寶華:武漢肺炎啟示錄—墨菲定律與防禦性編程

2020-12-13 電子工程世界網

1949年,美國空軍一位名叫愛德華·墨菲的空軍上尉工程師,對他的某位運氣不太好的同事隨口開了句玩笑:「如果一件事有可能被做壞,讓他去做就一定會更壞。」由此衍生出墨菲定律(Murphy's Law),指「凡是可能出錯的事就一定會出錯」。

「墨菲定律」告訴我們:如果壞事情有可能發生,不管這種可能性有多小,它總會發生,並引起最大可能的損失。「墨菲定律」是軟體工程領域防禦性編程的最基礎理論,而防禦性編程是每個軟體工程師必須遵守的規範。


當你認為沒有錯誤的時候,錯就一定會來找你。

——《中國機長》劉傳健


武漢疾控中心副主任李剛2019年1月19日通報:「此次新型冠狀病毒的傳染力不強」。


219年(漢獻帝建安二十四年),劉備經已穩定益州、漢中,荊州守將關羽見時機成熟,遂北伐曹操。關羽攻樊城,孫權則從背後偷襲荊州。大本營南郡失,關羽唯有退守麥城,突圍時被擒殺。


以上的三個片段告訴我們,凡事疏忽大意,必然釀成極其嚴重的後果。反觀川航3U8633事故中,機長劉傳健在緊急情況下,對飛機的操作,出現任何一點差錯,都將直接導致機毀人亡。但是中國機長劉傳健史詩級的操控卻成就了成為世界航空史上的一個奇蹟。這與他時時謹記「墨菲定律」是分不開的。


任何時候都要做防禦性編程,將bug在早期控制住,因為bug修復成本的對數log(cost),與修復它的時間階段成比例

所以,bug越晚暴露,修復的成本越指數級上升。如果李文亮醫生因為「造謠」被訓誡的時候,我們就開始修復這個bug,其成本毫無疑問會比現在的成本指數級下降。



早期的Android(2.2及以前的版本)有個著名的root提權漏洞,叫 「Rage Against The Cage(RAtC)」。

ADB在Android裡面最初以root權限運行,之後它通過setuid(AID_SHELL)降權到shell用戶,但是Android adb.c的代碼忽略了對函數返回值的檢查:


理論上,root用戶要降權到shell普通用戶,是沒人能阻擋的。類似馬雲在阿里巴巴強行要幹碼農,劉強東在京東強行要做快遞員。但是有一種情況下,馬雲做不了碼農,比如阿里巴巴公司有章程,規定最多只能1萬個碼農。公司HR聽說馬雲明天要宣布自己做碼農,前一天晚上就招滿了1萬個碼農,這樣第二天馬雲在宣布自己是碼農後,其實還是原來的身份。由於馬雲調用了setuid(碼農)也沒檢查返回值,它這個時候覺得自己已經是個碼農了。


在Linux系統中,一個用戶的進程數量受到RLIMIT_NPROC的限制,不可能無限制的創建。所以rage againest the cage攻擊的主要原理是不斷fork出shell用戶的進程,把pid的坑佔完,導致setuid(AID_SHELL)失敗:

相關代碼:rageagainstthecage.c


該提權漏洞被用於各類root刷機,漏洞發現人Sebastian Krahmer公布的利用工具RageAgainstTheCage(rageagainstthecage-arm5.bin)被用於z4root等提權工具、Trojan.Android.Rootcager等惡意代碼之中。


後續版本的Android對此bug進行了修正,非常簡單直接:

這個事情對我們的啟示是,過度"自信"的編碼,一定是錯誤代碼


2019年,我也「親自」犯了一個這樣的錯誤,即使在我已經非常熟悉「墨菲定律」的情況下。

Linux的Graphics compositor與client端進行通信的一種常見協議wayland,通過UNIX DOMAIN socket在client和compositor進行通信,通信的每條消息通常很短:

主要是一些window對應的surfaces(以及對應的buffers)的創建、撤銷、自動等,消息通常非常短。經過我長達半年的觀察,我沒看到大於200個字節的消息。

後來我為了截獲wayland的message並進行最終的協議dump分析,弄了char buf[256]這樣的數據結構去緩存每一條消息,當時極度自信,因為半年的觀察告訴我,wayland上面的每條消息不可能超過200個字節,因此這裡256個字節應該是極度安全了。後來的事實是,軟體很快就崩了。因為網上下載的一個軟體,有個奇葩的標題(title),它的 title十分長。在wayland的shell協議裡面,window的標題是會透過socket發給compositor的:

如果有個奇葩軟體,其標題非常長,set_title後面的title字符串就可以撐破256個字節。


這件事情讓我再次領略到「墨菲定律」的神奇正確性,以及編碼不能太「自信」。否則,即使是白馬斬顏良,襄樊擒于禁、殺龐德,千裡走單騎的關羽大神,也可能兵敗荊州。



首先你一定要小心內存的越界,比如下面的代碼:

把環境變量拷貝給str,風險就是tmp完全可能大於str的長度。比較安全的做法可能是:

上述代碼,明確地告知了str的size,以及採用了strncpy保證了不越界。


我們從C語言各個版本memcpy函數的變遷也能看出防禦性編程對C語言本身發展的影響:

在C11之後,memcpy()演化出了memcpy_s(),多了一個destsz參數:

destsz-max number of bytes to modify in the destination (typically the size of the destination object)

如果大家知道memcpy()這個函數引起的內存越界在歷史上作過多少孽的話,就會明白memcpy_s()的這個改進有多麼重大的意義。


防禦性編程要求我們一定要進行代碼的靜態掃描(在代碼運行前先進行體檢),這方面最出名的工具就是coverity,內核裡面有大量的補丁是修復coverity掃描出來的問題,比如這個:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=594619497f3d6d4b8d8440e6d380e8da9dcc9eeb


防禦性編程要求我們必須提供預設的行為,比如一定要考慮我們沒有考慮的分支,將代碼本身形成閉環。譬如,下面的代碼最後一定要有個else(無論你多麼的自信,這個else裡面的情況不可能出現):

防禦性編程要求我們一定要檢查函數的返回值,只要這個函數不是返回void,它就可能出錯,這個我們在rage againest the cage部分已經闡述。比如,哪怕是fork()、pthread_create()、read()、write()這些常規函數,都是極容易出錯的,你不能做最樂觀的估計。


防禦性編程要求我們一定要小心運算的越界,如Linux內核著名的Y2K38問題,時間變量會在2038年越界,但是如果2個時間變量平均呢?

avg_time = (time1 + time2)/2;

那麼就會提前一般的時間越界,我在2009年曾經花費了2個星期找到並修復這個bug,但是總共只改了1行代碼:



我國官方曾針對武漢八義士的事情發文:"但是,事實證明,儘管新型肺炎並不是SARS,但是信息發布者發布的內容,並非完全捏造。如果社會公眾當時聽信了這個'謠言',並且基於對SARS的恐慌而採取了佩戴口罩、嚴格消毒、避免再去野生動物市場等措施,這對我們今天更好地防控新型肺炎,可能是一件幸事。"這其實是最防禦性編程效果的最佳註解。


當然,防禦性編程不等於過度防禦。比如下面的代碼,不叫防禦性編程,叫有病:

拖著箱子從30層樓的家出門去機場,出到家門口,確認下門關好沒,反覆拉門把手;走到電梯口,拖著箱子走回家門口,反覆拉門把手確認門關好沒;坐電梯到1樓,又坐電梯回到30樓,反覆拉門把手確認門關好了沒~~。這不是防禦性編程,這是強迫症編程。




墨菲定律強調各種可能性最終都會實現,實際它也包含了正向的可能性。科幻電影巔峰之作之一的《星級穿越》,女主角的名字就叫「墨菲」。《星級穿越》實際重新詮釋了「墨菲定律」,讓「墨菲定律」並不總是指代壞事,而是說只要是有可能的事,就一定會發生,這自然包括拯救地球。主角的名字暗示了她和她的父親將最終聯手拯救地球:


同樣,李文亮醫生要拯救的地球一定會得救,我們一定會從疫情中走出來。勝利一定屬於英雄的中國人民。




相關焦點

  • 如何打破墨菲定律?成就快樂人生
    「墨菲定律」指的是「凡是可能出錯的事有很大機率就會出錯」。在《打破墨菲定律——樂觀主義者和悲觀主義者的不同結局》這本書裡,作者蘇珊娜·C.塞格斯特倫認為,「墨菲定律」是一個悲觀的概念。越壞的事情越容易發生,但樂觀主義者和悲觀主義者對事情往往有不同的看法,作者基於墨菲定律介紹了這一有趣的現象並闡述了背後的原理。
  • 墨菲定律
    什麼是 墨菲定律?   「墨菲定律」亦稱莫非定理或摩菲定理,是西方世界常用的俚語。墨菲是美國愛德華茲空軍基地的上尉工程師。1949年,他和他的上司斯塔普少校,在一次火箭減速超重試驗中,因儀器失靈發生了事故。墨菲發現,測量儀表被一個技術人員裝反了。
  • 什麼是墨菲定律,墨菲定律並不深奧,其實很簡單!
    說到「墨菲定律」,很多人都認為那是一種深奧的,難懂的理論,很高大上!其實「墨菲定律」非常的簡單,在生活中處處出現!什麼是「墨菲定律」?「墨菲定律」其實就是一種高級的心理學效應問題!是由美國的愛德華茲空軍基地的上尉工程師,愛德華·墨菲提出來的!因此叫做墨菲定律!墨菲定律是什麼?「墨菲定律」核心就是每一件事都會出現兩個結果,好與壞!
  • 「墨菲定律」裡的墨菲到底是誰?-墨菲,定律,科普 ——快科技(驅動...
    大家都知道墨菲定律(Murphy's Law),你甚至可能已經經歷過:凡是可能出錯的事必定會出錯(Anything that can go wrong will go wrong)。
  • 「墨菲定律」裡的墨菲到底是誰?
    大家都知道墨菲定律(Murphy's Law),你甚至可能已經經歷過:凡是可能出錯的事必定會出錯(Anything that can go wrong will go wrong)。(註:去年的科幻大片《星際穿越》(Interstellar)男主角Cooper的女兒Murphy就是因此得名的,影片中也講到了墨菲定律)但是提出這樣一個以他名字命名的「蹩腳定律」是誰呢?他就是愛德華·墨菲(Edward A. Murphy)。好消息是,墨菲本人不會老出錯的。壞消息是,墨菲會對犯錯誤的人發火。
  • 墨菲定律背後的墨菲到底是誰?
    大家都知道墨菲定律(Murphy’s Law),你甚至可能已經經歷過:凡是可能出錯的事必定會出錯(Anything that can go wrong will go wrong)。但是提出這樣一個以他名字命名的「蹩腳定律」是誰呢?
  • 墨菲定律註解
    墨菲定律:如果有可能出錯,就一定會出錯墨菲定律:唯有計劃周全,方能避免失誤醞釀效應:「不思考」也是一種思考方式控制錯覺定律:相信直覺,但別迷信直覺羊群效應:「從眾」和「盲從」的臨界點在哪裡巴納姆效應:似是而非的「真理」一無是處
  • 好書推薦 | 《墨菲定律》
    其實就是墨菲定律的另一種表達方式。本書分十個部分,從不同的方面,介紹定律、效應、法則、理論的神奇之處。在簡單地介紹了每個定律或法則的來源和基本理論後,就如何運用其解釋人生中的現象並指導我們的工作和生活等進行了重點闡述,是一部可以啟迪智慧、改變命運的人生枕邊書。墨菲定律還可以引申為,任何你覺得有可能失敗的事,它就會失敗。
  • 《與愛同居》又名《真愛墨菲定律》,「墨菲定律」到底是什麼?
    泰國BL劇《與愛同居》(《真愛墨菲定律》)從播出後就引起一陣熱潮,粉絲紛紛感嘆太上頭。繆糕CP更是讓劇粉們磕得停不下來。這部劇能大爆有多方面的原因:一是因為劇情精彩,人物性格鮮明,無論是主角還是配角,情節環環相扣,節奏緊湊;另一方面是劇中主角顏值創新高,演員本身的魅力加分;同時,該劇以一段愛情中的人物之間的糾葛,闡釋了一個看似無形卻無處不在的定律,就是「墨菲定律」,使得全劇能引人思考,有了深層次的哲學探討,不至於淪為口水劇。
  • 西方文化三大定律之一墨菲定律
    墨菲定律墨菲定律由愛德華·墨菲在 1949 年提出,亦稱墨菲法則、墨菲定理。定律內容為:如果有兩種或兩種以上的方式去做某件事情,而其中一種選擇方式將導致災難,則必定有人會做出這種選擇。這個定律指出,如果事情有變壞的可能,不管這種可能性有多小,它總會發生。墨菲定律的由來愛德華·墨菲是美國某空軍基地的上尉工程師。1949 年與其上司參加美國空軍進行的 MX981 火箭減速超重實驗時,儀器失靈發生了事故。
  • 聊聊墨菲定律
    1949年,愛德華·墨菲,一位美國空軍上尉工程師,對他某位總犯錯誤的同事,也是如此評價。如果一件事有可能被做壞,讓他去做就一定更壞。本是一句玩笑話,沒想到,好多人都覺得說進了心坎裡,於是迅速傳播開來,被稱作墨菲定律。
  • 墨菲定律選擇
    墨菲定律不是一種心理學效應,是一種數學推理,由愛德華·墨菲(Edward A. Murphy)提出,亦稱墨菲法則、墨菲定理。1949年,一位名叫愛德華·墨菲的空軍上尉工程師,對他的某位運氣不太好的同事隨口開了句玩笑:「如果一件事有可能被做壞,讓他去做就一定會更壞。」一句本無惡意的玩笑話最初並沒有什麼太深的含義,只是說出了壞運氣帶給人的無奈。
  • 為什麼墨菲定律這麼準?
    什麼是墨菲定律? 墨菲定律是一種心理學效應,由愛德華·墨菲(Edward A. Murphy)提出,亦稱墨菲法則、墨菲定理。 「墨菲定律」、「帕金森定律」和「彼德原理」並稱為二十世紀西方文化三大發現。
  • 生活中的墨菲定律
    墨菲定律是指如果壞事情有可能發生,不管這種可能性有多小,它總會發生,並引起最大可能的損失。 其實,關於墨菲定律,這其中還有一個小故事。 1949年,有一位名叫做愛德華·墨菲的空軍上尉工程師,有一天,閒著沒事,和他的一位同事小A聊天。
  • 被歪曲的「墨菲定律」的真正意思
    墨菲定律,是這幾年小說、電視劇、甚至抖音經常出現的一條名言,一般都是這樣子來描述它。這是各種文章、報告、抖音號描述的墨菲定律,不過實際情況是,這群人都是在斷章取義,甚至可以說,他們只是一群利用別人好奇心的「標題黨」。
  • 神奇的定律:關於墨菲定律,你想要知道的都在這兒
    墨菲定律的由來墨菲定律(Murphy's Law)是由美國工程師愛德華.墨菲(Edward A. Murphy)提出的一種心理學效應,被認為是二十世紀西方文化三大發現之一。我們使用愛德華·墨菲的姓氏(墨菲)來命名墨菲定律,以表示我們對其人的尊敬。那麼,愛德華·墨菲是誰呢?
  • 「墨菲定律」給我們的啟示
    「墨菲定律」給我們的啟示 2020-05-17 03:06 來源:澎湃新聞·澎湃號·政務
  • 墨菲定律是什麼?該如何理解?
    墨菲定律(Murphy's Law),是一種心理學效應,也被稱為莫非定律、莫非定理或摩菲定理,作為二十世紀西方文化三大發現之一,是西方世界常用的俚語。與墨菲定律並稱的還有帕金森定律和彼德原理。 . 墨菲定律的來源 1949年,一位名叫愛德華·墨菲的空軍上尉工程師,對他的某位運氣不太好的同事隨口開了句玩笑:「如果一件事有可能被做壞,讓他去做就一定會更壞。」
  • 唯心主義和墨菲定律的關係
    而墨菲定律呢?主要內容:任何事都沒有表面看起來那麼簡單;所有的事都會比你預計的時間長;會出錯的事總會出錯;如果你擔心某種情況發生,那麼它就更有可能發生。我們都知道唯心主義是不正確的!那麼墨菲定律和唯心主義到底有沒有關聯呢?
  • 考不好難道是因為墨菲定律?
    同學們有沒有發現,你做過的題總是會出現,做錯的題也總是容易出錯,或許你覺得這有些「靈異」,其實這是一種心理學效應,叫「墨菲定律」。     喜歡心理學方面知識的同學應該對「墨菲定律」不會陌生,這個定律讓很多同學驚出一身冷汗,簡直準得不要不要的!