1. 程式人生 > >Linux 從網卡到TCP IP協議棧數據流跟蹤與審計

Linux 從網卡到TCP IP協議棧數據流跟蹤與審計

軟中斷 sys load 一個 註冊 linux rst 是否 ring

前沿

在學代碼審計,然後最近做Linux協議棧的審計,發現Linux不愧是一個久經考驗的系統,本來以為可以找到個DoS的,結果發現其在TCP/IP協議棧的鏈路層實現,利用了各種技術,用來提高性能與安全性。

工具

在跟蹤數據從網卡到TCP/IP協議棧的過程中,使用4.10.0內核,利用understand查看代碼,以及flawfinder來配合進行安全性的檢查。以intel e1000 驅動為列。

分析

NAPI

首先,為了效率,Linux使用了NAPI機制。所謂NAPI機制,其就是當數據到來時,采用中斷加輪詢的方式,接受數據包。

如果Linux使用中斷的方式,接受數據包的話,每次數據包的到來,就會產生中斷,這樣,當有大量數據包到來的話,其中斷開銷就比較大,如果CPU是單核,且頻率較低的話,就有可能夠造成DoS攻擊。

如果只是使用輪詢的話,那麽當沒有數據包到來時,會造成CPU浪費在無用功上。

所有Linux內核黑客發明了NAPI機制,中斷與輪詢相互結合的方式。

當數據到來時,會產生中斷,設備首先會關閉自身中斷,然後將該網卡設備,加入到輪詢表中,然後進而觸發軟中斷,使用輪詢接受數據包,然後當該設備上沒有數據時,打開該設備的中斷。

其內核實現路徑為:

數據到來,觸發中斷,調用網卡中斷函數e1000_intr(/drivers/net/ethernet/intel/e1000/e1000_main.c),其會將該設備加入到輪詢表中(struct softnet_data中的poll_list,其中softnet_data是每個CPU所獨有的),然後觸發軟中斷NET_RX_SOFTIRQ。軟中斷會進一步回調設備註冊的輪詢函數,e1000設備驅動是e1000_clean。然後調用e1000_clean_rx_irq輪詢接受數據包。

GRO

GRO,其實就是Generic receive offload。通過在進入到Linux 內核TCP IP協議棧處理之前,將多個數據流合並成一個,減少內核協議棧處理,提高系統性能。

感覺這玩意涉及到數據包的合並,必然涉及到很多內存上面的操作,容易發生一些漏洞什麽的,,但是通過結合flawfinder,加人工審計,並沒有發現。也可能由於我對skb_buff結構不是很了解,它已經看到了我,我沒有看到它。這塊到跟進協議棧後,熟悉skb_buff結構體之後,回過來再次看一看。

其實現函數為:napi_gro_receive.就是從底層跟蹤到高層協議,查看是否能合並,比如mac 地址相同,就看ip地址是否相同,。。。。

分析發現,其會將不能合並的加入到一個鏈表中,然後我就想,我是否可以夠造惡意數據,讓耗盡其內存,然後分析發現too young,too simple。其實現中,會限制鏈表大小,當超過限制,會強制發送到協議棧中。

RPS RFS

如果沒有NAPI機制的話,就有可能耗盡多核中的一個CPU的運算量,但是RPS的出現,讓其變得不可能。

RPS RFS 其全稱分別是:Receive Packet Steering 與 Receive Flow Steering。顧名思義,其就是讓數據處理均衡到每個CPU上。

RPS:用戶通過 /sys/class/net/eth0/queues/rx-0/rps_cpus 設置參加負載均衡的CPU。當數據包到來時,會根據相關字段,如ip建立一個hash,然後用來選擇一個CPU。

RFS:RFS其實是,RPS的補丁,想象一下,當用戶進程等待在另一個CPU上,準備接受數據包時,但是RPS給其分配到了一個不相同的CPU上,這時,當數據包處理完後,該數據包到用戶進程所在CPU進一步處理,這樣會造成緩存失效,從而降低系統性能。RFS的出現就是為了解決該問題的。

內核函數:get_rps_cpu 選擇一個CPU,然後enqueue_to_backlog加入到一個CPU的等待隊列

Linux 從網卡到TCP IP協議棧數據流跟蹤與審計