← Назад к вопросам

Почему буфер переполняется?

1.0 Junior🔥 131 комментариев
#JVM и память#Производительность и оптимизация

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое переполнение буфера?

Переполнение буфера (Buffer Overflow) — это критическая уязвимость в программном обеспечении, возникающая, когда программа записывает данные за пределы выделенного для них буфера (области памяти фиксированного размера). Это одна из старейших и наиболее опасных уязвимостей, особенно в языках низкого уровня, таких как C и C++, где управление памятью осуществляется вручную.

Основные причины переполнения буфера

1. Отсутствие проверки границ

Самый частый сценарий — использование функций, не проверяющих длину копируемых данных. Например, в C:

char buffer[10];
strcpy(buffer, "Очень длинная строка, которая точно не поместится");

Функция strcpy копирует строку без проверки размера buffer, что приводит к записи за его пределы.

2. Использование небезопасных функций

В C/C++ многие стандартные функции уязвимы:

  • gets() — читает строку без ограничения длины.
  • sprintf() — может форматировать строку в буфер недостаточного размера.
  • strcat() — добавляет строку без проверки доступного места.

Безопасные аналоги (например, snprintf, strncpy) требуют явного указания размера буфера.

3. Арифметические ошибки при работе с указателями

Неправильный расчёт индексов или размеров:

int array[5];
for (int i = 0; i <= 5; i++) {  // Ошибка: выход за границы при i = 5
    array[i] = 0;
}

4. Целочисленное переполнение

Переполнение при вычислении размера буфера:

int size = width * height * 4;  // Может переполниться для больших изображений
char* buffer = malloc(size);    // Выделится недостаточно памяти

5. Некорректная обработка пользовательского ввода

Когда программа без проверки принимает данные извне (сеть, файлы, пользовательский интерфейс):

void vulnerable_function(char* input) {
    char local_buffer[20];
    strcpy(local_buffer, input);  // Пользователь может отправить >20 байт
}

Почему это опасно?

  1. Изменение соседней памяти — перезаписываются другие переменные, структуры данных.
  2. Нарушение целостности стека — может быть перезаписаны:
    • Локальные переменные
    • Адрес возврата из функции — позволяет перенаправить выполнение программы
    • Указатель базового кадра
  3. Выполнение произвольного кода — злоумышленник может поместить в буфер машинный код и перенаправить на него выполнение.
  4. Краш программы — доступ к невалидным адресам памяти вызывает segmentation fault.

Пример эксплуатации

#include <string.h>

void vulnerable() {
    char buffer[8];
    gets(buffer);  // Пользователь вводит "AAAAAAAAAAAAAAAA\xef\xbe\xad\xde"
}

int main() {
    vulnerable();
    return 0;
}

Если ввести 12 символов 'A', а затем специально подобранный адрес 0xdeadbeef, можно перезаписать адрес возврата и заставить программу перейти по адресу 0xdeadbeef.

Меры защиты

На уровне кода:

  • Использование безопасных функций (snprintf, strlcpy, fgets).
  • Ручная проверка границ перед операциями с памятью.
  • Статический анализ кода (Coverity, Clang Static Analyzer).
  • Инструменты динамического анализа (AddressSanitizer, Valgrind).

На уровне компилятора и ОС:

  • Stack Canaries — специальные значения на стеке, проверяемые перед возвратом из функции.
  • ASLR (Address Space Layout Randomization) — рандомизация адресного пространства.
  • DEP/NX (Data Execution Prevention) — запрет выполнения кода из областей данных.
  • Control Flow Integrity — проверка целостности потока управления.

Для Android-разработчиков:

  • Использование memory-safe языков (Kotlin, Java) для бизнес-логики.
  • Минимизация нативного кода (C/C++) или его тщательный аудит.
  • Включение защит в NDK (-fstack-protector, -Wformat-security).
  • Регулярное обновление зависимостей с уязвимыми нативными библиотеками.

Заключение

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

Почему буфер переполняется? | PrepBro