Segfault при вызове OpenProcessToken через Ruby/DL
Пожалуйста, смотрите обновление ниже
Я пытался исправить способность библиотеки Ruby взаимодействовать с другой программой в контексте UAC, и мне нужно создать общую карту файлов с теми же атрибутами безопасности, что и у текущего пользователя. Я использую Ruby/dl и пытаюсь заставить это работать на Ruby 1.9.3, и это привело к моей проблеме.
Вызов функции OpenProcessToken в advapi31 приводит к ошибке сегментации. Ниже вы найдете минимальный пример, который привел к ошибке сегментации на моей машине. Текст ошибки, которую я получил, находится здесь, а также снимок экрана с окном ошибки, которое появляется после того, как текст ошибки напечатан в командной строке:
require 'dl'
require 'dl/import'
require 'dl/types'
module Win
extend DL::Importer
dlload 'kernel32', 'advapi32'
include DL::Win32Types
# args: none
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx
extern 'HANDLE GetCurrentProcess()'
# args: hProcessHandle, dwDesiredAccess, (out) phNewTokenHandle
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa379295(v=vs.85).aspx
extern 'BOOL OpenProcessToken(HANDLE, DWORD, PHANDLE)'
# args: hObject
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx
extern 'BOOL CloseHandle(HANDLE)'
# args: none
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360(v=vs.85).aspx
extern 'DWORD GetLastError()'
def self.open_process_token
token_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
raise_error_if_zero(OpenProcessToken(Win.GetCurrentProcess, 0x8, token_handle.ref))
raise_error_if_zero(CloseHandle(token_handle))
end
def self.raise_error_if_zero(result)
if result == 0
raise "Windows error: #{Win.GetLastError}"
end
end
end
Win.open_process_token
Обновить
Обновление Ruby до 1.9.3p545 (с использованием RubyInstaller) позволило мне запустить приведенный выше пример, но у меня продолжают возникать проблемы. Я создал здесь Gist, содержащий файлы, которые при запуске с 1.9.3p545 приводят к ошибке сегментации (хотя на этот раз переводчик перестает отвечать на запросы и выдает диалоговое окно, как указано выше). Я пробовал это (и ниже) на моем машина, а также другая с той же версией Ruby, установленной с тем же результатом. Поскольку я не упоминал об этом ранее, я использую 64-разрядную версию Windows 7 Pro, то же самое верно и для другого компьютера, на котором я его тестировал.
Я заметил несколько вещей, которые могут подразумевать более глубокую проблему, не обязательно связанную с OpenProcessToken. Любое из следующих действий может, по отдельности, предотвратить появление ошибки:
- Копирование строки 3 из runner.rb в конец mwe.rb и прямой запуск mwe.rb.
- Закомментирование строки 5 mwe.rb или комментирование некоторого большого подмножества errors.rb (например, комментирование строк с 37 по 99 не приводит к segfault).
- Закомментирование строки 3 файла runner.rb, по сути, требует только других файлов и выхода.
- Комментирование сочетания следующего изнутри Pageant::Win приводит к отсутствию ошибки:
- Звонки в
extern
- Звонки в
struct
- Константы
- Методы класса
- Звонки в
В последнем случае нет необходимости комментировать все элементы определенной категории. Например, segfault можно избежать, если я закомментирую TOKEN_USER
а также SECURITY_ATTRIBUTES
, Я также могу предотвратить segfault, комментируя TOKEN_USER
и extern
заявление, связанное с IsValidSecurityDescriptor
, Я пробовал несколько других комбинаций, которые приводят к тому же поведению.
Любая помощь будет оценена.
1 ответ
Эта ошибка связана не с ruby, а с вашим кодом.
Вы использовали неподходящий метод ref для переменной типа DL::CPtr в методе open_process_token.
Метод open_process_token
def self.open_process_token
token_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
OpenProcessToken(Win.GetCurrentProcess, 0x8, token_handle.ref)
end
Должно быть
def self.open_process_token
ptoken_handle = DL::CPtr.malloc(DL::SIZEOF_VOIDP, DL::RUBY_FREE)
OpenProcessToken(Win.GetCurrentProcess, 0x8, ptoken_handle)
token_handle = ptoken_handle.ptr.to_i
end