工程趣聞 2026 年 7 月 9 日

2026-07-09 — T恤上會跑的bash動畫、只咬左撇子的觸控地雷,與拆解Linux核心的KASAN下毒機制

primary=https://tris.sherliker.net/blog/obfuscated-self-evaluating-bash-script-by-cdn-akamai-being-supplied-to-consumers-via-retail-stores/ primary=https://news.ycombinator.com/item?id=48829312 primary=https://shkspr.mobi/blog/2026/07/a-bug-which-only-affected-left-handed-users/ primary=https://core.trac.wordpress.org/ticket/46713 primary=https://github.com/WordPress/wordpress-develop/pull/12168 primary=https://bootlin.com/blog/poison-redzones-and-shadows-inside-kasan/

優衣庫T恤上印了一段會「自己執行」的bash script,工程師靠肉眼OCR把它挖出來

Tris Sherliker's Blog · 2026-07-09

2026年7月,工程師Tris Sherliker的太太買了一件Uniqlo與Akamai合作推出的「Peace for All」紀念T恤。T恤正面印著一顆愛心夾在大括號中間,背面則是一整片密密麻麻的英數字圖案。Sherliker一眼就認出那不是隨機圖樣,而是一段被base64編碼過的bash腳本。

發現經過

那段文字的開頭是熟悉的shebang#!/bin/bash,後面接著一長串base64字元,再串接base64 --decode | eval的執行模式。這種「解碼後直接丟給shell執行」的寫法,正是Sherliker口中「基本上就是病毒傳播的標準手法」——把不透明的內容交給eval,執行前完全看不出實際行為。問題是,這段文字只印在衣服上,沒有數位檔案可以複製貼上,唯一的輸入管道是相機和肉眼。

技術細節:三重OCR比對

要把印在布料上、可能因為拍照角度和布紋扭曲的字元,精準還原成可執行的base64字串,任何一個字元錯誤都會讓解碼直接失敗——base64沒有內建錯誤更正機制。Sherliker因此並用三種辨識管道互相校對:

  • Android的「畫圈搜尋」OCR功能,他形容效果「通常很不錯」
  • Tesseract,並反覆調整辨識參數
  • Claude AI,作為第三方比對來源

他把三份結果互相diff,再請Claude產生差異位置表,方便人工逐一核對修正。最後靠著字串收尾處剛好對齊的引號與括號作為完整性檢查,確認整段轉錄無誤。

解碼結果:一段終端機動畫

還原後的腳本其實無害,是一段會在終端機裡跑出正弦波動畫的裝飾程式。它讓字串♥PEACE♥FOR♥ALL♥逐字沿著水平正弦曲線移動,並用256色終端色碼在青色(色碼12)與橘色(色碼208)之間做漸層。核心運算如下:

freq=0.2
angle=$(echo "($t) * $freq" | bc -l)
sine_value=$(echo "s($angle)" | bc -l)
x=$(echo "($cols / 2) + ($cols / 4) * $sine_value" | bc -l)

腳本還用tput civis隱藏游標,並以trap "tput cnorm; exit" SIGINT確保使用者按下Ctrl+C離開時游標會恢復正常——算是少見地在一段惡搞彩蛋裡,還顧到了終端機的收尾禮貌。

字體側寫的插曲

Sherliker原本從「0字型偏斜的斜線、1沒有襯線、曲線帶圓角」等特徵推斷背後印刷字體是Consolas,後來Hacker News網友ralphinus指正,實際上是Roboto Mono。Akamai事後發布的新聞稿也解釋了設計脈絡:以「米色機殼」與Linux象徵早期網際網路基礎建設,呼應公司成立超過25年的里程碑。文章發布後,包括Wen Chuan Lee在內也有其他人各自獨立解出同一段程式,Hacker News上也出現了對應討論串。

原始來源:Tris Sherliker's BlogHacker News討論串


一顆「touchstart」地雷,埋了七年才炸到左撇子使用者

Terence Eden's Blog (shkspr.mobi) · 2026-07-08

部落客Terence Eden收到一位忠實讀者的抱怨:每次滑動頁面,留言回覆框都會莫名其妙彈出來打斷閱讀。Eden起初完全複製不出這個問題,直到讀者補了一句關鍵資訊——他是左撇子,習慣用左手拇指滑手機。這句話成了破案的鑰匙,因為Eden自己一直是用右手拇指滑動頁面。

發現經過

頁面上的「回覆」連結被放在留言區塊的左側。右撇子讀者滑動時,拇指軌跡通常落在螢幕右半邊,不會碰到左側的連結;左撇子讀者的拇指軌跡則正好會滑過去,不小心觸發連結背後綁定的事件。這個bug因此只對左手滑動的使用者顯現,右撇子(包含開發者本人)完全感覺不到異狀,這也是它潛伏七年才被回報的原因。

根本原因

循著程式碼往回追,問題出在WordPress核心一段2017年加入的touchstart事件監聽器,對應提交14dd35e62e1325ca1c6caef0a8623ce3f02d7da9。當年瀏覽器要區分「單純點擊」與「雙擊縮放」,中間會插入約300毫秒的判斷延遲,工程師於是替連結加上touchstart監聽器,試圖讓觸控回應更即時。

  • 2017年:為解決300ms觸控延遲,替連結加上touchstart監聽器
  • 問題:多數瀏覽器其實早在2013年就已經修掉了這個300ms延遲
  • 結果:監聽器留在程式碼裡整整多餘了好幾年,卻沒人移除
  • 觸發條件:左側連結 + 左手拇指滑動軌跡 = 意外觸發回覆框

修法與收尾

對應的WordPress Trac票券是#46713,早在多年前就已經被回報,卻遲遲沒人接手排查。Eden最終確認問題後,提交了GitHub PR #12168,修法內容非常簡單——直接刪掉那段過時的touchstart監聽器程式碼就解決了問題。整起事件的教訓在於,一段「為了修復舊瀏覽器行為」而加入的相容性程式碼,如果沒有隨著瀏覽器演進被清理,就可能在特定使用習慣的使用者身上,變成一顆潛伏多年的地雷。

原始來源:shkspr.mobiWordPress Trac #46713WordPress GitHub PR #12168


下毒、紅色警戒區與影子記憶:拆解Linux核心裡的記憶體抓鬼機制KASAN

Bootlin Blog · 2026-07-06

Bootlin工程師Alexis Lothoré在部落格發文,深入拆解Linux核心裡的KASAN(Kernel Address Sanitizer)如何在執行期抓出越界存取與use-after-free這兩大類記憶體錯誤。文章開頭就點出Linux核心至今仍以C語言為主,雖然這是撰寫底層程式的既定語言,卻也帶來製造錯誤的高度自由度,結果就是各種型態的未定義行為、緩衝區溢位與segmentation fault。KASAN正是為了在這些錯誤釀成災難前,提早在開發階段抓出來而生。

核心機制:影子記憶體

KASAN的作法是結合編譯器插樁與核心維護的「影子記憶體」(shadow memory),用一塊獨立的記憶體區域即時記錄每一段實際記憶體的可存取狀態。基本編碼單位是每8個位元組(一個「granule」)對應1個影子位元組,換算下來,generic KASAN模式預設會拿系統記憶體的八分之一來做這件事。位址換算公式是:

shadow_byte = (target_addr >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET

其中KASAN_SHADOW_SCALE_SHIFT在generic KASAN模式下固定為3,在x86_64架構上,影子記憶體區段對應到位址0xffffec0000000000

紅色警戒區與下毒

影子位元組的值本身就是一份小型狀態表:0x00代表整個granule可正常存取,0x010x07代表granule裡只有部分位元組合法(例如0x03代表前3個位元組可用),負值則代表整段記憶體已被「下毒」(poisoned),不允許存取。專門的標記值如KASAN_SLAB_FREE用來標示剛被釋放的記憶體,KASAN_SLAB_REDZONE則標示配置區塊前後刻意留出的「紅色警戒區」緩衝地帶,一旦程式碼寫超界踩進這塊緩衝區,就會立刻被攔截。

  • 配置階段:kasan_slab_alloc呼叫kasan_unpoison把影子位元組清成0x00
  • kasan_kmalloc會透過poison_kmalloc_redzone把配置後多出來的空間標記為不可存取
  • 釋放階段:kfree觸發kasan_poison_slab_object,把整塊記憶體標成KASAN_SLAB_FREE
  • 「檢疫區」(quarantine)機制會刻意延後SLAB配置器真正回收該記憶體的時間,降低立即被重新配置、掩蓋use-after-free的機率

編譯期插樁與兩種模式

這一切的前提是編譯器插樁,核心透過scripts/Makefile.kasan加上-fsanitize=kernel-address旗標,讓編譯器在每次記憶體讀寫前自動插入檢查呼叫,例如讀取對應__asan_load1__asan_loadN,寫入對應__asan_store1__asan_storeN,這些函式統一由DEFINE_ASAN_LOAD_STORE巨集展開產生。插樁又分成outline與inline兩種模式:outline模式每次存取都呼叫一次外部函式,程式碼體積小但執行期開銷較高;inline模式則直接把位移、比對邏輯內嵌展開,快速路徑就是比對影子位元組是否為0x00,失敗才跳轉到__asan_report_load8_noabort之類的慢速路徑,換來的是更大的核心映像檔案。

組態選項與變體

對應的核心組態選項包括CONFIG_KASAN總開關、CONFIG_KASAN_GENERIC(標準的每8位元組一位元組追蹤)、CONFIG_KASAN_OUTLINECONFIG_KASAN_INLINE對應前述兩種插樁模式,還有CONFIG_KASAN_VMALLOC用來追蹤vmalloc配置的記憶體、CONFIG_KASAN_STACK替堆疊變數加上紅色警戒區,以及內建自我測試模組的CONFIG_KASAN_KUNIT_TEST。除了generic KASAN之外,文章也提到軟體tag-based模式能降低記憶體開銷,而硬體tag-based模式則是利用ARM64專屬的記憶體標籤延伸(MTE)指令集,把追蹤負擔幾乎完全轉嫁給硬體。文中也示範用virtme-ng搭配CONFIG_KASAN=yCONFIG_KUNIT=yCONFIG_KASAN_KUNIT_TEST=m載入kasan_test模組,直接在虛擬機裡重現各種記憶體違規情境。

原始來源:Bootlin Blog


End of article
0
Would love your thoughts, please comment.x
()
x