-
Notifications
You must be signed in to change notification settings - Fork 174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid unaligned data access for grasshopper cipher. #376
base: master
Are you sure you want to change the base?
Conversation
shanechko
commented
Dec 15, 2021
Compiler can produce incorrect instructions for arch with strict memory access like ARM. Root case is compiler assuming some data type is always aligned properly. Pointer cast from unaligned pointer to this type `grasshopper_w128_t` can trigger segmentation fault.
@@ -183,7 +192,7 @@ static EVP_PKEY *load_private_key(int key_nid, int param_nid, const char *pk, | |||
BN_free(y); | |||
if (EC_POINT_cmp(group, pkey, xy, bc) == 0) | |||
printf("Public key %08x matches private key %08x\n", | |||
*(int *)pub, *(int *)pk); | |||
charbuf_to_uint(pub), charbuf_to_uint(pk)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Зачем это изменение - как вы поняли, что там могут быть unaligned данные?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Это исправление предупреждения компилятора.
Компилятор добавляет предупреждения при касте указателя с малого типа (char) в больший (int).
На архитектурах типа arm не каждый char* может быть конвертирован в int*.
Так как char* входящий параметр он не обязан быть выровнен по int.
@@ -667,29 +655,36 @@ static int gost_grasshopper_cipher_do_cfb(EVP_CIPHER_CTX *ctx, unsigned char *ou | |||
(gost_grasshopper_cipher_ctx *) EVP_CIPHER_CTX_get_cipher_data(ctx); | |||
const unsigned char *in_ptr = in; | |||
unsigned char *out_ptr = out; | |||
unsigned char *buf = EVP_CIPHER_CTX_buf_noconst(ctx); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Почему вы решили, что этот буфер unaligned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
скорее всего потому, что он выделяется изнутри openssl. Коллегам наверняка нужно выравнивание по 16 байтам, а компилятор по умолчанию выравнивает по 8. Компилятор openssl при этом ничего не знает про требования engine к выравниванию.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Спасибо. Но, почему должно быть выравнивание по 16 байт?
Особенно в том примере где просто доступ к (int *)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Почему вы решили, что этот буфер unaligned?
Я исправил предупреждение компилятора. Компилятор рассматривает наихудший допустимый случай на основе типа данных.
@beldmit у компилятора (и языка С) есть ABI и который устанавливает обязательное выравнивание типов и структур. Проблема в том что когда метод возвращает указатель на char из поля структуры, информация о выравнивании теряется, и компилятор считает что это произвольный допустимый указатель на char.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Спасибо. Но, почему должно быть выравнивание по 16 байт? Особенно в том примере где просто доступ к (int *)?
- Нет требования про 16 байт, это недопонимание.
- Изменения в этом MR направлены на избавления от одного UB: Каста указателя меньшего типа к большему. Так делать нельзя, потому что это приводит к ошибкам на архитектурах с инструкциями требующими выровненного обращению к памяти.
Кстати, по поводу остальных мест - скорее всего надо просто убрать |
В общем, моё мнение такое — я не одобряю этого PR, так как он испортит, а не улучшит код.
|
Если принять этот PR, то и дальше и во всем коде надо будет выравнивать всё по 16 байт, такой тренд задан. Мы готовы и хотим это делать? Почему нигде люди таким не занимаются? |
Я повторюсь это недопонимание. Не нужно ничего явно выравнивать, это работа компилятора правильно размещать данные. Нужно не мешать компилятору несовместимыми кастами указателей. Посмотрите как реализованы другие блочные шифры. |
Это так не работает. Выравнивание есть всегда, на основе типа данных и ABI. И компилятор ожидает этого выравнивания. Например если функция получает int* компилятор уверен что указатель кратен четырём. Если это SSE тип то компилятор знает что он выровнен по 16 байтам, и использует инструкции для работы с выровненными данными. ALIGN(16) добавлен потому что на x86 архитектуре SSE требует выровненных данных. На ARM архитектуре работа с int требует выровненных данных. |
Это не улучшение, а исправление реальных и возможных сбоев. Эти сбои никогда не воспроизведутся на x86 архитектуре.
Позвольте объяснить для чего используется Абсолютно согласен что касты к большему типу не нужны. Я расскажу как делал этот MR Компилятор всегда генерирует aligned код. Потому что так работает процессор.
charbuf_to_uint это исправление недопустимого каста.
В каждом коммите менятся только одна функция, и не более 20 изменений строк. Подскажите какие требования к изменениям? |
Посмотрю на той неделе, сегодня и на выходных недееспособен, извините. |
@shanechko, спасибо аз ответ. Извиняюсь, что не внимательно посмотрел ваш PR. У меня есть доступ к разным архитектурам, так что если вы напишете тесты, которые воспроизводят эти проблемы мы, вероятно, сможем их запустить. Даже если это будет не часто — это возможность тестирования на будущее. Ранее, мы специально делали тесты такими (есть даже отключение MIPS_FIXADE для mipsel), и гоняли их да других архитектурах, чтоб всплывали проблемы с alignment. ps. В теории, есть возможность вернуть CI на ppc64le, s390x и arm64 на Travis-CI (там это всё ещё доступно для Open Source repositories). |
elseif(CMAKE_C_COMPILER_ID MATCHES "GNU") | ||
set(CMAKE_C_FLAGS_RELEASE -O2) | ||
set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb") | ||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -ggdb") | ||
add_compile_options(-Werror -Wall -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-error=unknown-pragmas -Wno-error=pragmas -Wno-deprecated-declarations) | ||
add_compile_options(-Werror -Wall -Wcast-align -Wno-unused-parameter -Wno-unused-function -Wno-missing-braces -Wno-error=unknown-pragmas -Wno-error=pragmas -Wno-deprecated-declarations) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Если мы хотим это фиксить для всех архитектур, то, видимо, надо -Wcast-align=strict
. Чтоб и на x86 вылазили эти варнинги.
[Теперь я понял что] тут всё ОК. |
В таком случае тесты (для этих багов) не нужны! Я изначально не понял, что это фиксы варнингов и говорит про тесты и вообще не правильно понимал что тут фиксится. |
Ранее код был протестирован на sparc64 м mipsel (c MIPS_FIXADE 0) где доступ к int реально требует выровненных данных. А так же на armv7hf. Те segmentation faults, которые возникали были исправлены. Далее, если вопрос сводится к фиксу варнинга ps. И, на сколько я понимаю, на ARM ядро линукс умет исправлять unaligned access (как у mipsel). |