Няшная / Говнокод #26736 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  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
#include "gc.h"

static bool PointerNotOwnedByParentStackFrame(struct StackFrame *frame,
                                              struct StackFrame *parent,
                                              void *ptr) {
  return !(((intptr_t)ptr > (intptr_t)frame) &&
           ((intptr_t)ptr < (intptr_t)parent));
}

/**
 * Adds destructor to garbage shadow stack.
 *
 * @param frame is passed automatically by wrapper macro
 * @param fn takes one argument
 * @param arg is passed to fn(arg)
 * @return arg
 */
void __defer(struct StackFrame *frame, void *fn, void *arg) {
  struct StackFrame *frame2;
  if (!arg) return;
  frame2 = __builtin_frame_address(0);
  assert(frame2->next == frame);
  assert(PointerNotOwnedByParentStackFrame(frame2, frame, arg));
  if (append(&__garbage, /* note: append() not included */
             (&(const struct Garbage){frame->next, (intptr_t)fn, (intptr_t)arg,
                                      frame->addr})) != -1) {
    frame->addr = (intptr_t)&__gc;
  } else {
    abort();
  }
}

deferы в Сищечке

https://gist.github.com/jart/aed0fd7a7fa68385d19e76a63db687ff

Запостил: 3.14159265 3.14159265, (Updated )

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

  • Стековый «сбощик мусора›
    #ifndef GC_H_
    #define GC_H_
    
    #define gc(THING) defer(free, (THING))
    
    /**
     * Calls FN(ARG) when function returns.
     */
    #define defer(FN, ARG)                            \
      ({                                              \
        __typeof(ARG) Arg = (ARG);                    \
        /* force -fno-omit-frame-pointer and */       \
        /* prevent weird opts like tail call */       \
        asm("" : "+g"(Arg));                          \
        __defer(__builtin_frame_address(0), FN, Arg); \
        asm("" : "+g"(Arg));                          \
        Arg;                                          \
      })
    
    struct StackFrame {
      struct StackFrame *next;
      intptr_t addr;
    };
    
    struct Garbages {
      size_t i, n;
      struct Garbage {
        struct StackFrame *frame;
        intptr_t fn;
        intptr_t arg;
        intptr_t ret;
      } * p;
    };
    
    extern struct Garbages __garbage;
    
    int64_t __gc(void);
    void __defer(struct StackFrame *, void *, void *);
    
    #endif /* GC_H_ */
    Ответить
  • &(const struct Garbage) { ... }

    Это с какой версии такой изврат можно делать? Пиздец, почему просто локалку не заполнить над вызовом?
    Ответить
    • И всё ради того чтобы анскильные питушки могли написать fclose не в конце файлика, а defer в срединке.
      Ответить
      • А как они кстати конец функции ловят чтобы мусор чистить?
        Ответить
            • Ну вот примерно такое ебанатство придётся тащить в каждую реализацию Сишки, если примут предложение.

              А ещё питушение с longjmp.
              Ответить
          • > переписывают адрес разврата

            Т.е. со всякими защитами от нарушения control flow этот код несовместим? Заебись фича. Хуже были только гццшные "лямбды", которые вообще исполняемый стек требовали.
            Ответить
            • Да простейший флаг omit-frame-pointer вынесет его нахуй.

              > Хуже были только гццшные "лямбды", которые вообще исполняемый стек требовали.
              Лолчто???
              Ответить
              • Они на стеке генерят переходник и возвращают его адрес.
                Ответить
                • Это же attack-friendly-programming.

                  Можно же просто насрать в стек своим юзер-инпут говном, а потом порушить всё нахуй.
                  Ответить
                  • Вспомнил реальный пример attack-friendly-programming:
                    https://govnokod.ru/19017

                    В 64-битном «MSVC» нет встроенного асма. Что предложил автор примера? Он предложил положить мышиного кота в строковую инициализированную переменную и снять атрибут «no execute» у страниц, в которые попало это значение.
                    Ответить
                    • Ну тогда уж в отдельную RX секцию можно отправить эту строку. Один фиг под конкретный конпелятор.
                      Ответить
                      • Можно. На платформах, на которых можно создать эту секцию. У «Portable executable» («Windows», например) и у «ELF» нет проблем. А на какой-нибудь «Макоси» можно обломаться.
                        Ответить
                      • Кстати, если мы пишем модуль для «EFI»/«UEFI», то можно пользоваться всеми фишками формата «PE» или есть ограничения?
                        Ответить
                        • Ну там как минимум импортов и экспортов нет. И атрибуты на секциях только недавно стали учитывать, раньше все как RWX грузили.
                          Ответить
                            • Да ладно, в виндовом ядре буквально лет 5 назад тоже был полный RWX.
                              Ответить
                                • Да ладно, в «DOS» буквально лет 30 назад тоже был полный RWX.
                                  Ответить
                                  • Как будто в «DOS» сейчас не полный RWX... Хотя в программах для DPMI (в том же «Doom» и в «Duke Nukem») можно установить защиту (когда их писали, не было процессоров с аппаратной поддержкой флага NX, но от записи страницу кода защитить было можно).
                                    Ответить
                              • а когда починивать начали? Когда все перешли на x64?
                                Ответить
                                • Аппаратное «DEP» на «Интелах» впервые появилось на x64.

                                  В «Windows» поддержка «DEP» появилась в «Висте», но по дефолту была отключена для пользовательских программ, потому что с «DEP» старое говно может не работать.

                                  Удобной настройка исключений «DEP» в «Windows» стала, когда появилось средство «EMET»:
                                  https://en.wikipedia.org/wiki/Enhanced_Mitigation_Experience_Toolkit

                                  P.S. А, он про ядро, а не про юзерспейс.
                                  Ответить
                                • То есть юзерспейс они защитили, а в ядре защиты долгое время не было в надежде, что драйвера гадить системе не будут?
                                  Ответить
                                  • Ну видимо да.
                                    Драйверы все таки подписанные, да они и так могут всё сломать
                                    Ответить
                                • Начали где-то с восьмёрки, но всем было похуй.

                                  А реально прижали всех к стенке на десятке когда HVCI запилили, насколько я помню.
                                  Ответить
                                    • Анальный гипервизор, который не разрешает ядру исполнять неподписанный код.
                                      Ответить
                                        • Помимо минус первого кольца, кстати, в дивном новом мире существует и минус второе третье, называется «Intel ME» («AMD PSP» для любителей красного).
                                          UPD: оказывается, минус второе — это «System Management Mode».
                                          Ответить
                                          • Ну ME это всё-таки не кольцо, а отдельный большой брат, который без основного проца работать может.
                                            Ответить
                                            • В общем-то и другие отрицательные кольца — не совсем «кольца» в «классическом» смысле. Тут скорее речь про привилегии и возможности воздействия.
                                              Ответить
                                                • Смотря в каком месте. Если, к примеру, ты попадёшь на ночную тусовку любителей x86, то про «CPL».
                                                  Ответить
                                                  • >тут скорее речь про привилегии
                                                    >CPL

                                                    Расшифруй мне пожалуйста выделенную жирным букву
                                                    Ответить
                                                    • Что тебе не нравится? В «x86» есть только четыре «стандартных» — определяемых CPL — кольца, а все отрицательные кольца — понятия не строго технические, а эмпирические.
                                                      Гипервизор, например, считается минус первым кольцом, «SMM» — минус вторым, «Intel ME» — минус третьим. Однако, повторюсь, это больше эмпирическое разделение по принципу «кольцо N имеет произвольный доступ к кольцам N+i, кольцо N не может влиять на кольца N-i больше дозволенного этими кольцами». Что именно считать отрицательным «кольцом» — вопрос философский. Физический мир, например, можно записать в минус четвёртое: компьютер может влиять на окружающую среду только через строго определённые механизмы, в то время как окружающая среда может воздействовать на компьютер как угодно.
                                                      Ответить
                                                      • Мне не нравится, что ты противопоставил Code Privilege Level привилегиям. И то и другое привелегии же.

                                                        Формально SMM, Hypervisor, и кстати v86, не являются "кольцами", хотя суть у них та же.


                                                        Привилегии виртуализировать ресурсы, привилегии обрабатывать чужие ошибки, привелегии прерывать чужой код
                                                        Ответить
                                                        • Я противопоставил кольца «технические» (0-3) кольцам «философским» — отрицательным.
                                                          «Технические» кольца (по крайней мере, в «x86») определены строго: через CPL. «Философские кольца», в свою очередь, чисто эмпирические: все просто договорились считать гипервизор минус первым кольцом, например. С тем же успехом его можно записать в минус десятое (SMM — -11, etc.), от этого смысл не изменится.
                                                          Ответить
                                                          • Наконец я тебя понял.
                                                            Ты предлагаешь не считать кольцом то, чей номер не может быть записан в CPL?
                                                            Ответить
                                                            • Нет, я предлагаю просто разделять кольца как техническое решение (CPL, например) и кольца как философское понятие (гипервизор, «SMM», окружающая среда).
                                                              Ответить
                                          • ME — это вообще отдельный процессор. ME первого поколения был на рахиттинктуре «ARC», а ME второго поколения — уже на x86 (80386 или типа того).

                                            SMM (минус второе кольцо) точно был на всех 80486, а также на каких-то 80386, только он, кажется, раньше не был документирован, кто-то случайно раскрыл опкод для переключения в SMM.
                                            Ответить
                                            • Да, SMM был нужен кажется изначально для APM (в эпоху до ACPI) чтобы усыплять комп при длительном бездействии (например при презентации, лол) или еще что-то такое же бессмысленное делать.

                                              Через SMM комп пыталась поломать Йоанна Рутковская
                                              Ответить
                                      • а, помню эту тему. теперь у нас сама винда в виртуалке
                                        Ответить
              • У Борманда неточность: не лямбды, а замыкания.

                В «gcc» вложенные функции работают как замыкания, захватывая все локальные переменные и аргументы родительской функции.

                Зачем-то добавили фичу: на вложенную функцию можно взять указатель. Чтобы по этому указателю вложенную функцию можно было вызвать, придумали «трамплины»: это такой короткий код, который передаёт вызываемому замыканию указатель на контекст. Так вот авторы не придумали ничего лучше, чем создавать этот трамплин в стеке. Поэтому со всех страницы стека приходится снимать атрибут «no execute», иначе трамплин не вызовется.
                Ответить
                • Всё верно.
                  Лямблия просто онанимная функция. Она может зохватывать кого-то, а может и не зохватывать.
                  Замыкание же всегда зохватывает, но может быть и не онанимной.

                  "use strict";
                  
                  let someVar = 42;
                  
                  (() => {
                      console.log("Lambda, not closure");
                  }).apply();
                  
                  function closureNotLambda() {
                      console.log(`Closure, not lambda ${++someVar}`);
                  }
                  
                  closureNotLambda();



                  > Поэтому со всех страницы стека приходится снимать атрибут «no execute»

                  М-да, в base-system OpenBSD бы вас не приняли: там W^X
                  Ответить
                    • Есть. Для того, чтобы сказать _WRITE и _EXEC одновременно, нужно иметь спец ключик в заголовке (то-есть верно слинковаться).

                      А с этим ключиком тебе не дадут запуситься, если FS не прикручена со спец ключом. А ключ не стоит у раздела с base system.

                      Таким образом, в base system такого кода быть не может
                      Ответить
                        • В PHP такого действитлеьно нет.

                          PHP ставится в другой раздел (/usr/local/), не является частью базовой системы, и потому может хоть все страницы пометить как RWX, всем насрать.

                          Тео и Ко гарантируют безопасность и безбажность только базовой системы. Охуилон портов всякого говна они, разумеется, не могут проверить.
                          Ответить
            • Можно играть: пишешь говно в стек, и стараешься сделать так, чтобы при джампе туда вываелась какая-нить хирня
              Ответить
                • Здраствуйте. Я Noodles. Хочу чтобы вы сделали шеллкод, return-oriented-экшон. Суть токова... Можно напихать в стек адресов, содержащих нужные инструкции и данные, инструкции ret набигают и составленный в стеке шитый код исполняется. Можно заражать программы...

                  PS. я джва года жду такой шеллкод.
                  Ответить
                  • Да с исполняемым стеком можно и обычного кода напихать, без этого вашего ROP. Пачку nop'ов в начало и поехали.
                    Ответить
          • Ебать, Бедный ГЦЦ.
            Эти люди еще над SEH смеялись.
            Ответить
    • А чо не так, у структуры созданной из составного литерала нельзя адресс брать или шо.

      Вроде обычный C99.
      Ответить
      • Я так понимаю, что структуру инициализировали, и сразу взяли адрес. Это немного необычно.
        Ответить
          • gcc работает, а vc нет
            struct Garbage
            {
            	int i;
            };
            
            
            void foo(struct Garbage* a)
            {
            	a->i = 12;
            }
            
            int main()
            {
            	foo(&(struct Garbage){.i = 12});
            	return 0;
            }


            Видимо потому, что vc не умеет c'99.

            А где будет создаваться структура, кстати? на стеке мейна, просто неявно?
            Ответить
            • vc ВООБЩЕ НЕ УМЕЕТ сИ, УБЕРИ НАХУЙ ЭТО ГОВНО ОТСЮДА.

              в ТВОЕМ ПРИМЕРИ МОЖЕТ БЫТЬ НА СТЕКЕ, ЛИБО В СЕКЦИИ С КОНСТАНЦИЯМИ, ЛЕНЬ ИСКАТЬ В СТОНДАРТЕ. я, СОБСНО, ИСПОЛЬЗОВАЛ ЭТУ ФИЧУ С ГЛОБАЛЬНЫМИ КОНСТАНТАМИ, КОГДА СВЯЗНЫЕ СПИСКИ СТРОИЛ, ЧТОБЫ НЕ ДЕЛАТЬ ЛИШНИХ ОБЪЯВЛЕНИЙ.
              Ответить
              • VC умеет C90.
                Помню, что оно не умеет VLA, лол.
                Да, если оно const, то наверное можно его в константы, а иначе наверное на стеке.

                В общем неождианно, что такое есть в си, но правда удобно
                Ответить
  • Белый, белый, белый си, кобень за плечами.
    Белый, белый, белый си, снится мне ночами.
    Белый, белый, белый пи, анскильные птицы.
    Белый, белый, белый си, мне ночами снится.
    Ответить
  • Анскильный питух, жара, июнь
    Вореции такие сложные
    Только ты не пушишь никому
    Ждёшь ты только стека, стека, стека
    Ответить
    • Если же говорить по поводу самого кода, то это ненужные костыли, к тому же завязанные на гнутые расширения.
      Ответить
    • так он был пацаном, когда чото там насрал в подростковой игрушке, а потом решил девочкой-леваком стать?
      Ответить
      • Я был когда-то странным
        Разрабом безымянным
        Которому реквестов
        Никто не заведёт
        Теперь я трансоняшка
        Мне каждая дворняжка
        При встрече сразу
        Лапу подает!
        Ответить
    • Если программистов стали делить по сексуальной ориентации, значит, сексуальная ориентация влияет на качество кода?
      Ответить
          • На ARM можно менять не только endianess. У них ещё сетку инструкций менять можно: «thumb» и тому подобное.
            Ответить
            • Не у всех. На контроллерах, к примеру, только thumb2 обычно чтобы флешку не тратить.
              Ответить
              • Какой багор )))

                А есть ещё процессоры с переключателем набора инструкций типа «ARM» или «NEC V20»?
                Ответить
                    • Действительно. Когда ещё был x86_32, там в разных режимах различались только размеры непосредственных констант (два байта или четыре), а в 64-битном режиме x86_64 куча инструкций поехала: удалили однобайтовые инкременты/декременты, чтобы освободить место под REX-префиксы.
                      Ответить
          • У «NEC» были девайсы «V20» и «V30», которые в обычном режиме исполняли инструкции 8086/8088, но был ещё режим исполнения инструкций 8080, причём во время прерывания режим корректно переключался.
            Ответить

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

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8