Comments 15
На самом деле в реальном мире всё намного страшнее. Даже когда хотят, многие программисты не могут правильно написать правильную очистку памяти. Я эту ошибку регулярно встречаю в разных проектах, натравляя на них PVS-Studio. Она просто везде. Может даже статью как нибудь напишу про этот паттерн ошибки.
Например, это может выглядеть так:
Пример взят из ReactOS, который я как раз в данный момент изучаю. Скоро будет очередная статья с блюющим единорогом.
Например, это может выглядеть так:
#define MEMSET_BZERO(p,l) memset((p), 0, (l)) char *SHA384_End(SHA384_CTX* context, char buffer[]) { ... MEMSET_BZERO(context, sizeof(context)); ... }
Пример взят из ReactOS, который я как раз в данный момент изучаю. Скоро будет очередная статья с блюющим единорогом.
Какой такой SecureZeroMemory… Тут в ночи злодеи путают местами аргументы. Ещё код из ReactOS на эту тему:
Заполнили 0xFF байт вместо 8196. Тут SecureZeroMemory не поможет. :)
#define RtlFillMemory(Destination, Length, Fill) \ memset(Destination, Fill, Length) #define IOPM_FULL_SIZE 8196 HalpRestoreIopm(VOID) { ... RtlFillMemory(HalpSavedIoMap, 0xFF, IOPM_FULL_SIZE); ... }
Заполнили 0xFF байт вместо 8196. Тут SecureZeroMemory не поможет. :)
Хорошие примеры, да пост не об этом. Да, при вызове функции перезаписи можно ошибиться. А можно не ошибиться, но вызвать не ту функцию, и тогда оптимизирующий компилятор может удалить вызов.
Я понимаю, что просто про пользу очитки памяти. Я просто хотел показать, что даже если написан код для очистки, далеко не факт что он работает. И не потому, что компилятор что-то выбросит, а просто из-за того, что программисты не тестируют, чистится память или нет. Вроде есть memset — значит и так сойдет.
P.S. Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset.
P.S. Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset.
(Куда-то исчез мой комментарий. Прошу прощения, если будет дубль.)
Я понимаю, что пост про пользу очитки памяти. Я хотел показать, что даже если код очистки написан, далеко не факт что он работает. И не потому, что компилятор что-то выбросит, а просто из-за того, что программисты не тестируют, очищается память или нет. Вроде есть memset — значит и так сойдет.
P.S. Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset.
Я понимаю, что пост про пользу очитки памяти. Я хотел показать, что даже если код очистки написан, далеко не факт что он работает. И не потому, что компилятор что-то выбросит, а просто из-за того, что программисты не тестируют, очищается память или нет. Вроде есть memset — значит и так сойдет.
P.S. Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset.
>Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset
Очень даже может. Например, Visual C++ 9 при компиляции такого кода с включенной оптимизацией (/O2)
начисто удаляет второй вызов memset() — видно в машинном коде.
На это компилятор имеет полное право — такое изменение не влияет на наблюдаемое поведение, которое описано в Стандарте (1.9/6) как последовательность вызова функций ввода-вывода и чтения-записи volatile данных.
Очень даже может. Например, Visual C++ 9 при компиляции такого кода с включенной оптимизацией (/O2)
int main()
{
WCHAR buffer[1000] = {};
MessageBox( 0, buffer, buffer, 0 );
memset( buffer, 9, sizeof( buffer ) );
return 0;
}
начисто удаляет второй вызов memset() — видно в машинном коде.
На это компилятор имеет полное право — такое изменение не влияет на наблюдаемое поведение, которое описано в Стандарте (1.9/6) как последовательность вызова функций ввода-вывода и чтения-записи volatile данных.
1) Ужасы © «Городок»
2) Место для раздумий по поводу статического анализа. Спасибо за интересную информацию.
2) Место для раздумий по поводу статического анализа. Спасибо за интересную информацию.
Очень хороший пример оптимизации. Думаю, нелишним будет добавить его в статью в качестве иллюстрации того, что будет если не использовать SecureZeroMemory.
Добавьте тэг «безопасность» или что-либо в этом духе.
Кстати говоря, бывают случаи, когда использование SecureZeroMemory штука спорная. В том плане, что наличие этой функции в импорте приложения для потенциального кодокопателя — как красная тряпка для быка — «хотят стереть что-то секретное». Соответственно, не надо даже особо стараться в поисках «секретных» данных и вникать в код, просто ставим breakpoint на SecureZeroMemory и вуаля, то, что хотели спрятать у нас как на ладони перед самым затиранием. «Ручное затирание» в этом отношении выглядит всё же лучше, если, конечно, подсказать компилятору не оптимизировать этот кусочек кода. Кодокопателю в этом случае хотя бы придётся вникать в код и найти это место, а это уже время. Аналогично рассуждая, можно понять, что схожими свойствами обладает и использование CryptoAPI. Но всё же, лучше SecureZeroMemory, чем оставлять данные в памяти.
Пост в ИнфоБез бы переместить. Он его достоен.
Спасибо! Есть куда теперь тыкать носом.
Спасибо! Есть куда теперь тыкать носом.
Написать правильную очистку памяти сложно даже хорошему программисту. Это всегда было большой проблемой.
Опасность чтения из RAM-модулей напрямую мягко говоря преуменьшена.
cryptome.org/0003/RAMisKey.pdf
Но при кривых руках — вся система сплошная дыра
cryptome.org/0003/RAMisKey.pdf
Но при кривых руках — вся система сплошная дыра
Sign up to leave a comment.
Перезаписывать память – зачем?