Про acme.sh, эксплойты и костыли
Случайно наткнулся на
https://github.com/acmesh-official/acme.sh/issues/4659
(кстати, этот issue открыли ровно год назад 🎉)
История очень эпичная:
- какая-то китайская компания занимается перепродажей сертификатов и захотела сделать бесплатную автоматическую выдачу сертификатов через ACME, как Let's Encrypt
- но увы, сама компания не являются CA и не может выписывать сертификаты, поэтому полностью протокол ACME реализовать не может
- вместо этого китайцы используют RCE-эксплойт (оно же — удаленное выполнение произвольного кода) в acme.sh, который позволяет им вставить костыль в процесс выдачи сертификата. При этом они никакого вредоносного кода у клиентов не исполняют (скорее всего), но варварски эксплуатируют страшную дыру в безопасности
- клиентов, конечно же, просят юзать только acme.sh для выписывания сертификатов
- через некоторое время эта вся история с эксплойтом вскрывается, и появляется issue на гитхабе (ссылку на который я уже давал в самом начале поста)
- далее китайскую компанию, по всей видимости, жестко DDoS'ят (что можно узнать из комментов к issue)
- потом в issue приходит представитель этой самой компании и жалуется, что (далее прямая цитата, орфография сохранена)
и сообщает, что
- дыру с RCE, конечно же, в конце концов поправили
Мораль всей этой истории мне придумывать лень, оставлю это в качестве упражнения читателям 🐳 Могу лишь сказать, что использовать уязвимости для того, чтобы что-то закостылить или обойти — не самая удачная идея :)
Случайно наткнулся на
https://github.com/acmesh-official/acme.sh/issues/4659
(кстати, этот issue открыли ровно год назад 🎉)
История очень эпичная:
- какая-то китайская компания занимается перепродажей сертификатов и захотела сделать бесплатную автоматическую выдачу сертификатов через ACME, как Let's Encrypt
- но увы, сама компания не являются CA и не может выписывать сертификаты, поэтому полностью протокол ACME реализовать не может
- вместо этого китайцы используют RCE-эксплойт (оно же — удаленное выполнение произвольного кода) в acme.sh, который позволяет им вставить костыль в процесс выдачи сертификата. При этом они никакого вредоносного кода у клиентов не исполняют (скорее всего), но варварски эксплуатируют страшную дыру в безопасности
- клиентов, конечно же, просят юзать только acme.sh для выписывания сертификатов
- через некоторое время эта вся история с эксплойтом вскрывается, и появляется issue на гитхабе (ссылку на который я уже давал в самом начале поста)
- далее китайскую компанию, по всей видимости, жестко DDoS'ят (что можно узнать из комментов к issue)
- потом в issue приходит представитель этой самой компании и жалуется, что (далее прямая цитата, орфография сохранена)
we provides HiCA for non profit purpose, to provide ssl for free (RSA). We even donated 1000 USD to acme.sh last year to support the community developers, Except us any CA or reseller did this?
и сообщает, что
finally, we closed HiCA project and keep this before the community investigation finished.
- дыру с RCE, конечно же, в конце концов поправили
Мораль всей этой истории мне придумывать лень, оставлю это в качестве упражнения читателям 🐳 Могу лишь сказать, что использовать уязвимости для того, чтобы что-то закостылить или обойти — не самая удачная идея :)
😁9🕊3
Скомпилируется ли такой код на Си?
И если нет, то почему?
Примечания:
- компилируем под GNU/Linux на x86_64 с glibc и компилятором gcc любой не очень древней версии
- можно убедиться, что код содержит только ASCII-символы и не содержит длинных последовательностей пробелов (то есть приколов вроде «вот здесь используется кириллическое е вместо e латиницей, попались!» в этом коде нет)
- в дополнение к предыдущему пункту: если вы перенаберете код в своей любимой IDE так, как его видите в посте, то он будет абсолютно идентичен
Догадки можно писать в комментарии :)
И если нет, то почему?
#include <sys/fcntl.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
typedef struct {
int mtime;
int size;
} Storage;
void load(Storage *st) {
scanf("%d%d", &st->mtime, &st->size);
}
int main() {
Storage st;
load(&st);
int st_mtime = st.mtime;
int st_size = st.size;
printf("st_mtime = %d, st_size = %d\n", st_mtime, st_size);
return 0;
}
Примечания:
- компилируем под GNU/Linux на x86_64 с glibc и компилятором gcc любой не очень древней версии
- можно убедиться, что код содержит только ASCII-символы и не содержит длинных последовательностей пробелов (то есть приколов вроде «вот здесь используется кириллическое е вместо e латиницей, попались!» в этом коде нет)
- в дополнение к предыдущему пункту: если вы перенаберете код в своей любимой IDE так, как его видите в посте, то он будет абсолютно идентичен
Догадки можно писать в комментарии :)
🤯3
Гепардово гнездо
Скомпилируется ли такой код на Си? И если нет, то почему? #include <sys/fcntl.h> #include <sys/types.h> #include <errno.h> #include <unistd.h> #include <stdio.h> typedef struct { int mtime; int size; } Storage; void load(Storage *st) { scanf("%d%d"…
Ответ такой: код не скомпилируется. Даже несмотря на то, что он выглядит довольно безобидно, и явно никаких ошибок не видно.
Разгадка, как правильно указали в комментариях, заключается в следующем.
Где-то в недрах системных заголовков есть
И теперь выходит, что объявление переменной
Разгадка, как правильно указали в комментариях, заключается в следующем.
Где-то в недрах системных заголовков есть
struct stat (здесь он прилетает через #include <sys/fcntl.h>) — структура с метаданными файла, которая используется в системном вызове stat. Изначально времена доступа к файлам хранились в этой структуре в полях st_mtime, st_atime, st_ctime в виде UNIX таймстемпа с точностью до секунды. Затем точность повысили до наносекунд и стали использовать struct timespec для задания времени (поля st_atim, st_ctim, st_mtim). А чтобы не ломать обратную совместимость для тех программ, которые про наносекундную точность ничего не знают, вставили вот такой вот костыль:#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
И теперь выходит, что объявление переменной
st_mtime дает ошибку, поскольку уже объявлен макрос ровно с таким же именем, и препроцессор раскрывает st_mtime в st_mtim.tv_sec🐳4🤯3
Исключения в C++ и почему они такие медленные
Недавно читал статью, в которой рассказывается про тормоза исключений в C++ и про то, что можно с этим сделать. Ниже будет пересказ с моими дополнениями.
Начнем с причины, почему бросание исключений медленное. Дело в том, что для этого необходимо раскрутить стек до ближайшего подходящего
В статье указывается, что попытки починить вышеописанную проблему (например, заменив mutex на rwlock) приведут либо к гонкам, либо к поломке ABI. А, как известно, C++ по странным историческим причинам могут использовать вместе с древними, собранными в виде so'шек библиотеками, из-за чего ABI никто ломать не хочет. И теперь все вынуждены жить вот с такими вот медленными исключениями :(
Указывается еще две проблемы с исключениями в текущем виде: 1) они нелокальны из-за
Стоит отдельно упомянуть, что исключения на самом деле не zero cost, даже если они не кидаются: поддержка раскрутки стека раздувает размер бинаря и иногда заставляет компилятор генерить менее оптимальный код (потому что оптимизации помешают правильной раскрутке стека).
Авторы пишут, что если оставить семантику исключений в текущем виде, но ускорить раскрутку, то
Далее предлагаются разные способы ускорить механизм обработки ошибок, все без раскрутки стека. Удивительно, что
Я бы хотел отдельно рассказать про throwing values, но про это читайте пост ниже :)
Недавно читал статью, в которой рассказывается про тормоза исключений в C++ и про то, что можно с этим сделать. Ниже будет пересказ с моими дополнениями.
Начнем с причины, почему бросание исключений медленное. Дело в том, что для этого необходимо раскрутить стек до ближайшего подходящего
catch. Но раскрутка стека реализована через глобальные таблицы, которые защищены mutex'ом (например, чтобы обработать случай, когда в программу динамически подгружается so'шка и хочет, чтобы ее исключения тоже обрабатывались). Очевидно, что в многопоточном коде при интенсивном использовании исключений этот mutex быстро станет bottleneck'ом и будет драматически замедлять программу.В статье указывается, что попытки починить вышеописанную проблему (например, заменив mutex на rwlock) приведут либо к гонкам, либо к поломке ABI. А, как известно, C++ по странным историческим причинам могут использовать вместе с древними, собранными в виде so'шек библиотеками, из-за чего ABI никто ломать не хочет. И теперь все вынуждены жить вот с такими вот медленными исключениями :(
Указывается еще две проблемы с исключениями в текущем виде: 1) они нелокальны из-за
std::current_exception() и 2) они требуют аллокации на куче и RTTI. Все это, в числе прочих, мешает оптимизациям компилятора, когда тот понимает, что вот в этой ветке выкинется вот это исключение, и мог бы здесь попытаться срезать углы на создании и выбрасывании.Стоит отдельно упомянуть, что исключения на самом деле не zero cost, даже если они не кидаются: поддержка раскрутки стека раздувает размер бинаря и иногда заставляет компилятор генерить менее оптимальный код (потому что оптимизации помешают правильной раскрутке стека).
Авторы пишут, что если оставить семантику исключений в текущем виде, но ускорить раскрутку, то
Even with fully lock-free unwinding, we encountered some scalability issues with very high threads counts and high error rates (256 threads, 10% failure). These were far less severe than with current single-threaded unwinding, but nevertheless it is clear that the other parts of traditional exception handling do not scale either due to global state.что как будто бы частично решает проблему, но не до конца.
Далее предлагаются разные способы ускорить механизм обработки ошибок, все без раскрутки стека. Удивительно, что
std::expected<> показал себя не очень хорошо по скорости, хотя все остальные методы (boost::LEAF и throwing values) работают на аналогичных принципах.Я бы хотел отдельно рассказать про throwing values, но про это читайте пост ниже :)
👍7
Про throwing values
Расскажу коротко про throwing values (они же иногда называются herbceptions, потому что предложил их Herb Sutter). Полностью прочитать можно здесь, а я лишь отмечу основные моменты:
* функции, которые кидают исключение, помечены как
* такие «исключения» пробрасываются автоматически и синтаксически ловятся
* все исключения лежат в типе
Также в proposal'е предлагается добавить
На картинке выше (которую я честно украл из статьи) показывается сравнение синтаксиса throwing values и
Наверное, можно было бы еще поговорить на эту тему, но я вас уже и так закидал кучей разного текста на сегодня, поэтому остановимся здесь :)
Расскажу коротко про throwing values (они же иногда называются herbceptions, потому что предложил их Herb Sutter). Полностью прочитать можно здесь, а я лишь отмечу основные моменты:
* функции, которые кидают исключение, помечены как
throws, при этом по сути они возвращают исключение просто как значение, в регистрах (почти как Result<T, E> в Rust и std::expected<>)* такие «исключения» пробрасываются автоматически и синтаксически ловятся
try/catch как обычные, хотя на самом деле в этом случае раскрутка стека не используется. Конечно, можно их так не реализовывать, а сделать почти как в Rust и требовать подобие оператора ?, чтобы явно пробрасывать ошибку* все исключения лежат в типе
std::error размером с два указателя (чем-то похоже на гошный тип error и существующий в C++ std::error_code). Первая половина — это категория ошибки, а вторая — ее содержание (просто код ошибки для простых случаев, указатель на подробное описание для сложных, в зависимости от категории). В статье приводится также мотивация в пользу единого типа ошибок std::error вместо кучи разных типов как в текущей реализации исключенийТакже в proposal'е предлагается добавить
_Either(T, E) в Си для поддержания совместимости, а еще оптимизации вида «юзать регистр флагов, чтобы понять, вернулась ошибка или значение».На картинке выше (которую я честно украл из статьи) показывается сравнение синтаксиса throwing values и
std::expected<>, где видно, что код со throwing values выглядит гораздо проще.Наверное, можно было бы еще поговорить на эту тему, но я вас уже и так закидал кучей разного текста на сегодня, поэтому остановимся здесь :)
🐳6👍1
Драма в двух актах
(оригинал здесь: https://github.com/nim-lang/Nim/issues/23796)
(это я так законтрибутил фикс своей баги в Nim, а потом оказалось, что мой фикс ломает существующий код в специфичном сценарии)
(оригинал здесь: https://github.com/nim-lang/Nim/issues/23796)
(это я так законтрибутил фикс своей баги в Nim, а потом оказалось, что мой фикс ломает существующий код в специфичном сценарии)
😢6😎5
Недавно наткнулся на интересный пост про онлайн-безопасность (а точнее, ее отсутствие) в Южной Корее:
https://palant.info/2023/01/02/south-koreas-online-security-dead-end/
Если кратко:
- по историческим причинам крупные банки вместо TLS используют свою криптографию и протоколы для организации шифрованного соединения
- чтобы эти протоколы использовать, необходимо ставить сторонние расширения или приложения
- сами эти приложения защищены плохо и используют устаревшие и уязвимые библиотеки
- по этой же причине долгое время обязательно требовался Internet Explorer, но ситуация с тех пор поменялась
- никто эту проблему так и не решил (по крайней мере, на момент начала 2023 года, когда этот пост вышел)
Если честно, я шокирован, что такая ситуация может быть в целой стране, причем довольно развитой и технологичной
https://palant.info/2023/01/02/south-koreas-online-security-dead-end/
Если кратко:
- по историческим причинам крупные банки вместо TLS используют свою криптографию и протоколы для организации шифрованного соединения
- чтобы эти протоколы использовать, необходимо ставить сторонние расширения или приложения
- сами эти приложения защищены плохо и используют устаревшие и уязвимые библиотеки
- по этой же причине долгое время обязательно требовался Internet Explorer, но ситуация с тех пор поменялась
- никто эту проблему так и не решил (по крайней мере, на момент начала 2023 года, когда этот пост вышел)
Если честно, я шокирован, что такая ситуация может быть в целой стране, причем довольно развитой и технологичной
Almost Secure
South Korea’s online security dead end
Websites in South Korea often require installation of “security applications.” Not only do these mandatory applications not help security, way too often they introduce issues.
👍6😁3🤯1
Сегодня нашел забавное
Есть вот такая репа со «Standard Go Project Layout» (48К звезд, между прочим). Авторы подчеркивают, что, хотя организация и называется
Но однажды к ним пришел сам Russ Cox (один из core разработчиков Go) и заявил, что их «стандарт» вовсе не стандарт:
Issue, кстати, в итоге просто закрыли, а обсуждение ограничили. Такие вот дела 🐳
Есть вот такая репа со «Standard Go Project Layout» (48К звезд, между прочим). Авторы подчеркивают, что, хотя организация и называется
golang-standards, она не имеет никакого отношения к команде разработки Go. Создатели репы утверждают, что посмотрели, какой project layout используют разные проекты на Go, и сформировали из этого свой «стандарт»:This is NOT an official standard defined by the core Go dev team. This is a set of common historical and emerging project layout patterns in the Go ecosystem. Some of these patterns are more popular than others. It also has a number of small enhancements along with several supporting directories common to any large enough real world application.
Но однажды к ним пришел сам Russ Cox (один из core разработчиков Go) и заявил, что их «стандарт» вовсе не стандарт:
The README makes clear that this is not official, but even the claim "it is a set of common historical and emerging project layout patterns in the Go ecosystem" is not accurate.
For example, the vast majority of packages in the Go ecosystem do not put the importable packages in a pkg subdirectory. More generally what is described here is just very complex, and Go repos tend to be much simpler.
It is unfortunate that this is being put forth as "golang-standards" when it really is not. I'm commenting here because I am starting to see people say things like "you are not using the standard Go project layout" and linking to this repo.
Issue, кстати, в итоге просто закрыли, а обсуждение ограничили. Такие вот дела 🐳
😁11👍1🤯1😱1😢1🤡1🐳1
Есть такой сайт в интернетах: https://tylervigen.com/spurious-correlations. Это наглядная демонстрация того, что корреляция не обязательно означает причинно-следственную связь, и может быть лишь удачным совпадением.
Работает он очень просто:
* собираем много разных графиков на много разных тем (около 20'000 штук!)
* попарно пробуем вычислить корреляцию между ними
* собираем все случаи, когда величины коррелируют с хорошей такой достоверностью
* публикуем :)
Сайт существует довольно давно, какое-то время назад он был сломан. Сегодня я зашел и увидел, что он снова работает и получил обновление в духе нынешнего времени:
* добавились «объяснения» корреляций с помощью LLM'ок
* также LLM'ками генерятся «научные» статьи вокруг найденной корреляции
Получилась еще и довольно забавная иллюстрация того, как можно «объяснить» все, что угодно :)
Работает он очень просто:
* собираем много разных графиков на много разных тем (около 20'000 штук!)
* попарно пробуем вычислить корреляцию между ними
* собираем все случаи, когда величины коррелируют с хорошей такой достоверностью
* публикуем :)
Сайт существует довольно давно, какое-то время назад он был сломан. Сегодня я зашел и увидел, что он снова работает и получил обновление в духе нынешнего времени:
* добавились «объяснения» корреляций с помощью LLM'ок
* также LLM'ками генерятся «научные» статьи вокруг найденной корреляции
Получилась еще и довольно забавная иллюстрация того, как можно «объяснить» все, что угодно :)
Tylervigen
Spurious Correlations
Correlation is not causation: thousands of charts of real data showing actual correlations between ridiculous variables.
🔥13👍7🤯1
Чем я заnimался
Все описанное в посте происходило несколько месяцев назад, и у меня долго не доходили лапки оформить пост, но все же…
Как вы уже, наверное, догадались из заголовка, речь пойдет про язык программирования Nim.
Я уже писал ранее про свои коммиты в Nim, но с тех пор пришлось еще немного в него поконтрибутить. На этот раз не в стандартную библиотеку, а аж в сам компилятор!
В современных языках обычно принято писать компиляторы на них же самих. Nim здесь не исключение. Когда-то давным-давно его компилятор был написан на Object Pascal, но с тех пор весь код на паскале автоматически сконвертили в код на Nim. Результат этой конвертации хорошо описывается словами из compiler/readme.md:
Другая особенность компилятора Nim — это то, что он не использует LLVM (хотя существует сторонняя реализация, которая юзает LLVM как бэкенд компиляции), а транслирует код в Си, и только потом уже собирает бинарник при помощи
Конечно же, у такой двухэтапной компиляции есть и проблемы. Основная заключается в том, что, вообще говоря, Си и C++ — языки с достаточно большим количеством странностей и не всегда консистентным поведением. Например, ссылки в C++, которые умеют неявно разыменовываться, а сами ссылки нельзя никак изменять. Или массивы фиксированного размера в Си, которые ведут себя иногда как значение, а иногда как указатель на первый элемент — зависит от того, где и как массив используется. И, конечно же, при переводе кода на C/C++ эти все особенности надо учитывать. Естественно, учет особенностей приводит к костылям и багам в компиляторе. А избегать их иногда сложно, потому что хочется хороший интероп с C/C++.
Я несколько раз находил баги компилятора (раз, два, три) разной степени критичности. Кстати, баги в Nim исправляют довольно оперативно — через неделю-две созданный мной issue уже оказывался исправленным и закрытым. Но вот один раз мой баг игнорили аж целую неделю, поэтому я решил попробовать свои силы и исправить его самостоятельно.
Десяток часов времени, горстка отладочных
В итоге баг повержен, PR залит, issue закрыт. Победа? А вот и нет!
Для начала пришлось немного попотеть, чтобы бэкпортировать фикс в stable ветку. При попытке это сделать падали тесты, и пришлось черри-пикнуть в stable еще один коммит, чтобы все заработало.
Во-вторых, оказалось, что я все-таки не учел все случаи, и мой фикс сломал чей-то код. Пришлось чинить. Впрочем, об этом я уже даже когда-то писал :)
Выводы из всей этой истории делайте сами. Могу лишь сказать вот что: если вам нравится язык, смотреть исходники его компилятора может быть не лучшей идеей — можно разочароваться :) Тем не менее, даже несмотря на такой опыт с багами, я все еще считаю, что Nim как язык неплох.
Стоит отметить, что описанные выше проблемы с компиляцией пытаются потихоньку решить. В частности, авторы языка изобрели промежуточный байткод между самой логикой Nim и C/C++ бэкендами, что позволит, я надеюсь, упростить компилятор и уменьшить количество багов.
Все описанное в посте происходило несколько месяцев назад, и у меня долго не доходили лапки оформить пост, но все же…
Как вы уже, наверное, догадались из заголовка, речь пойдет про язык программирования Nim.
Я уже писал ранее про свои коммиты в Nim, но с тех пор пришлось еще немного в него поконтрибутить. На этот раз не в стандартную библиотеку, а аж в сам компилятор!
В современных языках обычно принято писать компиляторы на них же самих. Nim здесь не исключение. Когда-то давным-давно его компилятор был написан на Object Pascal, но с тех пор весь код на паскале автоматически сконвертили в код на Nim. Результат этой конвертации хорошо описывается словами из compiler/readme.md:
So the code is not a poster child of good Nim code.
Другая особенность компилятора Nim — это то, что он не использует LLVM (хотя существует сторонняя реализация, которая юзает LLVM как бэкенд компиляции), а транслирует код в Си, и только потом уже собирает бинарник при помощи
gcc, clang или любого другого компилятора, который существует в системе. Подход хорош тем, что позволяет очень и очень просто заюзать любую функцию из любой библиотеки на Си (просто указываешь, какую функцию из какого хедера ты хочешь импортировать в Nim, и какую библиотеку надо влинковать — и все работает. А этот ваш Rust так может?). Еще можно попросить компилятор скомпилить код не в Си, а C++ — это может пригодиться для интеропа с C++ и позволяет юзать классы из кода на C++ в коде на Nim.Конечно же, у такой двухэтапной компиляции есть и проблемы. Основная заключается в том, что, вообще говоря, Си и C++ — языки с достаточно большим количеством странностей и не всегда консистентным поведением. Например, ссылки в C++, которые умеют неявно разыменовываться, а сами ссылки нельзя никак изменять. Или массивы фиксированного размера в Си, которые ведут себя иногда как значение, а иногда как указатель на первый элемент — зависит от того, где и как массив используется. И, конечно же, при переводе кода на C/C++ эти все особенности надо учитывать. Естественно, учет особенностей приводит к костылям и багам в компиляторе. А избегать их иногда сложно, потому что хочется хороший интероп с C/C++.
Я несколько раз находил баги компилятора (раз, два, три) разной степени критичности. Кстати, баги в Nim исправляют довольно оперативно — через неделю-две созданный мной issue уже оказывался исправленным и закрытым. Но вот один раз мой баг игнорили аж целую неделю, поэтому я решил попробовать свои силы и исправить его самостоятельно.
Десяток часов времени, горстка отладочных
echo по коду — и баг исправлен. Пора делать PR. Кстати, довольно много времени ушло не на то, чтобы понять причину бага, а на то, чтобы понять, как наиболее правильно его исправить и не поломать старые костыли, учитывающие всевозможные хитрые случаи. А еще в случае с C++ для фикса надо было уметь копировать ссылку — это сложная задача, поэтому пришлось немного покостылить и сделать так, чтобы вместо нее копировался указатель.В итоге баг повержен, PR залит, issue закрыт. Победа? А вот и нет!
Для начала пришлось немного попотеть, чтобы бэкпортировать фикс в stable ветку. При попытке это сделать падали тесты, и пришлось черри-пикнуть в stable еще один коммит, чтобы все заработало.
Во-вторых, оказалось, что я все-таки не учел все случаи, и мой фикс сломал чей-то код. Пришлось чинить. Впрочем, об этом я уже даже когда-то писал :)
Выводы из всей этой истории делайте сами. Могу лишь сказать вот что: если вам нравится язык, смотреть исходники его компилятора может быть не лучшей идеей — можно разочароваться :) Тем не менее, даже несмотря на такой опыт с багами, я все еще считаю, что Nim как язык неплох.
Стоит отметить, что описанные выше проблемы с компиляцией пытаются потихоньку решить. В частности, авторы языка изобрели промежуточный байткод между самой логикой Nim и C/C++ бэкендами, что позволит, я надеюсь, упростить компилятор и уменьшить количество багов.
👍17🤯2🤔1
Чем я еще заnimался
Расскажу, пожалуй, еще одну интересную историю про Nim.
Но сначала познакомлю вас с действующими лицами сего повествования:
*лучшего языка программирования в мире. Можете считать примерным аналогом
*
*
Теперь можно начинать рассказ.
Однажды я заметил, что мой CI-пайплайн программы на Nim замедлился аж на целых пять минут! Все мы прекрасно помним
В итоге, используя метод grep'а и внимательного чтения нагрепанного кода (очень полезный метод, кстати), я выяснил вот что:
*
* перед тем, как создать ссылки на распакованные бинарники в нужной папке,
*
* далее
* сборка компилятора — конечно же, дело небыстрое, и занимает те самые пять минут. Скажем лишь спасибо, что компилятор собирается довольно быстро, и не приходится ждать часами.
В общем, предсказуемо никакого Jia Tan'а здесь не оказалось, зато оказался банальный баг. А с багами поступают обычно просто: репортят и ждут фикса. Пофиксили его, впрочем, быстро и легко: теперь
Выводы из этой истории делайте сами.
Расскажу, пожалуй, еще одну интересную историю про Nim.
Но сначала познакомлю вас с действующими лицами сего повествования:
*
nim: компилятор Nim, rustc из мира Rust.*
nimble: пакетный менеждер для языка Nim. Примерный аналог cargo из мира Rust.*
choosenim: утилита, которая умеет устанавливать nim и nimble нужных версий, а также обновлять их. Примерный аналог rustup из мира Rust.Теперь можно начинать рассказ.
Однажды я заметил, что мой CI-пайплайн программы на Nim замедлился аж на целых пять минут! Все мы прекрасно помним
xz и Jia Tan, и как из-за тормозов openssh был найден очень хорошо спрятанный бэкдор. Но в случае с openssh замедление составляло сотни миллисекунд, а здесь — аж целых пять минут! Паранойя зашкаливает, желание разобраться — еще больше.В итоге, используя метод grep'а и внимательного чтения нагрепанного кода (очень полезный метод, кстати), я выяснил вот что:
*
choosenim скачивает бинарники nim и nimble (и еще кучу разных других нужных вещей), и распаковывает их* перед тем, как создать ссылки на распакованные бинарники в нужной папке,
choosenim зовет nimble --version, чтобы напечатать предупреждение, если версия nimble слишком древняя и не поддерживается*
nimble перед тем, как показать свою версию, проверяет свое окружение, и обнаруживает, что компилятора nim нет на месте* далее
nimble пытается исправить это безобразие. Для этого он сам клонирует репу с компилятором nim и собирает его из исходников!* сборка компилятора — конечно же, дело небыстрое, и занимает те самые пять минут. Скажем лишь спасибо, что компилятор собирается довольно быстро, и не приходится ждать часами.
В общем, предсказуемо никакого Jia Tan'а здесь не оказалось, зато оказался банальный баг. А с багами поступают обычно просто: репортят и ждут фикса. Пофиксили его, впрочем, быстро и легко: теперь
--version лишь выводит версию и больше ничего сделать не пытается.Выводы из этой истории делайте сами.
👍11🤯1🕊1
Я написал очень длинный и очень интересный текст про Юникод. Поскольку в Telegram пост такого размера не помещается, выложил на сайт:
https://blo.gepar.do/v0/unicode.html
Все бегом читать :)
https://blo.gepar.do/v0/unicode.html
Все бегом читать :)
👍27🔥8🤯4
Вдогонку про Юникод и Rust
Во-первых, спасибо всем, кто читал и распространял мой пост про Юникод :) Формат с большими текстами на сайте оказался, как видно, довольно неплох, и надо будет когда-нибудь попробовать его еще раз…
Во-вторых, хотелось бы рассказать еще немного про крейт unicode_categories в Rust, который упоминался в посте. Крейт этот примечателен вот чем:
* С одной стороны, он заброшен и не развивается (последний релиз в 2016 году, последний коммит в репу — в 2021), а еще имеет версию
* С другой стороны, он очень активно используется: под 80'000 скачиваний ежедневно, занимает 623 место по общему числу скачиваний, и от него зависят многие другие крейты. Какое-то время назад он даже использовался в
Выводы делайте сами. Мне вспоминается лишь https://xkcd.com/2347 :)
Во-первых, спасибо всем, кто читал и распространял мой пост про Юникод :) Формат с большими текстами на сайте оказался, как видно, довольно неплох, и надо будет когда-нибудь попробовать его еще раз…
Во-вторых, хотелось бы рассказать еще немного про крейт unicode_categories в Rust, который упоминался в посте. Крейт этот примечателен вот чем:
* С одной стороны, он заброшен и не развивается (последний релиз в 2016 году, последний коммит в репу — в 2021), а еще имеет версию
0.1.1 и не поддерживает новые версии Юникода.* С другой стороны, он очень активно используется: под 80'000 скачиваний ежедневно, занимает 623 место по общему числу скачиваний, и от него зависят многие другие крейты. Какое-то время назад он даже использовался в
rustfmt, но, к счастью, его там заменили на более современный unicode-properties.Выводы делайте сами. Мне вспоминается лишь https://xkcd.com/2347 :)
🐳3
This media is not supported in your browser
VIEW IN TELEGRAM
Про переписывание истории
В баше (а точнее, в GNU Readline, который используется башом), есть довольно странная фича: историю команд можно редактировать!
Делается это так:
* нажимаем клавишу ↑, доматываем до команды, которую хотим отредактировать
* редактируем команду
* нажимаем клавишу ↓, доматываем до конца
* готово :)
Наглядную демонстрацию можно видеть на видео выше.
Я на эту «фичу» неумышленно натыкался много раз, и, сам того не зная, редактировал историю. А потом недоумевал, почему у меня при вызове
Как это отключить? Можно почитать, например, здесь. Если коротко, то надо в домашней папке создать файл с названием
В баше (а точнее, в GNU Readline, который используется башом), есть довольно странная фича: историю команд можно редактировать!
Делается это так:
* нажимаем клавишу ↑, доматываем до команды, которую хотим отредактировать
* редактируем команду
* нажимаем клавишу ↓, доматываем до конца
* готово :)
Наглядную демонстрацию можно видеть на видео выше.
Я на эту «фичу» неумышленно натыкался много раз, и, сам того не зная, редактировал историю. А потом недоумевал, почему у меня при вызове
history часть строк оказывались пустыми.Как это отключить? Можно почитать, например, здесь. Если коротко, то надо в домашней папке создать файл с названием
.inputrc и поместить в него такие строчки:$include /etc/inputrc
set revert-all-at-newline on
😁12🔥7👌2🤬1🤨1
Еще про проклятые фичи баша
https://yossarian.net/til/post/some-surprising-code-execution-sources-in-bash
tl;dr: вот эта функция на баше при передаче «правильного» аргумента может привести к выполнению произвольного кода:
Мораль проста:не пишите на баше не передавайте в bash-скрипты недоверенные данные
https://yossarian.net/til/post/some-surprising-code-execution-sources-in-bash
tl;dr: вот эта функция на баше при передаче «правильного» аргумента может привести к выполнению произвольного кода:
function guess() {
num="${1}"
if [[ "${num}" -eq 42 ]]
then
echo "Correct"
else
echo "Wrong"
fi
}Мораль проста:
😱5👍2
https://www.ryanliptak.com/blog/every-rc-exe-bug-quirk-probably/
Не знаю, как вы, а я просто обожаю такие посты.
Здесь автор попытался написать альтернативную реализацию компилятора ресурсов Windows. Это программа, которая принимает текстовый
Альтернативных реализаций компилятора ресурсов много, но у автора была цель, которой не добивались остальные:написать все на новом модном современном Zig как можно точнее сохранить совместимость с оригинальной версией от Microsoft, вплоть до багов и незадокументированного поведения.
Как достичь этой цели? Например, можно написать код, а затем пофаззить оригинальную реализацию с альтернативной и найти, на каких данных они выдают разные результаты. В результате этого процесса автор нашел горы странного поведения в компиляторе ресурсов от Microsoft.
Пост длинный; если хотите посмотреть только самое интересное, можно поискать по странице по словам
Не знаю, как вы, а я просто обожаю такие посты.
Здесь автор попытался написать альтернативную реализацию компилятора ресурсов Windows. Это программа, которая принимает текстовый
.rc файл с описанием менюшек, кнопочек, окошек, иконок, курсоров и прочего, и компилирует это описание в бинарный .res файл, который потом встраивается в бинарник приложения под Windows.Альтернативных реализаций компилятора ресурсов много, но у автора была цель, которой не добивались остальные:
Как достичь этой цели? Например, можно написать код, а затем пофаззить оригинальную реализацию с альтернативной и найти, на каких данных они выдают разные результаты. В результате этого процесса автор нашел горы странного поведения в компиляторе ресурсов от Microsoft.
Пост длинный; если хотите посмотреть только самое интересное, можно поискать по странице по словам
utterly baffling. Если же у вас много времени и вам не лень, можно прочесть и все :)Ryanliptak
Every bug/quirk of the Windows resource compiler (rc.exe), probably - ryanliptak.com
Fuzz testing decades-old software can turn up some curious behaviors
👍10🔥3👌1
Сегодня читал про то, как Debian везде перешел на 64-х битный
Проблема очень важная, ведь в 2038 году 32-х битный(осталось всего-то пережить пару эпидемий, восстание машин и ядерную войну), то проблему надо как-то решать!
Конечно же, не все настолько драматично. Большинство процессоров в мире уже давно как 64-х битные, и юзают «правильный», 64-х битный
Итак, для решения проблемы 2038 года в Debian приняли рядкомпромиссных решений странных костылей. Следите внимательно, чтобы не запутаться :)
* Для 64-х битных систем
* Для
* Для других 32-х битных архитектур (
Кстати, в Ubuntu этот переход тоже проделали, и пакеты с суффиксом
Выводы из всей этой истории делайте сами.
time_t. Изменение войдет в релиз Debian 13 (будет выпущен летом/осенью следующего года).Проблема очень важная, ведь в 2038 году 32-х битный
time_t переполнится, и многие компьютеры по всему миру не смогут узнать правильное время! А учитывая, что до 2038 года осталось немногим более 13 лет Конечно же, не все настолько драматично. Большинство процессоров в мире уже давно как 64-х битные, и юзают «правильный», 64-х битный
time_t по умолчанию почти везде. Но старые, 32-х битные системы все еще существуют, и для них надо что-то придумать.Итак, для решения проблемы 2038 года в Debian приняли ряд
* Для 64-х битных систем
time_t уже и так 64-х битный, поэтому весь «переход» заключается лишь в переименовании пакетов (например, libcurl4 → libcurl4t64). Новые пакеты с t64 при этом «предоставляют» пакет со старым именем, чтобы сторонние программы не заметили поломки ABI, не получили неудовлетворенных зависмостей и продолжали себе спокойно работать.* Для
i386 (так в Debian называют 32-х битные Intel'ы) пакеты тоже получили суффикс t64, но time_t там так и остался 32-х битным 🐳🐳 Как и на 64-х битных архитектурах, новые пакеты с t64 «предоставляют» старые. Так сделано, потому что либы под i386 очень уж часто юзаются для запуска старых программ, которые невозможно перекомпилить, поэтому поломка ABI для них нежелательна. А суффикс t64 все равно приписали, видимо, потому что переименование пакетов сделали для всех архитектур сразу.* Для других 32-х битных архитектур (
armel, armhf) пакеты тоже получили t64 суффикс, но при этом они получили еще и 64-х битный time_t.Кстати, в Ubuntu этот переход тоже проделали, и пакеты с суффиксом
t64 уже есть в последнем LTS-релизе, 24.04.Выводы из всей этой истории делайте сами.
🤨7✍5🐳1
https://habr.com/ru/post/472970/
Статья 2019 года, то есть довольно старая, с учетом того, сколько всего разного с тех пор добавили в Telegram (включая комментарии, истории и анимированных китов🐳 )
В ней описывается куча странных технических решений и множество костылей в Telegram и его протоколе MTProto.
Насколько все улучшилось в Telegram со времен написания этой статьи? Я не знаю, но мне кажется, с учетом всего добавленного за пять лет, костылей и подпорок в нем стало сильно больше…
К сожалению, слова «часть 1» в заголовке — неправда, и вторая часть так и не вышла :(
Статья 2019 года, то есть довольно старая, с учетом того, сколько всего разного с тех пор добавили в Telegram (включая комментарии, истории и анимированных китов
В ней описывается куча странных технических решений и множество костылей в Telegram и его протоколе MTProto.
Насколько все улучшилось в Telegram со времен написания этой статьи? Я не знаю, но мне кажется, с учетом всего добавленного за пять лет, костылей и подпорок в нем стало сильно больше…
К сожалению, слова «часть 1» в заголовке — неправда, и вторая часть так и не вышла :(
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
Критика протокола и оргподходов Telegram. Часть 1, техническая: опыт написания клиента с нуля — TL, MT
В последнее время на Хабре стали чаще появляться посты о том, как хорош Telegram, как гениальны и опытны братья Дуровы в построении сетевых систем, и т.п. В то же время, очень мало кто действительно...
💊3👍2🤯1🤡1
Итак, расскажу о том, что я сделал еще давно, но про что все никак не доходили руки написать пост.
Несколько лет назад, когда я разрабатывал шахматного бота под названием SoFCheck, мне понадобилось как-то проверять, действительно ли я улучшаю силу его игры, а также сравнивать его с другими ботами. Для этого я написал на Free Pascal утилиту под названием battlefield, которая запускает матчи между двумя ботами, считает всякие статистики и говорит, кто круче и насколько. Работал battlefield в целом довольно неплохо.
Не так давно мне захотелось сделать battlefield интереснее, чтобы можно было не только смотреть результаты матча, а наблюдать за партиями в реальном времени. Так появился day20. Он, как и его предшественник, тоже позволяет запускать матчи и смотреть статистики. Но теперь можно еще наблюдать за партиями в реальном времени.
Построен day20 довольно просто. Основной код написан на Go, в качестве базы — SQLite, а фронт сделан с помощью Go'шного стандартного шаблонизатора, HTMX и горстки обычного JS. Такой сетап, конечно, не дает масштабироваться до небес и не дает много девяток, но зато просто деплоится и задачу в целом выполняет: для запуска нужно всего два бинарника и все :)
Почему два? Дело в том, что day20 состоит из двух частей: основного сервера и сервера комнат. Первый общается с базой и с пользователем и рисует красивый UI. А второй принимает команды от основного сервера и запускает сами матчи. Такое разделение позволяет поднять основной сервер на не очень мощной машинке в облаке и крутить его постоянно. А самих ботов, которые требуют сильно больше CPU, можно запустить хоть на ноутбуке (либо на временной виртуалке). Серверов комнат, кстати, может быть сколько угодно (пока хватит ресурсов основного сервера принимать сделанные ходы и посылать новые матчи), что позволяет запускать много партий параллельно.
А теперь самое интересное: в ближайшие два дня вы можете зайти на https://day20.gepar.do и посмотреть все это в действии :) Там сейчас крутится матч между ботом от Антона @Wind_Eagle под названием Quirky (во много раз сильнее моего SoFCheck'а, кстати), и примерно равного ему по силе бота под названием Avalanche. При разработке Quirky, кстати, day20 неоднократно использовался для оценки его силы.
Несколько лет назад, когда я разрабатывал шахматного бота под названием SoFCheck, мне понадобилось как-то проверять, действительно ли я улучшаю силу его игры, а также сравнивать его с другими ботами. Для этого я написал на Free Pascal утилиту под названием battlefield, которая запускает матчи между двумя ботами, считает всякие статистики и говорит, кто круче и насколько. Работал battlefield в целом довольно неплохо.
Не так давно мне захотелось сделать battlefield интереснее, чтобы можно было не только смотреть результаты матча, а наблюдать за партиями в реальном времени. Так появился day20. Он, как и его предшественник, тоже позволяет запускать матчи и смотреть статистики. Но теперь можно еще наблюдать за партиями в реальном времени.
Построен day20 довольно просто. Основной код написан на Go, в качестве базы — SQLite, а фронт сделан с помощью Go'шного стандартного шаблонизатора, HTMX и горстки обычного JS. Такой сетап, конечно, не дает масштабироваться до небес и не дает много девяток, но зато просто деплоится и задачу в целом выполняет: для запуска нужно всего два бинарника и все :)
Почему два? Дело в том, что day20 состоит из двух частей: основного сервера и сервера комнат. Первый общается с базой и с пользователем и рисует красивый UI. А второй принимает команды от основного сервера и запускает сами матчи. Такое разделение позволяет поднять основной сервер на не очень мощной машинке в облаке и крутить его постоянно. А самих ботов, которые требуют сильно больше CPU, можно запустить хоть на ноутбуке (либо на временной виртуалке). Серверов комнат, кстати, может быть сколько угодно (пока хватит ресурсов основного сервера принимать сделанные ходы и посылать новые матчи), что позволяет запускать много партий параллельно.
А теперь самое интересное: в ближайшие два дня вы можете зайти на https://day20.gepar.do и посмотреть все это в действии :) Там сейчас крутится матч между ботом от Антона @Wind_Eagle под названием Quirky (во много раз сильнее моего SoFCheck'а, кстати), и примерно равного ему по силе бота под названием Avalanche. При разработке Quirky, кстати, day20 неоднократно использовался для оценки его силы.
👍26🤯6