7.5.2. Выравнивание памяти

7.5.2. Выравнивание памяти

Хотя инструмент Electric Fence очень помог в обнаружении второй проблемы в коде, а именно — вызова strcpy(), переполнившего буфер, первое переполнение буфера найдено не было.

Проблему в этом случае нужно решать с помощью выравнивания памяти. Большинство современных компьютеров требуют, чтобы многобайтные объекты начинались с определенных смещений в оперативной памяти. Например, процессоры Alpha требуют, чтобы 8-байтовый тип — длинное целое (long) — начинался с адреса, кратного 8. Это значит, что длинное целое может располагаться по адресу 0x1000 или 0x1008, но не 0x1005[11].

На основе этих соглашений реализации malloc() обычно возвращают память, первый байт которой выровнен в соответствии с размером слова процессора (4 байта для 32-разрядных и 8 байтов на 64-разрядных процессоров). По умолчанию Electric Fence пытается эмулировать такое поведение, предлагая функцию malloc(), возвращающую только адреса, кратные sizeof(int).

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

В случае с нашей тестовой программой первый вызов malloc() распределил пять байт.

Для того чтобы Electric Fence удовлетворял своим ограничениям по выравниванию, он трактует этот вызов как запрос восьми байт, с дополнительными тремя доступными байтами. В этом случае небольшие переполнения буфера, распространяющиеся на эту область, не перехватываются.

В связи с тем, что выравнивание malloc() обычно можно игнорировать, а выравнивание может способствовать незаметному переполнению буфера, Electric Fence предоставляет возможность управление выравниванием через переменную окружения ЕF_ALIGNMENT. Если эта переменная установлена, все результаты malloc() выравниваются в соответствии с ее значением. Например, если переменная установлена в значение 5, все результаты malloc() будут рассматриваться как кратные 5 (тем не менее, это значение не особенно полезно). Для отключения выравнивания памяти перед запуском программы установите ЕF_ALIGNMENT в 1. В среде Linux некорректно выровненный доступ в любом случае исправляются в ядре, несмотря на то, что в результате скорость выполнения программы может существенно снизиться. Программа будет функционировать корректно, если только в ней не присутствуют небольшие переполнения буфера.

Ниже приведен пример поведения тестовой программы, скомпонованной с Electric Fence, после установки ЕF_ALIGNMENT в 1.

$ export EF_ALIGNMENT=1

$ gdb broken

...

(gdb) run

Starting program: /usr/src/lad/code/broken

Electric Fence 2.2.0 Copyright (C) 1987 - 1999 Bruce Perens.

Program received signal SIGSEGV, Segmentation fault.

0x002a78c6 in strcpy() from /lib/tls/libc.so.6

(gdb) where

#0 0x002a78c6 in strcpy() from /lib/tls/libc.so.6

#1 0x08048522 in broken() at broken.c:15

#2 0x08048638 in main() at broken.с:47

На этот раз Electric Fence нашел переполнение буфера, которое произошло первым.