Предположение о зависимости от памяти препятствует тому, чтобы BN_consttime_swap был постоянным?

Контекст

Функция BN_consttime_swap в OpenSSL Красота. В этом фрагменте condition вычисляется как 0 или (BN_ULONG)-1:

#define BN_CONSTTIME_SWAP(ind) \
    do { \
            t = (a->d[ind] ^ b->d[ind]) & condition; \
            a->d[ind] ^= t; \
            b->d[ind] ^= t; \
    } while (0)
…
    BN_CONSTTIME_SWAP(9);
…
    BN_CONSTTIME_SWAP(8);
…
    BN_CONSTTIME_SWAP(7);

Цель состоит в том, чтобы гарантировать, что операции с большими числами более высокого уровня занимают постоянное время, эта функция либо меняет местами два больших числа, либо оставляет их на месте в постоянное время. Когда он оставляет их на месте, он фактически считывает каждое слово каждого бигнума, вычисляет новое слово, идентичное старому слову, и записывает этот результат обратно в исходное место.

Предполагается, что это займет столько же времени, как если бы бигнумы были эффективно заменены местами.

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

Вопрос

Я пытаюсь понять, характеризует ли вышеприведенная конструкция как выполнение с постоянным временем "наилучших усилий" или как идеальное выполнение с постоянным временем.

В частности, меня беспокоит сценарий, когда bignum a уже находится в кеше данных L1, когда вызывается функция BN_consttime_swap, а код сразу после возврата функции начинает работать с bignum a сразу. На современном процессоре одновременно может выполняться достаточно инструкций, чтобы копия не была технически завершена, когда используется bignum a. Механизм, позволяющий инструкциям после вызова BN_consttime_swap работать с a, является предположением о зависимости от памяти. Давайте предположим наивное предположение о зависимости от памяти ради аргумента.

Кажется, вопрос сводится к следующему:

Когда процессор, наконец, обнаруживает, что код после BN_consttime_swap считывается из памяти, которая, вопреки предположениям, была записана внутрь функции, отменяет ли он спекулятивное выполнение, как только обнаруживает, что адрес был записан, или позволяет ли он себе сохранить его, когда обнаруживает, что записанное значение совпадает со значением, которое уже было?

В первом случае BN_consttime_swap выглядит так, как будто реализует идеальное постоянное время. Во втором случае это только постоянное время наилучшего усилия: если большие числа не были заменены, выполнение кода, следующего за вызовом BN_consttime_swap, будет заметно быстрее, чем если бы они были заменены.

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

ПРИМЕЧАНИЕ. Я знаю об переадресации хранилища, но только ярлык. Это не мешает чтению выполняться до записи, которая должна быть после него. И в некоторых случаях он терпит неудачу, хотя этого и не следовало ожидать в данном случае.


person Pascal Cuoq    schedule 19.03.2015    source источник
comment
Связано: BN_consttime_swap был добавлен в марте 2014 г. в ответ на Восстановление одноразовых номеров OpenSSL ECDSA с использованием побочного канала FLUSH+RELOAD Cache Атака. Вот коммит с комментариями.   -  person jww    schedule 20.03.2015
comment
Связано: stackoverflow. ком/вопросы/27865974/   -  person Nayuki    schedule 26.03.2015
comment
@НаюкиМинасе Привет! Вы вносите свой вклад в OpenSSL? Я знаю, что существует не так много способов написать это, но стиль кажется очень знакомым. Если вы уже внесли свой вклад в OpenSSL, я был бы рад проверить постоянство времени или другие аспекты в обмен на то, что вы просматриваете исправления, которые я хотел бы получить.   -  person Pascal Cuoq    schedule 26.03.2015
comment
Возможно ли, что кто-то может объяснить, как я 5 этот пост? Я в полном замешательстве.   -  person masfenix    schedule 26.03.2015
comment
@masfenix Всем известно, что доступ к памяти раскрывает во время выполнения информацию о доступном адресе. Это один из эффектов кеша. Вопрос в том, может ли время выполнения записи в память зависеть от записываемого значения. Дополнительный контекст о том, почему нужно задавать этот вопрос и почему априори кажется возможным, что время выполнения записи в память будет зависеть от записываемого значения, был написан Робертом Грэмом в сообщении в блоге: blog.erratasec.com/2015/03/x86-is-high-level- язык.html   -  person Pascal Cuoq    schedule 26.03.2015
comment
@PascalCuoq: Привет! Нет, я не помогаю OpenSSL, поэтому не могу помочь вам с исправлениями. Если вы хотите поговорить о чем-то еще, моя контактная информация доступна в Интернете.   -  person Nayuki    schedule 29.03.2015


Ответы (3)


Также предполагается прямой перевод кода C на ассемблер (без того, чтобы компилятор C отменял усилия программиста).

Я знаю, что суть вашего вопроса не в этом, и я знаю, что вы об этом знаете, но мне нужно немного разглагольствовать. Это даже не квалифицируется как попытка "приложить все усилия" для обеспечения выполнения с постоянным временем. Компилятор имеет право проверять значение condition и пропускать все это, если condition равно нулю. Обфускация настройки condition делает это менее вероятным, но не является гарантией.

Якобы код «постоянного времени» не должен быть написан на C, точка. Даже если сегодня постоянное время, на компиляторах, которые вы тестируете, появится более умный компилятор и победит вас. Один из ваших пользователей будет использовать этот компилятор раньше вас, и они не будут знать о риске, которому вы их подвергаете. Есть ровно три способа добиться постоянного времени, о которых я знаю: специальное оборудование, сборка или DSL, который генерирует машинный код, а также доказательство выполнения с постоянным временем.


Отбросим разглагольствования, а перейдем к актуальному вопросу об архитектуре: предполагая, что компилятор до глупости наивен, этот код работает с постоянным временем на микроархивах, с которыми я достаточно знаком, чтобы оценить вопрос, и я ожидаю, что в целом это будет верно по одной простой причине: власть. Я ожидаю, что проверка в очереди хранилища или кеше, если сохраняемое значение соответствует уже существующему значению, и условное короткое замыкание хранилища или предотвращение загрязнения строки кеша в каждом хранилище потребляет больше энергии, чем было бы сохранено в редком случае, когда вы получаете чтобы избежать какой-то работы. Тем не менее, я не разработчик ЦП и не берусь говорить от их имени, поэтому примите это с несколькими столовыми ложками соли и, пожалуйста, проконсультируйтесь с одним из них, прежде чем предполагать, что это правда.

person Stephen Canon    schedule 19.03.2015
comment
Создание условия (и, возможно, других задействованных объектов) volatile даст вам, по крайней мере, гораздо больше шансов получить желаемое поведение, поскольку компилятор больше не сможет выполнять преобразования, которые изменяют количество доступов (и, следовательно, оценки условия) выполнено. - person R.. GitHub STOP HELPING ICE; 20.03.2015
comment
@R.. Полностью согласен. Сборка может быть идеальной с точки зрения чистой безопасности, но везде есть компромиссы, и библиотека с открытым исходным кодом может позволить себе только чистую, хорошо написанную версию C с volatile, которая должна обеспечивать ее безопасность в течение следующих 15 лет. . Я отправляю эту идею для группового обсуждения всех конструкций постоянного времени в библиотеке. - person Pascal Cuoq; 20.03.2015
comment
Я не думаю, что asm - это даже решение. Ничто не говорит о том, что процессор не может выполнять дополнительные оптимизации. Конечно, виртуальный процессор на основе dynrec может это сделать; в будущем реальный процессор может тоже. IMO, единственный допустимый подход к постоянному времени - это явный сон/вращение до желаемого общего времени, и, к счастью, это прекрасно выражается в C. - person R.. GitHub STOP HELPING ICE; 20.03.2015
comment
ASM — это решение только для известных микроархитектур, где вы можете гарантировать, что такой оптимизации не произойдет. Сон / вращение нежизнеспособны, потому что они имеют отчетливую подпись мощности, даже если они дают вам постоянное время. В конечном счете, специализированное оборудование, вероятно, является единственным реальным решением. - person Stephen Canon; 20.03.2015

Этот сообщение в блоге и комментарии, сделанные автором Генри на Тема этого вопроса должна рассматриваться как авторитетная, насколько можно ожидать. Я воспроизведу последний здесь для архива:

Я не думал, что случай перезаписи ячейки памяти одним и тем же значением имеет практическое значение. Я думаю, что ответ заключается в том, что в текущих процессорах значение хранилища не имеет значения, важен только адрес.

Здесь, в академических кругах, я слышал о двух подходах к устранению неоднозначности памяти: на основе адресов и на основе значений. Насколько мне известно, все современные процессоры выполняют устранение неоднозначности на основе адресов.

Я думаю, что текущий микробенчмарк имеет некоторые доказательства того, что значение не имеет значения. Многие из случаев связаны с повторным сохранением одного и того же значения в одном и том же месте (особенно со смещением = 0). Они не были аномально быстрыми.

Схемы на основе адресов используют очередь сохранения и очередь загрузки для отслеживания незавершенных операций с памятью. Загрузки проверяют очередь хранилища на совпадение адресов (Должна ли эта загрузка выполнять пересылку из хранилища в загрузку вместо чтения из кеша?), В то время как хранилища проверяют очередь загрузки (не затирает ли это хранилище местоположение более поздней загрузки, которую я разрешил выполнить? рано?). Эти проверки полностью основаны на адресах (где произошло столкновение хранилища и загрузки). Одним из преимуществ этой схемы является то, что это довольно простое расширение поверх переадресации store-to-load, поскольку там также используется поиск в очереди store.

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

Могут ли будущие переработчики перейти на схемы, основанные на ценности? Я подозреваю, что они могут. Они были предложены в середине 2000-х (?) для уменьшения сложности аппаратного обеспечения памяти.

person Pascal Cuoq    schedule 29.04.2015

Идея реализации с постоянным временем состоит не в том, чтобы на самом деле все выполнять за постоянное время. Этого никогда не произойдет в неупорядоченной архитектуре. Требование состоит в том, чтобы никакая секретная информация не могла быть раскрыта с помощью временного анализа. Чтобы предотвратить это, есть два основных требования:

а) Не используйте ничего секретного в качестве условия остановки цикла или предиката ветки. В противном случае вы откроете для себя атаку с прогнозированием перехода https://eprint.iacr.org/2006/351.pdf

б) Не используйте ничего секретного в качестве индекса доступа к памяти. Это приводит к атакам по времени кэширования http://www.daemonology.net/papers/htt.pdf

Что касается вашего кода: если предположить, что ваш секрет является «условием» и, возможно, содержимым a и b, код является совершенно постоянным по времени в том смысле, что его выполнение не зависит от фактического содержимого a, b и условия. Конечно, расположение a и b в памяти повлияет на время выполнения цикла, но не на СОДЕРЖИМОЕ, ​​которое является секретным. Это предполагает, конечно, что условие было вычислено в режиме постоянного времени. Что касается оптимизации C: компилятор может оптимизировать код только на основе известной ему информации. Если «условие» действительно секретно, компилятор не сможет распознать его содержимое и оптимизировать. Если это можно вычесть из вашего кода, то компилятор, скорее всего, сделает оптимизацию для случая 0.

person Vlad Krasnov    schedule 03.04.2015
comment
Вы не отвечаете на вопрос. Вы даете аксиоматическое определение понятия независимости от секретного времени (которое забывает о делении) и утверждаете, что код в вопросе не зависит от секретного времени в соответствии с аксиомами. Пожалуйста, внимательно прочитайте вопрос, вопрос заключается в том, может ли время выполнения записи в память заметно отличаться, когда записываемое значение совпадает со значением, уже находящимся в памяти. Это правдоподобно (по причинам, выделенным в вопросе) и будет означать, что ваше аксиоматическое определение неверно по второй причине. - person Pascal Cuoq; 03.04.2015
comment
«Что касается оптимизации C: компилятор может оптимизировать код только на основе известной ему информации» — это наивно. Компилятор знает, что макрос BN_CONSTTIME_SWAP не имеет никаких функциональных эффектов, когда condition равен 0, потому что так сказано в исходном коде, и может компилировать весь макрос, как если бы он был написан if (condition) …. Вопрос явно просит игнорировать это, потому что эта проблема ортогональна проблеме, о которой идет речь. И, наконец, это не «мой» код. Это из OpenSSL. - person Pascal Cuoq; 03.04.2015
comment
Я не знаю ни одного ЦП, который выполнял бы фактическую проверку, изменилось ли содержимое памяти после выполнения инструкции. Конечно, процессоры Intel не выполняют такую ​​проверку, и я думаю, никогда не будут, потому что это пустая трата оборудования. Дело в том, что если операция была выполнена с уже прочитанной памятью, ЦП будет использовать значение после выполнения, независимо от того, изменилось значение или нет. - person Vlad Krasnov; 07.04.2015