缓冲区溢出的C代码问题

时间:2011-03-07 03:55:30

标签: c linux buffer-overflow

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

SERVER 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;
}

SERVER 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;
}

2 个答案:

答案 0 :(得分:2)

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

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

如果你想验证溢出是否正在发生,我建议你在调试器中观察,或者打印出serv_addr和cli_addr结构中的值,我希望这些值会被你的溢出所破坏。

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

答案 1 :(得分:1)

当缓冲区溢出时,您无法预测程序将执行的操作。行为取决于缓冲区之后发生的事情以及过长输入中的确切内容。这些东西可能取决于程序中不相关的部分(编译的内容是什么),甚至可能还有加载地址等因运行而变化的内容。