應(yīng)用程序熱補(bǔ)丁(三):完整的設(shè)計(jì)與實(shí)現(xiàn)

原文地址 https://zhuanlan.zhihu.com/p/27405926

前言

在前兩篇文章介紹了應(yīng)用程序熱補(bǔ)丁的關(guān)鍵技術(shù):

  • 修復(fù)運(yùn)行時(shí)進(jìn)程的函數(shù)

  • 加載熱補(bǔ)丁到進(jìn)程中

  • 自動(dòng)生成熱補(bǔ)丁等等

這些是組成應(yīng)用程序熱補(bǔ)丁技術(shù)框架的關(guān)鍵部分柱查,但是在生產(chǎn)環(huán)境中使用熱補(bǔ)丁技術(shù)還需要考慮適應(yīng)現(xiàn)代軟件的屬性、熱補(bǔ)丁的安全性、以及在運(yùn)營(yíng)中對(duì)熱補(bǔ)丁的管理等等粤蝎。

通過(guò)介紹 UCloud 應(yīng)用程序熱補(bǔ)丁框架的設(shè)計(jì)理念和框架中各個(gè)組件窟扑,我們會(huì)解決以下實(shí)踐中遇到的問(wèn)題:

  • 熱補(bǔ)丁的管理(加載喇颁、卸載、激活嚎货、回滾熱補(bǔ)丁等)

  • 打入熱補(bǔ)丁時(shí)的安全檢查(簡(jiǎn)單說(shuō)是什么時(shí)候打入熱補(bǔ)丁是安全的)

  • 熱補(bǔ)丁對(duì)多線程的支持等等橘霎。

應(yīng)用程序熱補(bǔ)丁的意義

介紹 UCloud 應(yīng)用程序熱補(bǔ)丁框架之前,首先介紹一下我們?yōu)槭裁囱邪l(fā)和使用熱補(bǔ)丁技術(shù)殖属。

目前主流的熱補(bǔ)丁技術(shù)姐叁,例如 Ksplice、kpatch、kGraft外潜、以及后來(lái)的 livepatch 等都是特別針對(duì) Linux 內(nèi)核的熱補(bǔ)丁技術(shù)谭溉,可以在不重啟系統(tǒng)的情況下,修復(fù)內(nèi)核缺陷橡卤。我們一般稱為內(nèi)核熱補(bǔ)丁扮念。

UCloud 使用了內(nèi)核熱補(bǔ)丁修復(fù)了若干內(nèi)核問(wèn)題,避免了重啟系統(tǒng)導(dǎo)致的服務(wù)中斷碧库,保證了操作系統(tǒng)本身的可用性柜与。

在此基礎(chǔ)上,我們的下一個(gè)目標(biāo)提高是核心組件中的單點(diǎn)的可用性嵌灰。例如虛擬化的核心組件 QEMU弄匕,雖然作為單點(diǎn)程序運(yùn)行,但是可用性的要求和內(nèi)核是一致的沽瞭。雖然 QEMU 本身支持在線遷移迁匠,可以遷移客戶的虛擬機(jī)到新版本的 QEMU 上,但是遷移本身比較笨重驹溃。在遷移過(guò)程中會(huì)牽扯多個(gè)模塊城丧,例如網(wǎng)絡(luò)、存儲(chǔ)等豌鹤,同時(shí)遷移時(shí)間和虛擬機(jī)的 downtime亡哄、break time 在運(yùn)營(yíng)上也會(huì)帶來(lái)挑戰(zhàn)。

對(duì)比 QEMU 通過(guò)在線遷移升級(jí)布疙,使用熱補(bǔ)丁修復(fù)極快蚊惯,并且對(duì)虛擬機(jī)周邊環(huán)境沒(méi)有依賴,可以對(duì)用戶的虛擬機(jī)做到靜默升級(jí)灵临。由于熱補(bǔ)丁本身的天然屬性截型,熱補(bǔ)丁更適用于代碼改動(dòng)較小的修復(fù)(例如安全漏洞),而在線遷移升級(jí)比較適用于大版本的升級(jí)儒溉。

在 UCloud 我們通過(guò)熱補(bǔ)丁修復(fù)了若干次 QEMU 的缺陷和安全漏洞宦焦,極大提高了可用性和安全性。因此我們認(rèn)為對(duì)于代碼改動(dòng)較小的問(wèn)題時(shí)睁搭,熱補(bǔ)丁是一個(gè)完美的解決方案。

為什么要自研應(yīng)用程序熱補(bǔ)丁技術(shù)舔痪?答案也很簡(jiǎn)單锌唾,我們無(wú)法找到一個(gè)實(shí)用并且易用的應(yīng)用程序熱補(bǔ)丁技術(shù)锄码,同時(shí)也由于我們已經(jīng)在內(nèi)核熱補(bǔ)丁領(lǐng)域的具有一定的積累夺英,所以決定敢為人先滋捶、自研應(yīng)用程序熱補(bǔ)丁技術(shù)。

設(shè)計(jì)理念

提出需求

介紹設(shè)計(jì)理念之前重窟,首先應(yīng)該提出應(yīng)用程序熱補(bǔ)丁在 UCloud 云平臺(tái)的需求:

  • 應(yīng)用程序熱補(bǔ)丁的適用場(chǎng)景和內(nèi)核熱補(bǔ)丁是一致的载萌,目的是修復(fù)缺陷,而不是增加功能和升級(jí)版本扭仁。所以應(yīng)用程序熱補(bǔ)丁必須允許函數(shù)級(jí)別上的修改(不論是本地函數(shù)還是全局函數(shù))厅翔。

  • 應(yīng)用程序熱補(bǔ)丁必須是安全的,也就是打入熱補(bǔ)丁的前后進(jìn)程的狀態(tài)必須一致熊泵,熱補(bǔ)丁只會(huì)操作修改的函數(shù)甸昏,不會(huì)影響進(jìn)程的正常運(yùn)行。

  • 應(yīng)用程序熱補(bǔ)丁必須支持云平臺(tái)環(huán)境中現(xiàn)代軟件具有的特性怯邪,比如說(shuō) Linux x86_64花墩、多線程等等澄步。

  • 熱補(bǔ)丁必須由工具來(lái)構(gòu)建村缸,也必須要由工具來(lái)管理(加載卸載等)。

  • 熱補(bǔ)丁必須同時(shí)支持回滾仇箱,同時(shí)支持一個(gè)進(jìn)程多次熱補(bǔ)丁修復(fù)东羹。

  • 降低熱補(bǔ)丁運(yùn)營(yíng)的難度。

我們針對(duì)這些需求属提,設(shè)計(jì)出如下的應(yīng)用程序熱補(bǔ)丁框架。

設(shè)計(jì)思路

  • 支持修復(fù)函數(shù)級(jí)別的师坎、并且可以自動(dòng)化生成熱補(bǔ)丁的工具堪滨。

  • 支持多線程、熱補(bǔ)丁安全檢查惶岭、多熱補(bǔ)丁狀態(tài)管理的熱補(bǔ)丁加載工具犯眠。

  • 運(yùn)行中的應(yīng)用程序應(yīng)記錄熱補(bǔ)丁的信息和狀態(tài)筐咧,可供外部工具查詢。

或者簡(jiǎn)單來(lái)說(shuō)铺罢,我們要做到残炮,拿到源碼和 patch 就能通過(guò)工具自動(dòng)生成熱補(bǔ)丁,熱補(bǔ)丁可以安全的打入運(yùn)行的多線程應(yīng)用程序中(不會(huì)引起程序的錯(cuò)亂和崩潰)泉瞻,并且支持打入多個(gè)熱補(bǔ)丁苞冯。打入后的熱補(bǔ)丁可以被回滾取消舅锄,可以查詢當(dāng)前應(yīng)用程序中熱補(bǔ)丁的狀態(tài)和信息。

框架組件

這個(gè)框架的設(shè)計(jì)我們通過(guò)以下組件實(shí)現(xiàn):

  • Creator

負(fù)責(zé)通過(guò) patch 和源碼自動(dòng)化生成熱補(bǔ)丁畴蹭。

支持函數(shù)級(jí)別修復(fù)鳍烁,不論本地函數(shù)還是全局函數(shù)老翘。

  • Loader

負(fù)責(zé)加載熱補(bǔ)丁到目標(biāo)進(jìn)程中锻离,也負(fù)責(zé)管理熱補(bǔ)赌够场(類似于客戶端程序)傀履。

目標(biāo)進(jìn)程支持 Linux x86_64、多線程等碴犬。

支持熱補(bǔ)丁安全檢查梆暮。

支持對(duì)熱補(bǔ)丁狀態(tài)的操作(例如加載、卸載偿荷、激活唠椭、回滾查詢等等)贪嫂。

  • Core Runtime

負(fù)責(zé)記錄多個(gè)熱補(bǔ)丁的狀態(tài)和信息,同時(shí)提供熱補(bǔ)丁通用操作斗塘。

作為熱補(bǔ)丁模塊的通用運(yùn)行時(shí)框架被 Loader 加載到目標(biāo)進(jìn)程中餐曹。

Loader 對(duì)熱補(bǔ)丁狀態(tài)的操作最終由 Core Runtime 在目標(biāo)進(jìn)程空間中執(zhí)行台猴。

  • 熱補(bǔ)毒懔健(補(bǔ)丁本身)

負(fù)責(zé)提供修復(fù)后的替換代碼和額外信息宪彩。

被 Loader 加載到目標(biāo)進(jìn)程中,注冊(cè)自己的信息到 Core Runtime

在激活后使用自身包含的替換代碼代替有問(wèn)題的函數(shù)俊柔。

組件之間協(xié)作如下圖所示,Creator 工具根據(jù)程序源碼和 patch 生成熱補(bǔ)丁模塊物赶,然后 Loader 將熱補(bǔ)丁模塊加載到目標(biāo)進(jìn)程 Process 的地址空間里留晚,最后熱補(bǔ)丁和通用運(yùn)行時(shí) Core Runtime 一起完成熱修復(fù)。

image
image

實(shí)現(xiàn)方法

接下來(lái)分別講各個(gè)組件的實(shí)現(xiàn):

Creator

基于對(duì)多種內(nèi)核熱補(bǔ)丁技術(shù)的理解奖地,我們認(rèn)為應(yīng)用程序的熱補(bǔ)丁也是可以通過(guò)工具自動(dòng)生成的赋焕。雖然相比內(nèi)核隆判,應(yīng)用程序的格式更加復(fù)雜、編譯鏈接的過(guò)程也更不固定械筛,但是自動(dòng)生成熱補(bǔ)丁應(yīng)該是可行的飒炎。

我們知道郎汪,編譯源代碼之后會(huì)生成目標(biāo)文件,將單個(gè)或多個(gè)目標(biāo)文件鏈接可以生成可執(zhí)行文件抛计。目標(biāo)文件和可執(zhí)行文件都是 ELF 格式(Executable and Linkable Format)照筑。ELF 是一種標(biāo)準(zhǔn)且通用的文件格式,Linux 上的可執(zhí)行文件波俄、目標(biāo)文件懦铺、庫(kù)支鸡、core dump 都是 ELF趁窃。

Creator 工具根據(jù) ELF 標(biāo)準(zhǔn)的格式醒陆,解析修復(fù)前后的目標(biāo)文件叔汁,找到前后不同的函數(shù),提取出差異(包括改變和新增的函數(shù))码邻,連同差異本身的屬性信息像屋,生成一個(gè)動(dòng)態(tài)鏈接庫(kù)格式的熱補(bǔ)丁边篮。如下圖所示:

image
image

之前的文章介紹過(guò)二進(jìn)制比較生成熱補(bǔ)丁替換代碼戈轿,這里不再贅述思杯。

Loader

Loader 工具作為一個(gè)客戶端程序,操作目標(biāo)進(jìn)程 Process誊册,包括熱補(bǔ)丁的加載暖璧、激活澎办、回滾、卸載悍汛、查看等至会。如下所示:

image
image

Loader 利用了 ptrace 調(diào)用奉件。Loader 通過(guò) ptrace 可以對(duì) Process 的內(nèi)存县貌、寄存器進(jìn)行讀寫,改變 Process 的運(yùn)行狀態(tài)梧宫,也可以捕獲 Process 的信號(hào)摆碉。這樣 Loader 可以停止 Process 的運(yùn)行巷帝,并根據(jù) AMD64 ABI 對(duì)內(nèi)存和寄存器進(jìn)行修改,使 Process 執(zhí)行 dlopen 等函數(shù)驰徊,加載熱補(bǔ)丁到 Process 的地址空間中堕阔,或者執(zhí)行其他熱補(bǔ)丁的操作超陆。熱補(bǔ)丁被加載之后,在 / proc/pid/maps 文件中可以看到例驹。

Loader 如何利用 ptrace 加載熱補(bǔ)丁在之前的文章中有詳細(xì)描述退唠,不再贅述瞧预。

Loader 隨后會(huì)停止 Process 所有的線程,準(zhǔn)備激活熱補(bǔ)丁盆驹,此時(shí) Loader 需要進(jìn)行一致性檢查滩愁,也就是查看熱補(bǔ)丁的激活對(duì)當(dāng)前的所有線程來(lái)講是否安全。需要檢查的是熱補(bǔ)丁的需要替換的函數(shù)是否在線程當(dāng)前函數(shù)調(diào)用棧上廉丽,如果在調(diào)用棧上正压,說(shuō)明現(xiàn)在是不安全的,激活熱補(bǔ)丁不能保證一致性拓劝。

在停止所有線程的時(shí)候嘉裤,首先需要得到全部的線程信息价脾,可以通過(guò) libthread_db 庫(kù)與進(jìn)程中 libc 進(jìn)行交互得到線程的信息,也可以通過(guò) / proc/pid/tasks / 目錄從內(nèi)核中直接得到線程的信息犀变。在停止所有線程之后获枝,需要再次獲取所有線程信息骇笔,查看是否有新增線程,如果有需要停止新增線程懦傍。重復(fù)以上動(dòng)作直到?jīng)]有新線程出現(xiàn)粗俱。

Core Runtime

在一個(gè)進(jìn)程的生命周期中虚吟,可能需要多次熱補(bǔ)丁修復(fù),同時(shí)多個(gè)熱補(bǔ)丁也會(huì)使用一些通用的功能偏塞,因此需要一個(gè)通用的核心模塊來(lái)提供通用功能灸叼,并且記錄進(jìn)程中每個(gè)熱補(bǔ)丁的信息。這個(gè)通用模塊作為一個(gè)動(dòng)態(tài)鏈接庫(kù)慎冤,我們叫做 Core Runtime沧卢。

Loader 在加載熱補(bǔ)丁時(shí)但狭,首先需要加載 Core Runtime 到進(jìn)程的地址空間撬即,對(duì)進(jìn)程而言剥槐,Core Runtime 只需要加載一次。

在熱補(bǔ)丁被加載到進(jìn)程的地址空間后颅崩,通過(guò)構(gòu)造函數(shù)沿后,首先向 Core Runtime 提供自己的信息朽砰,注冊(cè)到 Core Runtime 里瞧柔,然后將熱補(bǔ)丁中差異函數(shù)的需要重定向的部分手動(dòng)計(jì)算重定向。在激活熱補(bǔ)丁的時(shí)候撼唾,Core Runtime 會(huì)根據(jù)熱補(bǔ)丁注冊(cè)時(shí)得到的信息备绽,保存舊函數(shù)肺素,并把舊函數(shù)入口位置替換成跳轉(zhuǎn)到新的函數(shù)的機(jī)器碼,完成熱修復(fù)猴伶。如下所示:

image
image

在回滾熱補(bǔ)丁的時(shí)候他挎,Core Runtime 把舊函數(shù)入口位置恢復(fù)办桨,完成回滾。

Core Runtime 同時(shí)可以管理多個(gè)熱補(bǔ)丁损姜,以熱補(bǔ)丁的名字作為 ID摧阅,區(qū)分不同的熱補(bǔ)丁绷蹲,記錄必要的信息。

如下所示:

image
image

熱補(bǔ)丁(補(bǔ)丁本身)

這里的熱補(bǔ)丁指的是狹義上的作為動(dòng)態(tài)鏈接庫(kù)被 Loader 加載到目標(biāo)進(jìn)程 Process 中的熱補(bǔ)丁苞俘。

熱補(bǔ)丁由 Creator 產(chǎn)生吃谣,包含了替換代碼和一些動(dòng)態(tài)信息(比如新舊函數(shù)的地址做裙、大小、重定向信息等)仔戈。熱補(bǔ)丁被加載后监徘,包含的函數(shù)和變量就存在于目標(biāo)進(jìn)程的地址空間中吧碾。熱補(bǔ)丁激活以后倦春,所有對(duì)老函數(shù)的訪問(wèn)落剪,都會(huì)重定向到熱補(bǔ)丁地址范圍內(nèi)的新函數(shù)忠怖。

如下所示:

image
image

總結(jié)

Creator凡泣、Loader问麸、Core Runtime钞翔、熱補(bǔ)丁這四者構(gòu)成了 UCloud 熱補(bǔ)丁技術(shù)框架布轿,這四個(gè)組件相輔相成来颤,互相協(xié)作完成熱補(bǔ)丁福铅。

Creator 負(fù)責(zé)生成熱補(bǔ)丁,Loader 負(fù)責(zé)熱補(bǔ)丁的進(jìn)程外管理(包括加載笆包、卸載庵佣、激活汛兜、回滾熱補(bǔ)丁等)粥谬,Core Runtime 負(fù)責(zé)熱補(bǔ)丁的進(jìn)程內(nèi)管理(記錄熱補(bǔ)丁、備份舊函數(shù)派哲、恢復(fù)舊函數(shù)等)哟玷。雖然是四個(gè)組件,但是都必須遵守同一個(gè)熱補(bǔ)丁規(guī)格標(biāo)準(zhǔn)椰苟,這樣才能共同完成熱補(bǔ)丁的工作树叽。

通過(guò)這個(gè)框架题诵,極大降低了我們制作熱補(bǔ)丁性锭、打入熱補(bǔ)丁和運(yùn)營(yíng)熱補(bǔ)丁的難度。

例如她奥,一個(gè) QEMU 安全漏洞修復(fù)的流程可以簡(jiǎn)化為:

  1. Creator 通過(guò) QEMU 源碼和漏洞修復(fù) patch 生成熱補(bǔ)丁怎棱。

  2. 熱補(bǔ)丁被 Loader 打入正在運(yùn)行的應(yīng)用程序中(加載并且激活)拳恋。

  3. (可選)對(duì)運(yùn)行中的應(yīng)用程序查詢熱補(bǔ)丁的狀態(tài)和信息。

  4. (可選)對(duì)已經(jīng)打入的熱補(bǔ)丁進(jìn)行回滾和卸載隙赁。

值得指出的是鸳谜,目前不是全部 patch 都可以自動(dòng)生成熱補(bǔ)丁式廷,原因是極少部分由于程序修改復(fù)雜滑废,但是可以通過(guò)手動(dòng)修改 patch 簡(jiǎn)化代碼或者簡(jiǎn)化邏輯做到可以自動(dòng)生成熱補(bǔ)丁蠕趁。大約 90% 的 patch 在無(wú)需修改的情況下都能自動(dòng)生成熱補(bǔ)丁。

在一些特定場(chǎng)景下豁延,我們通過(guò)第一篇文章(《應(yīng)用程序熱補(bǔ)蛾几荨(一):幾行代碼構(gòu)造免重啟修復(fù)補(bǔ)丁》)中介紹的熱補(bǔ)丁技術(shù)手動(dòng)編寫熱補(bǔ)丁即可,無(wú)需使用復(fù)雜的自動(dòng)生成熱補(bǔ)丁技術(shù)诱咏。

另外苔可,目前 UCloud 應(yīng)用程序熱補(bǔ)丁技術(shù)支持 Linux C 語(yǔ)言程序,但對(duì)于其他編譯型語(yǔ)言解決思路基本一致(例如 C++ 等)袋狞。

在 UCloud焚辅,我們利用應(yīng)用程序熱補(bǔ)丁修復(fù)了若干緊急安全漏洞和缺陷,在關(guān)鍵時(shí)刻迅速解決問(wèn)題苟鸯,相比于傳統(tǒng)的軟件升級(jí)方式同蜻,解決問(wèn)題更加及時(shí)。

希望通過(guò)一系列的文章填補(bǔ)目前應(yīng)用程序熱補(bǔ)丁的空白部分早处,使更多人了解熱補(bǔ)丁的技術(shù)原理,讓熱補(bǔ)丁技術(shù)給更多人帶來(lái)更多的價(jià)值陕赃。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卵蛉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子么库,更是在濱河造成了極大的恐慌,老刑警劉巖甘有,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诉儒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡亏掀,警方通過(guò)查閱死者的電腦和手機(jī)忱反,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)滤愕,“玉大人温算,你說(shuō)我怎么就攤上這事〖溆埃” “怎么了注竿?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)魂贬。 經(jīng)常有香客問(wèn)我巩割,道長(zhǎng),這世上最難降的妖魔是什么付燥? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任宣谈,我火速辦了婚禮,結(jié)果婚禮上键科,老公的妹妹穿的比我還像新娘闻丑。我一直安慰自己漩怎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布嗦嗡。 她就那樣靜靜地躺著勋锤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪酸钦。 梳的紋絲不亂的頭發(fā)上怪得,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音卑硫,去河邊找鬼徒恋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛欢伏,可吹牛的內(nèi)容都是我干的入挣。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼硝拧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼径筏!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起障陶,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤滋恬,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后抱究,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恢氯,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年鼓寺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勋拟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妈候,死狀恐怖敢靡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苦银,我是刑警寧澤啸胧,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站墓毒,受9級(jí)特大地震影響吓揪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜所计,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一柠辞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧主胧,春花似錦叭首、人聲如沸习勤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)图毕。三九已至,卻和暖如春眷唉,著一層夾襖步出監(jiān)牢的瞬間予颤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工冬阳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛤虐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓肝陪,卻偏偏與公主長(zhǎng)得像驳庭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氯窍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355