LINUX.ORG.RU

Анонсирован первый конкурс недобросовестного программирования на Rust

 


4

9

Команда Rust анонсирует первый ежегодный конкурс «недобросовестного Rust» по мотивам существующих конкурсов «недобросовестного C» и «недобросовестной криптографии».

Задача Rust — сделать доступным написание безопасного низкоуровневого кода, защищённого от случайных уязвимостей. Меньше времени уделяется возможности Rust защитить от умышленного внедрения уязвимостей при бдительном обзоре кода. Конкурс предназначен для обнаружения и устранения возможных слабостей языка и его экосистемы. Иными словами, авторы просят вас сломать систему с помощью достаточно лёгкого для понимания кода. Можете ли вы написать полностью safe-Rust, скрывающий логический баг, или скрыть в unsafe-Rust уязвимость, которая не обнаружится при обзоре кода?

>>> Подробности

anonymous

Проверено: Shaman007 ()
Последнее исправление: sudopacman (всего исправлений: 2)

Ответ на: комментарий от atrus

А по активности на форуме не скажешь.

Может работа как раз в этом и заключается.

mashina ★★★★★
()

А призовые места там есть?

jori
()
Ответ на: комментарий от kto_tama

В расте чтоб навернутся достаточно сделать unwrap() на None, что благополучно и совершается многими ленивыми задницами на этом языке. Жалко только что это не сегфолт и свой машинный код туда не подсунешь.

q0tw4 ★★★★
()
Ответ на: комментарий от q0tw4

В расте чтоб навернутся достаточно сделать unwrap() на None

Но ведь ты не можешь сделать unwrap на ().

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Там вполне конкретная задача, реализовать небольшой платежный бэкенд, который будет осуществлять salami slicing (уводить мелкие копейки на счёт атакующего) так, чтобы это прошло аудит. Рекомендую посмотреть что было на underhanded c, чтобы получить примерное представление.

ТС написал кучу фигни, но о сути не написал чуть менее, чем ничего.

grossws
()
Ответ на: комментарий от q0tw4

Задача не написать падающую программу, а сделать определенное действие (украсть денег) так, чтобы аудит кода не выявил этой проблемы.

grossws
()
Ответ на: комментарий от grossws

Задача не написать падающую программу

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

q0tw4 ★★★★
()

Проверено: Shaman007

anonymous
()

Лень создавать тему ради таких глупостей. Подскажите, правильно, я понимаю?

struct Ouroboros{
    ...
}

impl Ouroboros {
    fn eat_himself(self) { ... }
}

Что после вызова метода, объект перестанет существовать? Зачем это может понадобиться?

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 4)
Ответ на: комментарий от makoven

По умолчанию перестанет, это move-семантика. Но если реализовать (или сделать derive) trait Copy, то будет в функцию уедет копия.

Обычно это актуально для деструктивных операций над объектом с передачей владения.

grossws
()
Ответ на: комментарий от grossws

Обычно это актуально для деструктивных операций над объектом с передачей владения

Спасибо. Но все-равно непонятно зачем. Объект же сам помрет по выходу из скопа, безо всяких деструктивных операций

Но если реализовать (или сделать derive) trait Copy, то в функцию уедет копия

синтаксис определения eat_himself и вызова метода при этом не изменится?

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 2)

И еще пока обмазывался туториалами, где-то проскакивала такая конструкция: foo(&12). Подскажите, чем она отличается от foo(12)?

makoven ★★★★★
()
Ответ на: комментарий от makoven

Но все-равно непонятно зачем. Объект же сам помрет по выходу из скопа, безо всяких деструктивных операций

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

синтаксис определения eat_himself и вызова метода при этом не изменится?

Не должен

grossws
()
Ответ на: комментарий от makoven

И еще пока обмазывался туториалами, где-то проскакивала такая конструкция: foo(&12). Подскажите, чем она отличается от foo(12)?

Для примитивов-то зачем о_О. foo(&bar) используется для заимствования (borrow) объекта.

Рекомендую The Book, там всё довольно подробно описано. Есть русский перевод.

grossws
()
Ответ на: комментарий от grossws

Например, для построения нового объекта на основе частей старого

О, точно. Отличное применение

makoven ★★★★★
()
Ответ на: комментарий от grossws

Это из официального блога https://blog.rust-lang.org/2015/05/11/traits.html

Там дженерик компилится в

print_hash(&12_i64);
. Просто интересно, отличается ли оно от
print_hash(12_i64);

makoven ★★★★★
()
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Напиши - приз получишь.

Смеяцца будут. Насколько я помню:

1. Написать на safe Rust интерпретатор языка, дающий полный доступ к фс/системе (возможно из-за логической ошибки) 2. Скормить этому интерпретатору небезопасный скрипт. 3. ... 4. Rust скомпрометирован.

red75prim ★★★
()
Ответ на: комментарий от CARS

помойму Rust имеет лучший дизайн именно фич языка, набора хороших практик, чем всё что сейчас есть на эту тему

stevejobs ★★★★☆
()
Ответ на: комментарий от h4tr3d

пробовал брать типичные ынтерпрайз-приложения на java и менять ArrayList на LinkedList (+нестандартный свой связный список, ради чего и был тест). Удивительное рядом: производительность не выросла ни разу, обычно проседала раза в 1.2 , а в паре мест упала более чем в 3 раза.

Т.е. вместо того, чтобы городить велосипедные линкед-листы, можно просто один раз потырить реализацию arraylist из джавы, включая сортировку с помощью timsort, и потом использовать её просто везде

stevejobs ★★★★☆
()
Ответ на: комментарий от stevejobs

Так не удивительно :) Начинаешь стрелять по разным местам памяти даже при обычном прямом переходе. ArrayList и Vector в Java это, по сути, аналоги std::vector в C++ - сами данные хранятся в виде обычного массива (насколько он solid в пределах JVM - я не знаю). Vector только синхронизирован для работы с ним из нескольких потоков. Понятно, что если у тебя меньше промахов по кешу, которые практически неизбежны в случае связного списка, то и быстродействие выше. Плохо случается только когда место кончается и нужно переаллокацию делать + копирование, особенно когда данных уже много. Поэтому - reserve() в помощь. Или использовать дек, как компромисс.

h4tr3d ★★★★★
()
Ответ на: комментарий от h4tr3d

Пытаюсь проследить ход мысли:

1) h4tr3d сказал:

Ну там и связный список без unsafe не сделаешь

2) stevejobs ответил
что связные списки нафиг не нужны, arraylist хватит всем. (и соответственно unsafe тоже не нужен)

3) на что h4tr3d ответил:

Так не удивительно :)

Где логика?

pftBest ★★★★
()
Последнее исправление: pftBest (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

у вас обоих так горит от раста

Я на самом деле не из тех, у кого горит. И вообще я большой любитель маргинальных ЯП, в частности интересовался dependent types немного. Но не нравится мне, когда защищающий от ошибок компилятор не шибко понятливый. Впрочем я понимаю, что описать стандарт, суждение которого о корректности программ соответствует тому, что делает мозг человека, нереально. Так что я за развитие статического анализа в применении к динамически типизированному языку (с возможностью явного указания типов по желанию конечно).

q0tw4 ★★★★
()
Ответ на: комментарий от q0tw4

Впрочем я понимаю, что описать стандарт, суждение которого о корректности программ соответствует тому, что делает мозг человека, нереально.

И не нужно. Человеческий мозг — говно, когда нужна точность и надёжность.

anonymous
()
Ответ на: комментарий от h4tr3d

Начинаешь стрелять по разным местам памяти даже при обычном прямом переходе. ArrayList и Vector в Java это, по сути, аналоги std::vector в C++ - сами данные хранятся в виде обычного массива (насколько он solid в пределах JVM - я не знаю).

Vector давно не рекомендуется использовать (как и, например, Hashtable). В памяти массив на знакомых мне реализациях jvm лежит непрерывно. Вполне вероятно, что в jvms есть на это требование.

grossws
()
Ответ на: комментарий от pftBest

Где логика?

У вас — в нигде. Из того, что unsafe не нужен для связанного списка никак не следует то, что он не нужен вообще.

grossws
()
Ответ на: комментарий от makoven

Зачем это может понадобиться?

Всякие билдеры, например.

Но вообще self - это просто параметр. То есть, это стоило бы сделать просто для единообразия, ведь обычные параметры иногда удобно отдавать/перемещать.

DarkEld3r ★★★★★
()
Ответ на: комментарий от pftBest

Где логика?

А она вам нужна? Тогда попробуйте мысленно поставить смайлик в исходном сообщении. Согласен, выглядит как-то так.

Против Rust ничего не имею, хотя близко с ним не знакомился, по причине отсутствия необходимости и свободного времени, которое некуда девать. Но единственное, что у меня вызвало отторжение при беглом знакомстве - это его синтаксис (хуже только шаблонная магия в плюсах /хотя и читаю и пользуюсь и сам заклятия сочиняю/ или конкретная перловка). Но это вкусовщина и субъективизм чистой воды - в случае необходимости, это не будет проблемой.

Структуры же данных должны выбираться по задаче и целевой платформе. Работаете в каком-то baremetal с выключенным кешем по данным или с областью памяти, которая через MMU отмечена как uncached (часто всяким DSP такую отдают), то и запары с промахами нет, а если память ещё и сильно фрагментирована (хотя, обычно, где это критично, использование памяти достаточно детерминировано и её вообще можно сразу порезать), то связный список или дек тут то, что дохтур прописал - распихать ноды (или чанки) по свободным кусочкам памяти. Вернулись на PC, то уже как бы и повнимательнее нужно быть. В любом случае, лично я, сначала буду использовать решения из стандартной библиотеки, не устраивает - популярной сторонней, снова не устраивает - ну тогда может в компании есть какие-то наработки, и опять мимо - что делать, буду писать сам. А ещё - пользоваться профилировщиком и исправлять только те месте, где действительно есть просадки по проивзодительности.

Да и собственно, как будет внутри реализована безопасная снаружи абстракция, выполненная с минимальным (или без оного) оверхеда - глубоко без разницы. Тут выше накидали уже вариантов как обойтись без unsafe в случае списка. Не берусь оценивать с точки зрения удобства, накладных расходов и прочего, но раз можно - значит можно.

Вообще, если в хлебоносном для меня ЦПП мысленно ввести понятия safe/unsafe, львиная доля существующего кода окажется именно во второй секции, ведь даже, казалось бы, ссылки, призванные защититься от ошибок с указателями, внезапно и ненавязчиво могут оказаться висячими. То, с чем в C++ пытаются бороться хорошими практиками, в Rust делают средствами компилятора и явно определяют границы дозволенности. Вот только, что C, что C++ пытаются быть везде и им это, так или иначе, удаётся как раз благодаря некоторым обтекаемым формулировкам в стандарте. Меня бы ввело в замешательство, то, что на платформе, где байт 10 бит имя типа u8 уже не отражает своего содержимого (лет 12 назад с подобной платформой столкнулся).

Плюс сложные вещи, типа OS, будут требовать использования unsafe (да что OS: coreutils, util-linux /хотя тут всё достаточно гладко/), а тут уже спрятаться проблемам будет проще (можно ещё перебрать этот список на предмет использования unsafe, но у меня столько времени нет).

Резюмируя: не в списке дело, а unsafe не так редко нужен, как хотелось бы и писать г-но можно на любом ЯП.

Ну... теперь, надеюсь, логики добавилось :)

h4tr3d ★★★★★
()
Последнее исправление: h4tr3d (всего исправлений: 1)
Ответ на: комментарий от grossws

Vector давно не рекомендуется использовать (как и, например, Hashtable).

Всё течёт, всё меняется.

В памяти массив на знакомых мне реализациях jvm лежит непрерывно.

Правило наименьшего удивления в действии. Да и с JNI лучше стыкуется.

h4tr3d ★★★★★
()
Ответ на: комментарий от makoven

Оказывается еще есть один Self (с большой буквы)

Ага и я предпочитаю использовать его вместо явного указания типа, там где это возможно.

DarkEld3r ★★★★★
()
Ответ на: комментарий от h4tr3d

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

И что? Ты серьёзно пишешь код, который ожидает, что ссылка может оказаться невалидной? Как по мне, это никакого отношения к unsafe не имеет.

DarkEld3r ★★★★★
()
Ответ на: комментарий от q0tw4

Так что я за развитие статического анализа в применении к динамически типизированному языку

Ээ? Чем это должно отличаться от статичной типизации?

anonymous
()
Ответ на: комментарий от DarkEld3r

Нет, я пишу код, который, по возможности, в такой ситуации приведёт к ошибке компиляции. Т.е. иногда чуточку ума у компилятора не хватает, и приходится ему помогать. Это не защищает и не может защитить от целенаправленного желания самоубиться как-то так:

void some_proc(const Foo& foo) { /*что-то делаем с foo*/ }
...
auto const& badfoo = *reinterpret_cast<const Foo*>(0);
some_proc(badfoo);

Но посыл был в другом: многие обыденные вещи в C++, если подумать, не так безопасны. Пример с висячими ссылками может не вполне удачен, а вот с операторами присваивания и конструкторами копирования по-умолчанию - это уже более приземлённый сценарий: по сути, без их принудительного запрещения по-умолчанию, код уже - unsafe. Или же с разрешёнными, по умолчанию, new/delete. Или же... в общем - придумать много можно. Сам же понимаешь, что тут будет:

struct Foo {
  Foo() {
    ptr = new char[256];
  }

  ~Foo() {
    delete[] ptr;
  }

  char *ptr;
};
...
Foo f0;
Foo f1;
f1 = f0;

Отсюда и правила трёх, а потом и пяти возникают. А следом и правило нуля.

А если в коде случайно забыть и просто delete написать, а не delete[]?

h4tr3d ★★★★★
()
Ответ на: комментарий от h4tr3d

Но посыл был в другом: многие обыденные вещи в C++, если подумать, не так безопасны.

Дык, зачастую они небезопасны именно из-за того, что в языке нет нормального разделения на «безопасное» и нет.

DarkEld3r ★★★★★
()
Ответ на: комментарий от h4tr3d

а unsafe не так редко нужен

Примеры есть? Большинство кода на раст без unsafe. unsafe только в биндингах и железяках.

RazrFalcon ★★★★★
()
Ответ на: комментарий от anonymous

Чем это должно отличаться от статичной типизации?

Гибкостью правил. Запрещено только то, для чего доказано, что существует юзкейс, при котором оно точно упадет (в смысле не обработанный эксепшен или сефолт) или зависнет. Недоказуемые случаи подсвечены желтым цветом. Где возможно выведен тип. Где нет - работает динамика. Удобно, блин. И никаких «я это не скомпилю только потому, что правила типизации запрещают и мне плевать, работало бы оно в duck typing или нет».

q0tw4 ★★★★
()
Ответ на: комментарий от RazrFalcon

Пытаюсь понять мотивы.

Кинофильм снят по мотивам книги Cаши Грина «Алые паруса». В Астане (столице Казахстана) имеется компьютерный магазин «Белый ветер». :-)

anonymous
()
Ответ на: комментарий от anonymous

Люди уже огромное множество раз обыгрывали компьютер в шахматы. Сами можете попробовать...:-)

anonymous
()
Ответ на: комментарий от h4tr3d

Человек предполагает, а Бог располагает. :-)

anonymous
()
Ответ на: комментарий от RazrFalcon

Ну я немного примеров выше привёл. И как бы язык позиционируется как низкоуровневый (в хорошем смысле слова :)), и безопасности, тем более в реализации ядра, хотелось бы побольше ;)

h4tr3d ★★★★★
()
Ответ на: комментарий от h4tr3d

Он достаточно низкоуровневый, чтобы убрать сишку с десктопа, но не с 8-и битных контролеров.

Какие гарантии безопасности вам нужны, если вы дёргаете ASM код?

RazrFalcon ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.