Как разделить память между сервисами и пользовательскими процессами? - PullRequest
6 голосов
/ 22 мая 2009

У меня есть набор приложений Win32, которые обмениваются информацией с использованием сегмента общей памяти, созданного с помощью CreateFileMapping() и MapViewOfFile(). Одним из приложений является системный сервис; остальные запускаются вошедшим в систему пользователем. На Windows XP проблем не было. Мы назвали наши сегменты «Global \ Something», и все было хорошо.

Дополнительная безопасность в Vista (и предположительно Windows 7), по-видимому, препятствует работе этой архитектуры. Обычным пользователям не разрешается создавать (ошибка Win32 5) объекты в глобальном пространстве имен. В MSDN указано, что если учетная запись имеет привилегию «создать глобальную», то все должно быть хорошо, но на практике это не так. Кроме того, функции «целостности» Vista, по-видимому, препятствуют доступу пользовательских процессов «с низким уровнем целостности» к объекту общей памяти, созданному службой «с высоким уровнем целостности». Похоже, я смогу это исправить с помощью какого-то магического заклинания SetSecurityDescriptorSacl(), но мне трудно научиться говорить на сакле.

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

Чтобы исключить простой ответ «просто выключите UAC», мы находимся в довольно закрытой среде, и это невозможно.

Редактировать: и сервис, и пользовательский процесс должны иметь доступ на чтение / запись к сегменту.

1 Ответ

10 голосов
/ 22 мая 2009

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

Обычные пользователи не имеют привилегии create global, но сервисы могут иметь эту привилегию. Если вам нужно, чтобы ваши пользователи создали общую память, а затем попросили службу проверить ее, вы могли бы иметь схему IPC, в которой ваш код пользователя отправляет сообщение службе, содержащей дескриптор сопоставления файлов, а затем служба вызывает DuplicateHandle, чтобы получить ссылка на это. Это потребует, чтобы ваша служба работала с привилегией отладки.

Самый простой способ создать DACL - это использовать ConvertStringSecurityDescriptorToSecurityDescriptor, который принимает строку в формате SDDL, определяющем ACL.

Написание безопасного кода содержит отличную главу по созданию DACL с SDDL.

// Error handling removed for brevity
SECURITY_ATTRIBUTES attributes;
ZeroMemory(&attributes, sizeof(attributes));
attributes.nLength = sizeof(attributes);
ConvertStringSecurityDescriptorToSecurityDescriptor(
         L"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GR;;;IU)",
         SDDL_REVISION_1,
         &attributes.lpSecurityDescriptor,
         NULL);

CreateFileMapping(INVALID_HANDLE_VALUE, &attributes,
              PAGE_READWRITE, sizeHigh, sizeLow, L"Global\\MyObject");

LocalFree(attributes.lpSecurityDescriptor);

"D: ​​P (A; OICI; GA ;;; SY) (A; OICI; GA ;;; BA) (A; OICI; GR ;;; IU)" определяет DACL. D: P означает, что это DACL (вместо SACL ... вы редко используете SACL), за которым следуют несколько строк ACE, которые контролируют, кто получает доступ. Каждый из них является A (разрешить) и допускает объект и содержит наследование (OICI). Первый, чтобы предоставить весь доступ (GA - предоставить все) Системе (SY) и Администраторам (BA, встроенные администраторы). Последнее предоставляет чтение (GR) интерактивным пользователям (IU), которые фактически являются пользователями, вошедшими в сеанс.

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

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

...