Может ли recv () привести к переполнению буфера?

Я знакомлюсь с программированием сокетов на C / C ++ и использую send() а также recv() обмениваться данными между клиентской и серверной программой через TCP Розетки.

Вот некоторые соответствующие выдержки из моего кода:

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) — это приведет к переполнению буфера? (Я на самом деле пытался сделать это, но, похоже, не может вызвать segfault).

Я на самом деле пытаюсь создать намеренно уязвимую серверную программу, чтобы лучше понять эти проблемы, поэтому я попытался переполнить через recv(),

поправка:

Не связано, было бы выяснить, почему client.c выше, отправит больше, чем 1024 байты, указанные strlen(send_data), я использую gets(send_data) заполнить этот буфер из стандартного ввода, но если я введу гораздо больше, чем 1024 байта через стандартный ввод, server.c Программа показывает, что получает ВСЕ БАЙТЫ! :). Ли strlen(send_data) за send() не ограничивать количество отправляемых байтов?

5

Решение

Например, если я изменил 3-й аргумент на recv () на нечто большее, чем буфер, на который указывает recv_data (например, 4000) — это вызовет переполнение буфера?

Конечно да. Если сетевой буфер имеет данные 4000 байтов, он поместит их в буфер. Ключевым моментом является то, что recv, как и любой другой C API, который принимает буфер, и его длина считает, что вызывающая сторона передаст фактическую длину буфера, и если вызывающая сторона передает неправильную длину, то ошибка лежит на вызывающей стороне, и это может привести к неопределенному поведению.

В Си, когда вы передаете массивы в функцию, вызываемая функция не может узнать размер массива. Таким образом, все API просто полагаются на предоставленные вами данные.

char recv_data[1024];

// Socket setup and so on ommited...

bytes_recieved = recv(connected, recv_data, 1024, 0);
recv_data[bytes_recieved] = '\0';

Приведенный выше код может вызвать проблемы во многих отношениях, чем один. Это приведет к неопределенному поведению при следующих условиях:
(а) Если recv возвращается -1, то вы напрямую индексируете в буфер recv_data без проверки возвращаемого значения
(б) Если recv возвращается 1024опять же, это приводит к неконтролируемому доступу как массиву размера 1024 должны быть доступны из 0 в 1023,

9

Другие решения

это

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-терминатор работает за памятью, выделенной для strlen()С аргументом программа наверняка столкнется с неопределенным поведением и, следовательно, может вернуть любое значение.

Итак, чтобы ответить на ваш вопрос: если send_data является не 0 концевыми strlen() заставляет приложение работать с неопределенным поведением, чтобы оно могло аварийно завершиться или strlen() возвращает значение больше 1024, поэтому send() попытался бы отправить это количество символов.

5

Даже если вы отправите больше байтов, чем recv() буфер, вы все еще можете recv() это при последующих вызовах recv()вот почему ты сказал, что bytes_received все еще 5000 байты, потому что, скажем, вы отправляете 5000 байт, и ваш буфер приема 1000 байт, при первом вызове recv() это только получит 1000 байтов при следующем вызове, 1000 байт снова, пока не получит все ваши данные. Итак, я думаю, что здесь нет переполнения буфера. Это, кстати, как работает TCP.

0