LINUX.ORG.RU

rust, безопасность и разбор сетевых пакетов

 


0

5

Не пойму такой вещи в безопасном расте. Типичный сценарий: сервер (или клиент - не суть важно) получает по сети поток байтов, и должен сформировать пакет. Например, какой-то очень простой протокол:

клиент, запрос: |1|длина_тела|тело|

сервер, ответ: |2|длина_тела|тело|

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

Клиент делает такую штуку: кладёт в тело 10 байт, а в длине_тела указывает какое-нибудь 10000. Сервер всё это принимает, но программист сервера забыл сделать проверку, что длина_тела <= длина(тело) (того, что реально получено в езернет кадре, например). Объекта типа «пакет» ещё нет на сервере, и нет массивов, длину которых может проконтролировать рантайм, эти массивы структуры данных только конструируются из фактически бестипового потока байтов. Т.е. делается просто копирование длина_тела байт из тела, сервер залезает в какие-то свои кишки на стеке, и отправляет всё это клиенту. А там пароли, криптографические ключи, коды запуска ракет, …

Как раст защитит программиста сервера от такого сценария?

★★★★★

Последнее исправление: seiken (всего исправлений: 1)

Как раст защитит программиста сервера от такого сценария?

Святой водой и молитвой, очевидно.

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

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

то при попытке считать за границами массива вылетит ошибка.

если опуститься на самый нижний уровень, когда результат системного вызова ОС передается в код на расте, массива раста ещё нет, он конструируется из сишного массива, и вот я забыл проверить длинну пришедшего пакета и соотв. сишного массива, а смотрю только на передаваемое клиентом поле длины.

seiken ★★★★★
() автор топика

https://doc.rust-lang.org/std/net/struct.TcpStream.html#impl-Read-for-%26TcpStream

Ты в read передаёшь свой буфер известного размера и тебе больше чем ты сам выделил в него не запишут.

Не, если ты сам себе выстрелишь в разные места и через transmute и unsafe сколхозишь мутный указатель на буфер - есть шансы, но разговор же ж не об этом.

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

на всех сисколах read, write, send, recv, и т.п. вместе с указателем обязательно передается длина буфера и для чтений возвращается сколько собственно прочитало. Стандартная библиотека делает акуратно обертки над этими вызовами что в безопасном коде никогда за память не выйдешь как бы не старался.

pftBest ★★★★
()

В пределах твой программы на расте такое не должно быть возможно без unsafe. Но если, условно, ядро говорит мол «вот пакет, его размер 1000 байт, начиная с этого адреса», а на самом деле там ничего нет, или есть, но не 1000 байт, а меньше, то здесь раст тебе никак не поможет, потому что проерить, соврало ли ядро - невозможно.

anonymous-angler ★☆
()

У тебя какая-то каша в тексте. И скорее всего такая же каша в мыслях (иначе откуда взяться каше в тексте?). Оттуда и все проблем

Агрессивнй пиар раста я не одобряю и сам не собираюсь с ним иметь дело, но конкретно тут не прав ты.

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

Результат системного вызова возвращает в том числе и длину возвращёных данных, которые, кстати, заведомо не длинне чем предоставленный системному вызову заранее выделенный буфер. Я практически уверен, что все эти длины там не болтаются сами по себе, а учтены в растовской обёртке над вызовом. А поле длины, переданное клиентом, это уже логика верхнего уровня, которая ко всем этим деталям никакого отношения не имеет.

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

Я практически уверен, что все эти длины там не болтаются сами по себе, а учтены в растовской обёртке над вызовом.

Да, это прекрасно. Это что-то типа libc, но уже на расте, и оно соорудит безопасный растовский буфер. Но, допустим, я пишу кастомный код для МК, и у меня нет стандартной библиотеки. И не заморачиваюсь универсальными оберткам к recv/send. Тогда в любом случае в каком-то месте будет unsafe, в котором я забуду необходимую проверку.

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

unsafe сколхозишь мутный указатель на буфер - есть шансы, но разговор же ж не об этом.

Об этом. Хотя в общем, идея, что unsafe часть кода очень небольшая по сравнению с Safe, и небольшую часть можно как следует проверить на ошибки, вполне здравая, зачётная.

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

Так ты и на си забудешь.

Так это как раз реальный пример «из жизни С».

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

Так вот я и разбираюсь. Гораздо лучше, когда подсказывают эксперты.

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

Хотя в общем, идея, что unsafe часть кода очень небольшая по сравнению с Safe, и небольшую часть можно как следует проверить на ошибки

That’s the point, поэтому так делать не стоит:

И не заморачиваюсь универсальными оберткам к recv/send. Тогда в любом случае в каком-то месте будет unsafe, в котором я забуду необходимую проверку

theNamelessOne ★★★★★
()