Проблемы с кодом C для переполнения буфера - PullRequest
0 голосов
/ 07 марта 2011

Я пишу небольшой tcp echo-сервер для тестирования переполнения буфера в Linux.У меня есть две немного разные версии серверного кода.Когда буфер большего размера отправляется первым, он переполняется, как и ожидалось, в функции чтения, вызывая ошибку сегментации.Для второй версии кода я добавил цикл While (1) вокруг функций accept, read и write, чтобы сервер не завершал работу при обычном использовании, однако при отправке того же буфера на второй сервер переполнение отсутствуети сервер не падает вообще.У меня возникли проблемы с выяснением, почему код идентичен короткому циклу 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;
}

Ответы [ 2 ]

2 голосов
/ 07 марта 2011

Переполнение буфера приводит к перезаписи стека, в частности, адреса возврата из функции. Сам фактическое переполнение не является причиной ошибки сегментации, это то, что при последующем возврате из функции, у которой было переполнение, адрес возврата был поврежден. (Другие возможные ошибки из-за переполнения буфера включают доступ к памяти из перезаписанных указателей или использование перезаписанных указателей функций и т. Д.).

В вашем примере цикл while препятствует тому, чтобы вы когда-либо достигали оператора return, поэтому, когда ваш буфер переполнен, а ваш адрес возврата засорен, этот адрес возврата никогда не используется, поэтому ошибка не возникает.

Если вы хотите убедиться, что переполнение происходит, я бы рекомендовал либо наблюдать в отладчике, либо распечатывать значения внутри структур serv_addr и cli_addr, которые, как я ожидаю, будут перекрыты вашим переполнением.

Также, если вы хотите увидеть segfault из-за переполнения, переместите вызов recv и его целевой буфер в отдельную функцию, а затем вызовите эту функцию из цикла while (1). Segfault должен возникать, когда возвращается функция с recv.

1 голос
/ 07 марта 2011

Вы не можете предсказать, что будет делать ваша программа при переполнении буфера. Поведение зависит от того, что происходит после буфера и от того, что находится на слишком длинном входе. Эти вещи могут зависеть от несвязанных частей вашей программы (по каким адресам объекты компилируются) и, возможно, даже от таких вещей, как адреса загрузки, которые меняются от запуска к запуску.

...