Pull to refresh

Comments 15

На самом деле в реальном мире всё намного страшнее. Даже когда хотят, многие программисты не могут правильно написать правильную очистку памяти. Я эту ошибку регулярно встречаю в разных проектах, натравляя на них PVS-Studio. Она просто везде. Может даже статью как нибудь напишу про этот паттерн ошибки.

Например, это может выглядеть так:

#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 на эту тему:

#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.
(Куда-то исчез мой комментарий. Прошу прощения, если будет дубль.)
Я понимаю, что пост про пользу очитки памяти. Я хотел показать, что даже если код очистки написан, далеко не факт что он работает. И не потому, что компилятор что-то выбросит, а просто из-за того, что программисты не тестируют, очищается память или нет. Вроде есть memset — значит и так сойдет.

P.S. Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset.
>Я очень сомневаюсь, что адекватный компилятор может выбросит вызов функции memset

Очень даже может. Например, 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) Место для раздумий по поводу статического анализа. Спасибо за интересную информацию.
Очень хороший пример оптимизации. Думаю, нелишним будет добавить его в статью в качестве иллюстрации того, что будет если не использовать SecureZeroMemory.
Все же пост не об этом. Да, вопрос «почему memset() не годится для перезаписи» очень правильный, но пост о том, зачем вообще нужна перезапись.
Добавьте тэг «безопасность» или что-либо в этом духе.
Кстати говоря, бывают случаи, когда использование SecureZeroMemory штука спорная. В том плане, что наличие этой функции в импорте приложения для потенциального кодокопателя — как красная тряпка для быка — «хотят стереть что-то секретное». Соответственно, не надо даже особо стараться в поисках «секретных» данных и вникать в код, просто ставим breakpoint на SecureZeroMemory и вуаля, то, что хотели спрятать у нас как на ладони перед самым затиранием. «Ручное затирание» в этом отношении выглядит всё же лучше, если, конечно, подсказать компилятору не оптимизировать этот кусочек кода. Кодокопателю в этом случае хотя бы придётся вникать в код и найти это место, а это уже время. Аналогично рассуждая, можно понять, что схожими свойствами обладает и использование CryptoAPI. Но всё же, лучше SecureZeroMemory, чем оставлять данные в памяти.
Не все так плохо. Обычно функции вроде SecureZeroMemory() реализуют так, чтобы они встраивались или хотя бы статически влинковывались. В этом случае никакого импорта не будет.
Пост в ИнфоБез бы переместить. Он его достоен.
Спасибо! Есть куда теперь тыкать носом.
Написать правильную очистку памяти сложно даже хорошему программисту. Это всегда было большой проблемой.
Опасность чтения из RAM-модулей напрямую мягко говоря преуменьшена.
cryptome.org/0003/RAMisKey.pdf

Но при кривых руках — вся система сплошная дыра
Sign up to leave a comment.