2013-03-03 51 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如何工作的方式。