0

我正在编写一个小型 tcp echo 服务器来测试 Linux 上的缓冲区溢出。我有两个略有不同的服务器代码版本。当一个过大的缓冲区被发送到第一个缓冲区时,它会在读取函数中按预期溢出,从而导致分段错误。对于代码的第二个版本,我在接受、读取和写入函数周围添加了一个 While (1) 循环,以便服务器在正常使用下不会退出,但是当相同的缓冲区被发送到第二个服务器时,没有溢出并且服务器根本不会崩溃。我无法弄清楚为什么,代码与 while 循环相同。任何帮助将不胜感激。:)

服务器 1

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno, clilen;
    char recv[512];
    bzero(recv,512);
    struct sockaddr_in serv_addr, cli_addr;
    if (argc < 2) exit(1);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) exit(1);
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) exit(1);
    listen(sockfd,5);
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) exit(1);
    int n = read(newsockfd,recv,1024);
    if (n < 0) exit(1);
    write(newsockfd,recv,n);
    close(newsockfd);
    return 0;
}

服务器 2

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno, clilen;
    char recv[512];
    bzero(recv,512);
    struct sockaddr_in serv_addr, cli_addr;
    if (argc < 2) exit(1);
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) exit(1);
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) exit(1);
    listen(sockfd,5);
    clilen = sizeof(cli_addr);
    while (1) {
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0) continue;
        int n = read(newsockfd,recv,1024);
        if (n < 0) continue;
        write(newsockfd,recv,n);
        close(newsockfd);
    }
    return 0;
}
4

2 回答 2

2

缓冲区溢出会导致堆栈被覆盖,特别是函数的返回地址。实际的溢出本身并不是导致分段错误的原因,而是当您稍后从发生溢出的函数返回时,返回地址已损坏。(其他可能来自缓冲区溢出的段错误包括从被覆盖的指针访问内存,或使用已被覆盖的函数指针等)。

在您的示例中,while 循环阻止您到达 return 语句,因此当您的缓冲区溢出并且您的返回地址被破坏时,该返回地址从未使用过,因此不会发生段错误。

如果你想验证溢出是否发生,我建议要么在调试器中观察,要么打印出 serv_addr 和 cli_addr 结构中的值,我希望它们会被你的溢出破坏。

此外,如果您想从溢出中查看段错误,请将 recv 调用及其目标缓冲区移动到一个单独的函数中,然后从 while(1) 循环内部调用该函数。当带有 recv 的函数返回时,应该会发生段错误。

于 2011-03-07T04:10:35.860 回答
1

当缓冲区溢出时,您无法预测程序会做什么。行为取决于缓冲区之后发生的事情以及过长输入中的确切内容。这些事情可能取决于程序的不相关部分(编译的地址是什么),甚至可能取决于从运行到运行的加载地址。

于 2011-03-07T04:02:54.357 回答