2013-03-03 130 views
5

我介紹自己插座C/C++編程,並且正在使用send()recv()超過TCP插座交換客戶端和服務器程序之間傳輸數據。`recv()`是否會導致緩衝區溢出?

下面是我的一些代碼相關摘錄:

server.c

char recv_data[1024]; 

// Socket setup and so on ommited... 

bytes_recieved = recv(connected, recv_data, 1024, 0); 
recv_data[bytes_recieved] = '\0'; 

client.c:

char send_data[1024]; 

// Setup ommited... 

send(connected, send_data, strlen(send_data), 0); 

是否recv()本身提供對任何保護緩衝區溢出?舉例來說,如果我改變了第三個參數來recv()比緩衝區的東西更高指向recv_data(例如4000) - 這會導致緩衝區溢出? (我已經嘗試過這樣做,但似乎無法觸發段錯誤)。

實際上,我試圖創建一個故意漏洞的服務器程序,以便更好地瞭解這些問題,這就是爲什麼我已經通過recv()試圖溢出。

修訂

不無關係,會找出爲什麼client.c上面會永遠派比strlen(send_data)指定的1024字節。我使用gets(send_data)來填充從標準輸入該緩衝區,但如果我在通過標準輸入多個超過1024字節,server.c計劃表明,它接收所有字節! :)。是否strlen(send_data)send()沒有限制發送的字節數量?

+1

與你的問題無關,但你拼寫錯誤。現在更好地糾正它,而不是稍後。 :-) – 2013-03-03 15:51:54

+0

@JamesMcLaughlin好抓,先生! – csjohn 2013-03-03 15:55:38

+1

緩衝區溢出總是程序中的一個錯誤,但是它們只有時間會導致段錯誤,這取決於libc如何佈置幕後內存。正如你觀察到的那樣,也可能有損壞的數據,或者一切都可能正常工作。這就是爲什麼緩衝區溢出難以追查的原因。 – gcbenison 2013-03-03 16:04:04

回答

9

例如,如果我將recv()的第三個參數改爲高於recv_data所指向的緩衝區(例如4000) - 這是否會導致緩衝區溢出?

Ofcourse yes。如果網絡緩衝區有4000字節的數據,它將把它放入緩衝區。關鍵是,recv就像任何其他C API一樣需要一個緩衝區,並且它的長度認爲調用者將傳遞緩衝區的實際長度,並且如果調用者傳遞了不正確的長度,則錯誤在於調用者,並且可能導致到未定義的行爲。

在C中,當您將數組傳遞給函數時,被調用的函數無法知道數組的大小。所以,所有的API都依賴於您提供的輸入。

char recv_data[1024]; 

// Socket setup and so on ommited... 

bytes_recieved = recv(connected, recv_data, 1024, 0); 
recv_data[bytes_recieved] = '\0'; 

上面的代碼可能會導致更多的麻煩。 (a)如果recv返回-1,那麼您直接將索引編入recv_data緩衝區而不檢查返回值
(b)如果recv返回1024,那麼它會再次導致未定義的行爲,如果recv返回1024由於大小爲1024的數組應該從01023訪問,所以不能訪問綁定訪問。

+0

看起來如果server.c'recv_data'緩衝區是4000字節,並且我指定'recv()'調用中的長度參數爲3000字節,並且我從客戶端發送了5000個 - 第一次調用'recv()'只會複製3000個字節,但如果我再次調用它,它將會收到1000個字節。所以(網絡緩衝區?)必須持有尚未處理的數據 - 這就是爲什麼我會在後續調用recv()時看到它? – csjohn 2013-03-03 16:21:10

+0

是的。當然。網絡緩衝區將保存數據,並且只提供與緩衝區大小相同的數據。 – Jay 2013-03-04 04:38:48

+0

@csjohn:理解TCP是一種字節流協議是很重要的......這意味着在傳輸過程中可以拆分或重新組合數據包。如果您從客戶端發送5000,即使接收器要求3000,它也可能得到1..3000字節,而不會產生錯誤。接收器需要判斷是否有足夠的數據處理,否則用其他'recv()'調用的數據重新組合。例如。在上面的場景中,即使* if *第一個'recv()'得到3000字節,第二個調用可能得到50和第三個950(或更多,如果另一個'send()'發生了)。 – 2013-03-04 07:34:05

5

recv_data[bytes_recieved] = '\0'; 

可能導致緩衝區溢出,如果收到1024個字節。

你可能想改變這種

bytes_recieved = recv(connected, recv_data, 1024, 0); 

成爲

bytes_recieved = recv(connected, recv_data, 1024 - 1, 0); 

使bytes_recieved絕不會超過1023,這是最大的有效指標recv_data變得更大。


而且您的系統調用(recv()/send())缺乏錯誤檢查。測試他們以任何其他方式使用結果之前已經返回-1


參考你的修訂:

strlen()試圖返回開始從字符指向它的參數,直到第一NUL/0個字符數的字符數。這個數字可以是任何值,這取決於你在哪裏放置終止0

如果此0 -terminator的運行在分配給strlen()參數的內存後面,程序肯定會遇到未定義的行爲,因此可能返回任何值。

因此,要回答你的問題:如果send_data 0終結strlen()使應用程序運行到未定義behaviuor所以它可能會崩潰或strlen()返回一個值大於1024,那麼send()會嘗試發送此數目的字符。

+0

我儘可能多地懷疑,儘管我似乎無法觸發段錯誤。我已將此調用更改爲'recv(connected,recv_data,4048,0);'。在客戶端,'send_data'緩衝區只有1024個字節,但是當我發送5000個字節的輸入時,服務器仍然顯示'bytes_received'是5000字節。 – csjohn 2013-03-03 15:52:58

+1

@csjohn是什麼讓你認爲緩衝區溢出只存在,如果它觸發段錯誤? – jalf 2013-03-03 15:53:59

+0

@jalf沒什麼,我只是*感覺*就像我投擲的垃圾的大小會觸發一個:)。 – csjohn 2013-03-03 15:56:29

0

即使你比recv()發送緩衝區較大的字節,你仍然能夠recv()它隨後調用recv(),這就是爲什麼你說bytes_received仍然5000字節,因爲,讓我們說你送5000字節,你接收緩衝區是1000字節,在第一次調用recv()時它只會得到1000字節,在下次調用時,再次1000字節,直到它接收到所有數據。所以,我認爲這裏沒有緩衝區溢出。這就是TCP如何工作的方式。