Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 31.03.18 05:46
Оценка:
есть проект в котором есть один главный процесс и куча дочерних
они ессно меж собой должны взаимодействовать, причем активно гоняя кучу данных
при этом дочерние процессы не должны иметь никакой возможности убить главный

классически это делается через сериализацию

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

а нельзя ли както сделать так чтобы код, который общий, был в расшареном сегменте, т.е. был замаплен во все дочерние процессы и был при этом доступен для них только на вызов
чтобы дочерний процесс не мог покоцать ни расшареный код, ни его данные
и чтобы можно было общаться с ним через с/с++ интерфейсы например, т.е. без всех этих 0-to-3 ring переходов

может user-mode драйвера както тут помогут? не знаю пока что они могут, но расшаренный код должен иметь все возможности обычного user-mode режима

было бы очень странно если бы такой возможности не было, потому как сериализовать/ждать/десериализовывать там де нужен простой потокобезопасный вызов кажется мне большой печалью и геморроем
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Отредактировано 31.03.2018 5:49 Barbar1an . Предыдущая версия . Еще …
Отредактировано 31.03.2018 5:48 Barbar1an . Предыдущая версия .
Re: Мультипроцессный защищенный код
От: okman Беларусь https://searchinform.ru/
Дата: 31.03.18 06:45
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>...

B>а нельзя ли както сделать так чтобы код, который общий, был в расшареном сегменте, т.е. был замаплен во все дочерние процессы и был при этом доступен для них только на вызов
B>чтобы дочерний процесс не мог покоцать ни расшареный код, ни его данные
B>и чтобы можно было общаться с ним через с/с++ интерфейсы например, т.е. без всех этих 0-to-3 ring переходов

B>может user-mode драйвера както тут помогут? не знаю пока что они могут, но расшаренный код должен иметь все возможности обычного user-mode режима


Если строго под Windows, я бы, наверное, использовал Microsoft RPC.

Если вкратце: это дешево и сердито, зато достаточно быстро (накладные расходы очень незначительные) и
безопасно (со стороны клиента уронить или подвесить сервер практически нереально, только разве что
через какую-нибудь уязвимость в системе).

Сначала в IDL-файле описываются все нужные интерфейсы, потом файл компилируется MIDL-компилятором и
сгенерированные файлы .c и .h подключаются к соответствующим проектам. Далее нужно написать код
инициализации клиента и сервера — это, условно говоря, пара страниц кода.

После этого вызовы функций интерфейса будут "прозрачно" превращаться в удаленные, причем клиент и
сервер могут быть как в пределах одной машины, так и на разных. В случае использования в доменных
средах доступны все соответствующие "фишки" AD: доменная аутентификация, kerberos и т.п.

Еще быстрее, наверное, (A)LPC, — ее использует Windows для обмена информацией между процессами, —
но эта технология, в отличие от MS RPC, почти полностью недокументированная.
Re: Мультипроцессный защищенный код
От: kov_serg Россия  
Дата: 31.03.18 11:14
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>есть проект в котором есть один главный процесс и куча дочерних

B>они ессно меж собой должны взаимодействовать, причем активно гоняя кучу данных
B>при этом дочерние процессы не должны иметь никакой возможности убить главный

B>классически это делается через сериализацию


https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa366551(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/ms810613.aspx
Re: Мультипроцессный защищенный код
От: Pzz Россия https://github.com/alexpevzner
Дата: 31.03.18 11:43
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>а нельзя ли както сделать так чтобы код, который общий, был в расшареном сегменте, т.е. был замаплен во все дочерние процессы и был при этом доступен для них только на вызов


Можно, путем вынесения этого кода в DLL

B>чтобы дочерний процесс не мог покоцать ни расшареный код, ни его данные


Насчет данных сложнее. Процесс может создать memory mapped file, и передать другому процессу HANDLE с правами "только на чтение", а другой процесс, соответственно, замапирует его к себе, без права записи.

Я на вскидку не помню уже вендовый API на эту тему, вроде можно создать и анонимный "memory mapping", без дискового файла, стоящего за ним.

B>и чтобы можно было общаться с ним через с/с++ интерфейсы например, т.е. без всех этих 0-to-3 ring переходов


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

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


Вендовый RPC, я слышал, использует для этих целей недокументированный API, который умеет пересылать сообщения между процессами, путем перемапливания страниц памяти из адресного пространства одной задачи в другую.

Не факт, что это так уж и бесплатно, потому что каждое такое перемапливание сбрасывает TLB
Re[2]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 31.03.18 12:21
Оценка:
ну вообще я вкурсе как расшарить кусок данных, это не проблема

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

при этом чтобы когда я писал код главного процесса, я мог написать

auto d = new CObject ...

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

типа например вот так, auto d = new CObject( ..., global_allocator)

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

типа сделать глобальный пул, в нём порождать всё не перебирая, что нужно а что нет — это удобство
этот пул замапить во все дочерние процесс как read-only

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

но это реально тока если адреса маппинга страниц памяти во всех процессах будут одинаковые — можно ли такое? иначе ничего не получится, потому что указатели же ж это абсолютные значения в виртуальном пространстве адресов
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[3]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 31.03.18 12:27
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>этот пул замапить во все дочерние процесс как read-only


т.е. страницы с общим кодом(DLL) должны иметь возможность писать в этот пул, а приватные страницы кода дочерних процессов — не должны

тогда я не смогу прямо покоцать общий пул, но вызвала код DLL смогу менять данные

это вообще реально в венде?

наверно это нереал, вроде как права на то куда можно, а куда — нет, нельзя устанавливать для отдельных сегментов кода
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[3]: Мультипроцессный защищенный код
От: Pzz Россия https://github.com/alexpevzner
Дата: 31.03.18 13:57
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>но это реально тока если адреса маппинга страниц памяти во всех процессах будут одинаковые — можно ли такое? иначе ничего не получится, потому что указатели же ж это абсолютные значения в виртуальном пространстве адресов


Можно вместо указателей использовать смещения от начала этого глобального пула.

Теоретически, при создании маппинга можно указать адрес. Но практически надо очень хорошо понимать, как устроена вся эта внутренняя кухня, чтобы этот диапазон адресного пространства не оказался вдруг неожиданно занят.
Re[3]: Мультипроцессный защищенный код
От: c-smile Канада http://terrainformatica.com
Дата: 31.03.18 18:48
Оценка: 6 (1)
Здравствуйте, Barbar1an, Вы писали:


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


B>при этом чтобы когда я писал код главного процесса, я мог написать


B>auto d = new CObject ...


http://garret.ru/shmem/Readme.htm
Re[3]: Мультипроцессный защищенный код
От: Pavel Dvorkin Россия  
Дата: 01.04.18 13:33
Оценка: 4 (1)
Здравствуйте, Barbar1an, Вы писали:

B>ну вообще я вкурсе как расшарить кусок данных, это не проблема


B>я же хочу расшарить статические объекты



Можно, и ты сам пишешь, что в курсе

>и кучу


А вот это AFAIK нет.

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


file mapping, shared section в DLL.

B>при этом чтобы когда я писал код главного процесса, я мог написать


B>auto d = new CObject ...


Только если переопределить operator new так, чтобы он выделял память в расшаренной области.

B>и этот указатель становился сразу доступным всем дочерним процессам без спецаильных мер


https://msdn.microsoft.com/ru-ru/library/windows/desktop/aa366763(v=vs.85).aspx

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

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

Кстати, в VC++ есть вот такое

https://msdn.microsoft.com/en-us/library/57a97k4e.aspx

B>но при этом дочерние процессы не должны иметь возможности покоцать эти общедоступные объекты


Это не проблема, пусть только главный создает мэппинг R/W, а дочерние R/O

B>типа сделать глобальный пул, в нём порождать всё не перебирая, что нужно а что нет — это удобство

B>этот пул замапить во все дочерние процесс как read-only

Да, примерно так и будет

B>тогда можно было бы дергать в дочерних процессах указатели на данные в этом пуле напрямую, и не бояться похерить их


Можно

B>но это реально тока если адреса маппинга страниц памяти во всех процессах будут одинаковые — можно ли такое? иначе ничего не получится, потому что указатели же ж это абсолютные значения в виртуальном пространстве адресов


См. выше.
With best regards
Pavel Dvorkin
Отредактировано 01.04.2018 13:54 Pavel Dvorkin . Предыдущая версия .
Re[2]: Мультипроцессный защищенный код
От: Pavel Dvorkin Россия  
Дата: 01.04.18 13:57
Оценка:
Здравствуйте, Pzz, Вы писали:


Pzz>Я на вскидку не помню уже вендовый API на эту тему, вроде можно создать и анонимный "memory mapping", без дискового файла, стоящего за ним.


Можно, не анонимный не надо — он приватен для процесса. Надо создавать CreateFileMapping, передавая вместо hFile значение INVALID_HABDLE_VALUE.
With best regards
Pavel Dvorkin
Re[4]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 01.04.18 20:44
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Но вообще-то особой необходимости иметь эти адреса одинаковыми для всех процессов нет. Пусть каждый процесс маппит независимо, и базовые адреса будут различными. Если после этого каждый процесс будет оперировать не абсолютным адресом, а смещением от базового адреса, то все будет в порядке


ну это ж неудобно нифига, придется везде добавлять смещение и делать кучу конверсий, к каждому указателю коих сотни будут
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[4]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 01.04.18 22:32
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

B>>auto d = new CObject ...


PD>Только если переопределить operator new так, чтобы он выделял память в расшаренной области.



тут вот проблема что для своих объектов я могу переопределить new, а если я например возвращаю референс на std::string? и вообще все std классы где будут инициироваться сами и свои потроха? а де попало...
или там всё так круто написано что мой аллокатор и все потроха разместит в том пуле который мне нужен?

но всё равно куча рисков сохраняется например

class A
{
std::string Text;
A * operanor new (...
}

autp a = new A

запихнет Text туда же куда и A
а потроха Text, (буфер текста) будут в каком пуле?

может проще вообще все XxxxAlloc перехватить и перенаправить на общий пул?
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Отредактировано 01.04.2018 22:37 Barbar1an . Предыдущая версия .
Re[4]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 01.04.18 22:46
Оценка:
или мож в стд есть способ глобально сменить пул по умолчанию?

а если такое есть...как тогда глобальные переменные стд? они ж инициализируются до передачи управления в main , или они дефолтный пул не используют?
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re: Мультипроцессный защищенный код
От: Cyberax Марс  
Дата: 02.04.18 02:57
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>и чтобы можно было общаться с ним через с/с++ интерфейсы например, т.е. без всех этих 0-to-3 ring переходов

Аж прямо в boost есть: https://www.boost.org/doc/libs/1_55_0/doc/html/interprocess.html
Sapienti sat!
Re[5]: Мультипроцессный защищенный код
От: Pavel Dvorkin Россия  
Дата: 02.04.18 04:01
Оценка:
Здравствуйте, Barbar1an, Вы писали:

Отвечаю на все 3 здесь

B>ну это ж неудобно нифига, придется везде добавлять смещение и делать кучу конверсий, к каждому указателю коих сотни будут


Неудобно, конечно, но можно функцию соорудить

>тут вот проблема что для своих объектов я могу переопределить new, а если я например возвращаю референс на std::string? и вообще все std классы где будут инициироваться сами и свои потроха? а де попало...


Ну вообще-то у классов STD есть возможность свой аллокатор использовать.

http://ru.cppreference.com/w/cpp/memory/allocator


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


Боюсь, что ты хочешь невозможного.

Кучи процессов не шарятся, они per process. Поэтому если использовать RTL кучу, то ничего не выйдет. Свои объекты, память для которых ты выделяешь сам по mmf механизму, шарить можно.

Правда, я вот такое нашел сейчас

https://www.codeproject.com/Articles/14525/Heap-Manager-for-Allocating-Memory-from-a-Shared-M

но насколько это применимо — не знаю.
With best regards
Pavel Dvorkin
Re[6]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 02.04.18 16:17
Оценка:
странно что вообще эта тема нигде не проработана, нет инстументария
а file mapping — это очень мало

а ведь она сильно бы упростила написание устойчивых машстабируемых систем

ибо я не вижу особых проблем дергать такие, глобальные, указатели в разных процессах, добавь потокобезопасность и всё, никаких проблем

и не нужен весь этот геморрой с сериализацией, идентификацией объектов и прочим, скока процессорного времени тратится на этот мусор! единственная польза — что можно по сети всё это гонять
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Отредактировано 02.04.2018 16:17 Barbar1an . Предыдущая версия .
Re[7]: Мультипроцессный защищенный код
От: Pavel Dvorkin Россия  
Дата: 02.04.18 17:16
Оценка:
Здравствуйте, Barbar1an, Вы писали:

B>странно что вообще эта тема нигде не проработана, нет инстументария


Был. Причем был совершенно всем доступный. Это был механизм управления памятью в 16-битной Windows. Там куча (глобальная) была одна для всех задач (так тогда называли процессы). Можно было выделить память в одной задаче и передать указатель в другую. И даже освободить память в другой можно было.

А вот в Win32 все же у каждого процесса свое адресное пространство, поэтому доступ к общей памяти требует усилий. Он не тривиален — если не синхронизировать, то будет плохо. Да и вообще идея получить указатель в одном процессе и передать его в другой не очень соответствует современным принципам. Тут много проблем, и их в Win API и C++ CRT не решают, а только предоставляют средства, на базе которых каждый может попробовать свое написать — на свой страх и риск.
With best regards
Pavel Dvorkin
Re: Мультипроцессный защищенный код
От: ononim  
Дата: 05.04.18 17:08
Оценка: 4 (1)
Как уже писали, главная проблема — получить фиксированный между разными процессами адрес, чтоб не занят был. В принципе если говорить про драйвер, то это несложно сделать из нотификации на создание процесса резервировать регион памяти по заданному адресу и радоваться жизни. Вопрос какой адрес выбрать для фиксации, а выбрать надо такой, чтоб не перекрывался с адресом загрузки базовых длл (ntdll/kernelbase/kernel32/user32/gdi32/может-там-еще-чего-добавили) в данной сессии и не перекрывался с адресом загрузки ваших ехе модулей.
Предполагаемый функционал в драйвере:
— Драйвер имеет admin-only IOCTL, который ему говорит: для процессов, созданных из имажа с таким то путем резервируй адреса с такогото по такой-то.

Предполагаемый функционал в юзермодном 'главном' сервисе:
— При запуске определяет текущие ASLR-ed базы указанных выше длл, ехе-шника нужного имажа/ов, подбирает заданный адрес и дергает драйвер за тот самый IOCTL.
— Имеет локальный IPC, через пайпы например или LPC, который позволяет дернуть его из непривелигированного процесса, запросив shared memory. При дерганье сервис создает персональнй mapping, занимающий некоторый заданный диапазон адресов зарезервированного пула между собой и процессом клиентом. MapViewOfFile2 позволяет промапить неименованный анонимный мапинг в АП чужого процесса. Ну или NtMapViewOfSection, если вы без комплексов.
— При желании на эту область памяти можно даже натянуть хип.
— Помимо мапинга вам еще понадобится некая синхронизация клиент-сервер.

Очевидные недостатки — область памяти будет иметь захардкоженный размер на всех и еще меньший размер на одного клиента. В принципе, на х64 этот размер может быть достаточно велик для любых применений, главное — не комтить страницы сразу, а максимально пользоваться MEM_RESERVE/SEC_RESERVE.

В итоге получится не требующий фиксапов межпроцессный хип.

  Скрытый текст
Но это все равно глупая затея. И дело не в трудоемкости. Защищенность сервиса предполагает, что клиент не сможет его порушить. А значит, что сервису придется тщательно смотреть за структурами данных, которые ему в расшаренную память положил процесс. Причем это значит, что клиент, будучи написанным хакером, может abuse-ить ваш протокол, к примеру записывая в расшаренную память в обход предусмотренного механизма синхронизации. Это не то чтобы нерешаемая задача — можно обеспечить транзакционную синхронизацию, переключающую режим работы хипа между клиентом и сервисов устанавливая защиту на страницы памяти которую клиент не сможет изменить, но по итогу с такой синхронизацией + проверками валидности данных работать оно врядл будет быстрее чем реализация протокола-через-пайпы. А без них — ни о какой защищенности кода говорить нельзя и проще заюзать предложенный выше буст.
Как много веселых ребят, и все делают велосипед...
Отредактировано 05.04.2018 17:10 ononim . Предыдущая версия .
Re[2]: Мультипроцессный защищенный код
От: Barbar1an Украина  
Дата: 06.04.18 10:55
Оценка:
Здравствуйте, ononim, Вы писали:

O>Но это все равно глупая затея. И дело не в трудоемкости. Защищенность сервиса предполагает, что клиент не сможет его порушить. А значит, что сервису придется тщательно смотреть за структурами данных, которые ему в расшаренную память положил процесс. Причем это значит, что клиент, будучи написанным хакером, может abuse-ить ваш протокол, к примеру записывая в расшаренную память в обход предусмотренного механизма синхронизации. Это не то чтобы нерешаемая задача — можно обеспечить транзакционную синхронизацию, переключающую режим работы хипа между клиентом и сервисов устанавливая защиту на страницы памяти которую клиент не сможет изменить, но по итогу с такой синхронизацией + проверками валидности данных работать оно врядл будет быстрее чем реализация протокола-через-пайпы. А без них — ни о какой защищенности кода говорить нельзя и проще заюзать предложенный выше буст.



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

тогда нужно будет лишь хорошо проверять входные параметры и всё
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Re[3]: Мультипроцессный защищенный код
От: ononim  
Дата: 06.04.18 11:00
Оценка:
B>так а можно сделать, чтобы клиентский код не мог писать в общий хип напрямую, а только вызывая апи сервиса? но мог читать, т.е. мог разыменовывать указатели из общего хипа
B>тогда нужно будет лишь хорошо проверять входные параметры и всё
Не очень понял. Если имеется ввиду можно ли сделать хип read-only для непривелигированных процессов — то, конечно, можно. Более того, в винде такое юзается: user32 мапит кусочек session-space в readonly для всех процессов — там есть т.н. desktop и shared heap — они отображаются на юзермода как read-only страницы. Это позволяет обойтись без перехода в кернелмод для многих функций, не требующих изменения состояния, типа IsWindow, WindowFromPoint etc.
Как много веселых ребят, и все делают велосипед...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.