Please see the update below
I have been attempting to fix a Ruby library's ability to communicate with another program across UAC contexts and need to create a shared file map with the same security attributes as the current user. I'm using Ruby/dl and trying to get this to work on Ruby 1.9.3 is what led to my issue.
Calling the OpenProcessToken function in advapi31 results in a segmentation fault. You will find a minimal example below, which resulted in a segmentation fault on my machine. The text of the error I received is here, and here is also a screenshot of the error box that comes up after the error text prints to the command line:
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
Updating Ruby to 1.9.3p545 (using RubyInstaller) allowed me to run the example provided above, but I continue to have issues. I have created a Gist here containing the files which, when run with 1.9.3p545, produce a segmentation fault (though this time without interpreter becoming unresponsive and producing the dialog box as above.) I have tried this (and the below) on my machine as well as another with the same version of Ruby installed with the same result. Since I didn't mention it previously, I'm running Windows 7 Pro 64-bit, the same is true for the other computer I tested it on.
I have noticed a few things that may imply a deeper issue, not necessarily associated with OpenProcessToken. Any one of the following may, individually, prevent a segfault:
extern
struct
In the last case it is not necessary to comment out all of the items of a particular category. For instance, a segfault is avoided if I comment out TOKEN_USER
and SECURITY_ATTRIBUTES
. I may also prevent a segfault by commenting out TOKEN_USER
and the extern
statement associated with IsValidSecurityDescriptor
. I have tried several other combinations that result in the same behavior.
Any help would be appreciated.
This bug is not due to ruby but to your code.
You used the inappropriate method ref on a variable of DL::CPtr type in the open_process_token method.
The method 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
Should be
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
(Thanks to Heesob Park on this non-issue.)