Domanda

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:

Ruby problem dialog box

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

Update

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:

  • Copying line 3 from runner.rb to the bottom of mwe.rb and running mwe.rb directly.
  • Commenting out line 5 of mwe.rb or commenting out some large subset of errors.rb (e.g. commenting out lines 37 through 99 result in no segfault).
  • Commenting out line 3 of runner.rb, in effect only requiring the other files and exiting.
  • Commenting out a combination of the following from within Pageant::Win results in no segfault:
    • Calls to extern
    • Calls to struct
    • Constants
    • Class methods

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.

È stato utile?

Soluzione

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.)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top