1. Си / Говнокод #27541

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    /* https://fstarlang.github.io/lowstar/html/Introduction.html#the-essence-of-low
    
    Consider the following very simple program:
    
    module Intro
    
    module P = LowStar.Printf
    module C = LowStar.Comment
    module B = LowStar.Buffer
    
    open FStar.HyperStack.ST
    open LowStar.BufferOps
    
    let main (): St Int32.t =
      push_frame ();
      let b: B.buffer UInt32.t = B.alloca 0ul 8ul in
      b.(0ul) <- 255ul;
      C.comment "Calls to printf are desugared via meta-programming";
      let s = "from Low*!" in
      P.(printf "Hello from %s\nbuffer contents: %xul\n"
        s 8ul b done);
      pop_frame ();
      0l
    
    ....
    
    Once compiled by the KreMLin compiler, we obtain the following C code:
    */
    
    int32_t main()
    {
      uint32_t b[8U] = { 0U };
      b[0U] = (uint32_t)255U;
      /* Calls to printf are desugared via meta-programming */
      Prims_string s = "from Low*!";
      LowStar_Printf_print_string("Hello from ");
      LowStar_Printf_print_string(s);
      LowStar_Printf_print_string("\nbuffer contents: ");
      LowStar_Printf_print_lmbuffer_u32((uint32_t)8U, (uint32_t *)b);
      LowStar_Printf_print_string("\n");
      return (int32_t)0;
    }

    Какая-то компилируемая в сишку хренотень с завтипами, разрабатываемая в Microsoft Research

    Запостил: j123123, 29 Июля 2021

    Комментарии (66) RSS

    • Нахрен кстати им генерить какую-то там сишку, пусть бы сразу в какое-нибудь middle-end представление компилятора набрасывали (в Clang это LLVM-байткод, в GCC это байткод GIMPLE). Заодно пусть все оптимизации и трансформации докажут формально.
      Ответить
      • У «Nim» есть и такая, и такая реализации.
        Ответить
      • пусть сначало C# приложения в Native AOT компилировать научатся
        Ответить
        • ngen?

          Да, это не труъ AOT. Но приложухи после него вполне шустро работают.
          Ответить
          • Кстати, а почему он не труъ? Потому что на выходе не нормальный экзешник, а странная питушня из блоков кода, представленных как массив данных?
            Ответить
            • Потому что мутабельная рантайм рефлексия и прочие eval в труъ AOT невозможны?
              Ответить
              • разАОТится обратно если что, это же как с JIT
                Ответить
                • > разАОТится

                  Ну вот... т.е. это скорее стартовый снепшот для JIT'а, чем нативный образ.
                  Ответить
                  • Теперь понял. Это кэш одного из возможных состояний (наиболее вероятного). Если нужно перейти к другому (к эвалам всяким), придётся переключаться обратно к честной интерпретации.

                    Кстати, а как реализована библиотека «Phobos» для языка «D»? Ну там всякие «std.functional», где код передаётся строками? Она в рантайме вызывает модуль для компиляции кода и инжектит сгенерированный код?

                    https://dlang.org/phobos/std_functional.html
                    Ответить
                    • В "D", если я не туплю, в рантайме ничего не генерится, это труъ конпелятор. Просто он умеет выполнять какое-то ограниченное подмножество "D" в компайлтайме и отдавать строки из mixin своему же парсеру.
                      Ответить
                      • Точно. Попробовал template compose, он в компайлтайме нагенерировал функций со страшными именами типа
                        __D3std10functional__T7composeVAyaa7_61202b20302e35SQBxQBw__TQBnVQBia15_746f2128696e7429286129202b2031S_D1b3fooFiZQDfZQDsZ__TQDzTiZQEfFiZd
                        Ответить
                      • Минимальный пример:
                        import std.stdio;
                        import std.functional;
                        
                        int main() {
                        	writeln(unaryFun!("a + 0.5")(1));
                        
                        	return 0;
                        }


                        Дизасм:
                        .text:00000384                 public __Dmain
                        .text:00000384 __Dmain         proc near
                        .text:00000384
                        .text:00000384 var_8           = qword ptr -8
                        .text:00000384
                        .text:00000384                 mov     eax, 1
                        .text:00000389                 call    __D3std10functional__T8unaryFunVAyaa7_61202b20302e35VQva1_61Z__TQBqTiZQBwFNaNbNiNfiZd
                        .text:0000038E                 sub     esp, 8
                        .text:00000391                 fstp    [esp+8+var_8]   ; double
                        .text:00000394                 call    __D3std5stdio__T7writelnTdZQlFNfdZv
                        .text:00000399                 xor     eax, eax
                        .text:0000039B                 retn
                        .text:0000039B __Dmain         endp ; sp-analysis failed
                        .text:0000039B
                        .text:0000039B _text           ends
                        
                                        public __D3std10functional__T8unaryFunVAyaa7_61202b20302e35VQva1_61Z__TQBqTiZQBwFNaNbNiNfiZd
                        .text:000003F8 __D3std10functional__T8unaryFunVAyaa7_61202b20302e35VQva1_61Z__TQBqTiZQBwFNaNbNiNfiZd proc near
                        .text:000003F8                                         ; CODE XREF: __Dmain+5p
                        .text:000003F8
                        .text:000003F8 var_4           = dword ptr -4
                        .text:000003F8
                        .text:000003F8                 enter   4, 0
                        .text:000003FC                 mov     [ebp+var_4], eax
                        .text:000003FF                 fild    [ebp+var_4]
                        .text:00000402                 fadd    ds:_TMP0
                        .text:00000408                 leave
                        .text:00000409                 retn
                        .text:00000409 __D3std10functional__T8unaryFunVAyaa7_61202b20302e35VQva1_61Z__TQBqTiZQBwFNaNbNiNfiZd endp


                        И ещё куча питушни для реализации writeln. Фактически writeln — это крестошаблон.
                        Ответить
              • Надо вернуться к использованию реального режима процессора: там самомодифицирующийся код был нормой.
                Ответить
                • > самомодифицирующийся код был нормой

                  Да он и сейчас вполне норма... JIT'ы ведь работают.
                  Ответить
                  • В принципе, форматы «ELF» и «PE» позволяют создать секцию с атрибутами «rwx» и течь...
                    Ответить
                    • ...но не в самой лучшей в мире ОС

                      точнее создать можно, загрузить нельзя
                      Ответить
                      • В рантайме то потом можно выделить? Или там всякие js'ы на чистой интерпретации лагают?
                        Ответить
                        • JSам можно. Нужен спец ключ в заголовке ELF, чтоб разрешили, и такой файл нужно класть в спец место

                          В base system таких файлов нет
                          Ответить
                          • Сурово.

                            В винде такое только в ядре решились сделать.
                            Ответить
                            • Ну там это тоже не везде работает. В /usr/local можно срать rwx, иначе бы всякая джитня и правда не работала.
                              Ответить
                              • Джитня реализуема через переключения mprotect()-ом из "rw-" в "r-x". Можно и такое переключение запретить, но тогда надо и mmap с PROT_EXECUTE запретить, и dlopen запретить, и еще /proc/self/mem запретить, и execve запретить (ведь можно насрать байтиками в файл с нужными разрешениями и тупо запустить его)
                                Ответить
                                • >mprotect
                                  да, так тоже можно)
                                  Ответить
                                • > dlopen, execve

                                  Ну тут достаточно запретить грузить файлы, которые не помечены как исполняемые. А дальше можно на уровне файлухи вырубить "x", а на файлухе с исполняемыми файлами отобрать у юзера "w" и хрен ты насрёшь байтиков в исполняемый файл.
                                  Ответить
                                  • Какой SRP ^_^ ^_^ ^_^
                                    Ответить
                                  • > Ну тут достаточно запретить грузить файлы, которые не помечены как исполняемые.

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

                                    > дальше можно на уровне файлухи вырубить "x", а на файлухе с исполняемыми файлами отобрать у юзера "w"

                                    Их может допустим перезаписать какой-нибудь кривой говноскрипт, у которого будут такие права
                                    Ответить
                                    • > перезаписать какой-нибудь кривой говноскрипт

                                      Ну тут можно пойти дальше и через selinux запретить привилегированным процессам шариться по юзерским каталогам. Вообще. Всем. Ну кроме какой-нибудь бекапилки (но у неё можно отобрать write на систему) и тулов для управления юзерами (им достаточно delete и create, без чтения и записи обойдутся).

                                      В интеловских процах сейчас тоже такая фишка есть, кстати (SMAP и SMEP).
                                      Ответить
                                      • https://rdot.org/forum/showthread.php?p=39356
                                        >SMEP
                                        >Не позволяет процессору, будучи в ring0, выполнять код со страниц, помеченных флагом User.
                                        >Таким образом, столь привычные способы эксплуатации, когда есть возможность перезаписать указатель в какой-нибудь структуре в ядре адресом в юзер-моде, заммапить этот адрес и ждать, что ядро прыгнет на него исполнять наш шелл-код, перестают работать.
                                        >SMAP
                                        >Не позволяет процессору, будучи в ring0, обращаться (например, читать) к страницам, помеченным флагом User.
                                        >Поскольку ядру это необходимо в работе, были введены 2 новые инструкции, которые должны использоваться перед и после обращением к страницам памяти с флагом User: CLAC/STAC.
                                        >Использование SMAP незначительно увеличивает размер ядра и уменьшает скорость работы.

                                        Это вообще не об этом. Запретить что-то читать и писать на жесткий диск этим не выйдет

                                        Тут надо делать поеботину примерно как в KasperskyOS https://youtu.be/zUyllpPYpXY?t=746
                                        Ответить
                                        • > Это вообще не об этом

                                          Ну я про аналогию, что супер-юзер не может лезть к данным обычного юзера и исполнять его код. Суть уязвимостей ведь абсолютно такая же -- кривой привелигированный код без причины взял что-то у юзера и неаккуратно поюзал.
                                          Ответить
                                        • Кашпировский? Да ну нах

                                          > как создать безопасный промышленный шлюз
                                          На авито за 1000 рублей купить
                                          Ответить
                                          • > как создать безопасный промышленный шлюз

                                            На помойке найти
                                            Ответить
                                  • У опёнка так примерно и сделано.

                                    Чтобы mmapнуть регион с W&X нужно иметь ключ в заголовке ELF

                                    Но с обычной FS такой бинарь не загрузится: нужно прикрутить FS со спец ключом

                                    Base system и home без такого ключа, так что там физически не может быть W&X

                                    А usr/local с таким ключом, так что в сёрд парти софте можно срать, но на продакшен сервере такого софта лучше не иметь

                                    Потому для SMTP, WWW, Perl, FTP и X11 у них свои сборки без W&X
                                    Ответить
                      • Я не могу запомнить, чем отличаются «Open», «Free» и «Net». Есть шпаргалка с различиями?
                        Ответить
                        • Open: повёрнутость на безопасности, отсутствие свистелок и пирделок (минимализм), много фишек для сети (CARP, качественный файрвол pf), очень хорошая документация в man.

                          Net: максимальная переносимость, RUMP kernel.

                          Free: максимально производительный сервер на x86, драйверов очень много, большое коммунити, хороший handbook.

                          DragonFly: максимальная многопоточность (раньше всех убрали локи в ядре чтобы использовать все ядра), своя файловая система похожая на ZFS

                          На сервере приложений логично иметь free, на роутере или бастионе Open. Остальное скорее академический интерес
                          Ответить
              • Так, походу я гоню и в дотнете нет таких фишек? Только новые классы можно нагенерить и загрузить, что совсем не будет мешать AOT'у?
                Ответить
                • Про какие фишки ты говоришь? Модификация MSIL в рантайме?


                  А хотя какая разница, в любом случае дотнет говно, как впрочем и жаба.
                  Ответить
                  • Да, модификацию существующих классов и методов в рантайме. Новые то я и в крестах могу высрать при желании.
                    Ответить
                    • > Да, модификацию существующих классов и методов в рантайме
                      Ну CLR (он же MSIL) там модифицировать можно
                      https://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time
                      И вот еще https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method

                      > Новые то я и в крестах могу высрать при желании.
                      Ты и в крестах можешь mprotect-нуть сегмент с исполняемым кодом и переписать байтики опкодов в какой-то там функции и потом эту патченную хуйню исполнять.
                      Ответить
                      • > Ты и в крестах можешь

                        Хуй там... Откуда я знаю, куда ещё конпелятор заинлайнил и заанроллил код, который я хочу запатчить?

                        А новый класс будет через VMT взаимодействовать, там всё чисто.
                        Ответить
                        • > Хуй там... Откуда я знаю, что куда ещё конпелятор заинлайнил и заанроллил код, который я хочу запатчить?

                          Для этого просто нужен особый компилятор, который будет предсказуемым образом что-то инлайнить и анроллить по какой-то строгой спецификации.
                          Ответить
                          • Ну или хотя бы оставляет какие-то таблички с пометками куда и что он инлайнил.
                            Ответить
                      • > Ну CLR (он же MSIL) там модифицировать можно

                        Ну такое...

                        В одном варианте какие-то кишки рантайма/джита пинают чтобы переджитить заново, в другом варианте нативный jmp (sic!) патчат в джит-переходнике.

                        Может быть я невнимательно читала, но выглядит как ёбаные хаки.
                        Ответить
                  • Формулировка выдаёт профессионала
                    Ответить
                • привет, в .net я могу сборку в рантайме загрузить
                  Ответить
                  • Я в Си тоже могу через dlopen-dlsym загрузить всякую фигню. Только bormand не про это спрашивала.
                    Ответить
                    • Но это сломает AOT же. А вот это точно сломает

                      https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.assemblybuilder?v iew=net-5.0
                      Ответить
                      • > Но это сломает AOT же.

                        Загрузка/генерация новых классов не ломает AOT. Старый скомпилированный код либо их вообще не увидит либо будет к ним обращаться через какие-то уже известные ему интерфейсы.
                        Ответить
                        • АОТ может заинлайнить что-то, думая что снаружи никто это трогать не будет

                          А новый класс потрогает. Да и старый может потрогать через рефлексию, и в этом случае оно разAOTится обратно кмк
                          Ответить
                          • А как это мешает?

                            Чтобы рефлексия работала я вижу джва варианта:

                            - Хранить в метаинфе для рефлексии ссылку на нативный метод. Тогда линкер его не удалит даже если все точки вызова заинлайнились и нам всегда будет что вызвать.
                            - Хранить в метаинфе оригинальный IL метода. Тогда его всегда можно воссоздать на лету и проинтерпретировать/заджитить.
                            Ответить
                            • Я думаю, что у них второй вариант, но это не точно
                              Ответить
                          • Хорошо что у меня в контроллерах нет всей этой хуйни
                            Ответить
                            • Честно говоря, если у меня на сервере или на ноутбуке это и есть, то меня это точно не ебёт.
                              Ответить
    • https://fstarlang.github.io/lowstar/html/Core.html#struct-types
      Struct types

      Flat records are part of the original paper formalization, and are translated as regular C structs.

      type uint128 = {
        low: UInt64.t;
        high: UInt64.t
      }


      typedef struct uint128_s
      {
        uint64_t low;
        uint64_t high;
      }
      uint128;


      In the original paper, structs may be allocated within buffers.

      let uint128_alloc (h l: UInt64.t): St (B.buffer uint128) =
        B.malloc HyperStack.root ({ low = l; high = h }) 1ul


      uint128 *uint128_alloc(uint64_t h, uint64_t l)
      {
        KRML_CHECK_SIZE(sizeof (uint128), (uint32_t)1U);
        uint128 *buf = KRML_HOST_MALLOC(sizeof (uint128));
        buf[0U] = ((uint128){ .low = l, .high = h });
        return buf;
      }


      Still in the original paper, one may access a buffer index, then select a number of fields.

      let uint128_high (x: B.buffer uint128): Stack UInt64.t
        (requires fun h -> B.live h x /\ B.length x = 1)
        (ensures fun h0 _ h1 -> B.live h1 x)
      =
        (x.(0ul)).high


      uint64_t uint128_high(uint128 *x)
      {
        return x->high;
      }
      Ответить
      • А теперь смотрим сюда:

        https://github.com/FStarLang/kremlin/blob/6e60e33aac1551c1ae20e4e02cb66a188935990b/include/kremlin/internal/target.h#L38
        #ifndef KRML_HOST_MALLOC
        #  define KRML_HOST_MALLOC malloc
        #endif

        Проверка на NULL после malloc()? Не, не слышали
        Ответить
        • Ня порть высокие построения математической мысли своими грязными OOMами. В чистом мире математики лента машины Тьюринга бесконечня! ヽ(o^▽^o)ノ
          Ответить
          • Тогда еще надо чтоб бесконечное адресное пространство, чтоб указатели были бигинтами
            Только зачем тогда что-то выделять в бесконечном адресном пространстве, если всю хуйню можно в бигинте хранить?
            Ответить
            • Из адреса ячейки нельзя читать, его можно только для адресации использовать вроде
              Ответить
    • Хуйня, симпл-димпл «Nim» круче.
      Ответить
      • А в «Nim» есть "requires" и "ensures"?
        Ответить
        • Нет, т.к. они не нужны. Ты бы ещё спросил, есть ли в «Nim» та питушня из «Rust».
          Ответить
          • Почему не нужны? А если я хочу на этапе компиляции проверять такую хуйню, что мне делать в случае с "Nim"?
            Ответить
    • Там ещё компилятор называется КРЕМЛИН, то есть гологубу бы не понравился такой язык. Да и мне тоже.
      Ответить
      • А может, это в честь Путивльского кремля названо?
        https://ru.wikipedia.org/wiki/Путивльский_кремль
        Ответить
        • Путлерского
          https://img.tsn.ua/cached/914/tsn-65e5f602e5840498ead47d2707d23e52/thumbs/1200x630/bb/75/2524db20ca99bb936092340d30ed75bb.jpg
          Ответить
          • а справа путивльская реальность – зарешеченная помойка и целых 2 аптеки
            Ответить
      • https://coub.com/view/x8ei
        Ответить
    • let b: B.buffer UInt32.t = B.alloca 0ul 8ul in

      Какой понятный синтаксис )))
      Ответить

    Добавить комментарий