0

Linux でバッファ オーバーランをテストするための小さな tcp エコー サーバーを作成しています。サーバー コードの 2 つのわずかに異なるバージョンがあります。大きすぎるバッファが最初に送信されると、読み取り関数で期待どおりにオーバーフローし、セグメンテーション フォールトが発生します。コードの 2 番目のバージョンでは、受け入れ、読み取り、および書き込み関数の周りに While (1) ループを追加して、サーバーが通常の使用で終了しないようにしましたが、同じバッファーが 2 番目のサーバーに送信されても​​オーバーフローは発生しません。サーバーはまったくクラッシュしません。理由を理解するのに苦労しています。コードは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

バッファオーバーフローにより、スタック、特に関数からのリターンアドレスが上書きされます。実際のオーバーフロー自体はセグメンテーション違反の原因ではありません。後でオーバーフローが発生した関数から戻ったときに、リターンアドレスが破損しているためです。(バッファオーバーフローによるその他の考えられるsegfaultには、上書きされたポインタからのメモリへのアクセス、または上書きされた関数ポインタの使用などがあります)。

この例では、whileループが原因でreturnステートメントに到達できなくなっているため、バッファがオーバーフローしてリターンアドレスが上書きされている間、そのリターンアドレスは使用されないため、セグメンテーション違反は発生しません。

オーバーフローが発生していることを確認する場合は、デバッガーで監視するか、serv_addrおよびcli_addr構造内の値を出力することをお勧めします。これは、オーバーフローによって破壊されると予想されます。

また、オーバーフローからのセグメンテーション違反を確認したい場合は、recv呼び出しとその宛先バッファーを別の関数に移動してから、while(1)ループ内からその関数を呼び出します。segfaultは、recvを含む関数が戻ったときに発生するはずです。

于 2011-03-07T04:10:35.860 に答える
1

バッファオーバーフローが発生したときにプログラムが何をするかを予測することはできません。動作は、バッファの後に何が起こるか、および正確に長すぎる入力に何が含まれるかによって異なります。これらのことは、プログラムの無関係な部分(コンパイルされるアドレス)に依存する可能性があり、実行ごとに変化するロードアドレスのようなものにさえ依存する可能性があります。

于 2011-03-07T04:02:54.357 に答える