Class: PatchELF::MM

Inherits:
Object
  • Object
show all
Defined in:
lib/patchelf/mm.rb

Overview

Memory management, provides malloc/free to allocate LOAD segments.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(elf) ⇒ MM

Instantiate a PatchELF::MM object.

Parameters:

  • elf (ELFTools::ELFFile)


14
15
16
17
# File 'lib/patchelf/mm.rb', line 14

def initialize(elf)
  @elf = elf
  @request = []
end

Instance Attribute Details

#extend_sizeInteger (readonly)

Returns The size extended.

Returns:

  • (Integer)

    The size extended.



9
10
11
# File 'lib/patchelf/mm.rb', line 9

def extend_size
  @extend_size
end

#thresholdInteger (readonly)

Returns Where the file start to be extended.

Returns:

  • (Integer)

    Where the file start to be extended.



10
11
12
# File 'lib/patchelf/mm.rb', line 10

def threshold
  @threshold
end

Instance Method Details

#dispatch!void

This method returns an undefined value.

Let the malloc / free requests be effective.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/patchelf/mm.rb', line 35

def dispatch!
  return if @request.empty?

  @request_size = @request.map(&:first).inject(0, :+)
  # The malloc-ed area must be 'rw-' since the dynamic table will be modified during runtime.
  # Find all LOADs and calculate their f-gaps and m-gaps.
  # We prefer f-gap since it doesn't need move the whole binaries.
  # 1. Find if any f-gap has enough size, and one of the LOAD next to it is 'rw-'.
  #   - expand (forwardlly), only need to change the attribute of LOAD.
  # 2. Do 1. again but consider m-gaps instead.
  #   - expand (forwardlly), need to modify all section headers.
  # 3. We have to create a new LOAD, now we need to expand the first LOAD for putting new segment header.

  # First of all we check if there're less than two LOADs.
  abnormal_elf('No LOAD segment found, not an executable.') if load_segments.empty?
  # TODO: Handle only one LOAD. (be careful if memsz > filesz)

  fgap_method || mgap_method || new_load_method
end

#extended?Boolean

Query if extended.

Returns:

  • (Boolean)


57
58
59
# File 'lib/patchelf/mm.rb', line 57

def extended?
  defined?(@threshold)
end

#extended_offset(off) ⇒ Integer

Get correct offset after the extension.

Parameters:

  • off (Integer)

Returns:

  • (Integer)

    Shifted offset.



66
67
68
69
70
71
# File 'lib/patchelf/mm.rb', line 66

def extended_offset(off)
  return off unless defined?(@threshold)
  return off if off < @threshold

  off + @extend_size
end

#malloc(size) {|off, vaddr| ... } ⇒ void

This method returns an undefined value.

Parameters:

  • size (Integer)

Yield Parameters:

  • off (Integer)
  • vaddr (Integer)

Yield Returns:

  • (void)

    One can only do the following things in the block:

    1. Set ELF headers’ attributes (with ELFTools)

    2. Invoke Saver#inline_patch

Raises:

  • (ArgumentError)


27
28
29
30
31
# File 'lib/patchelf/mm.rb', line 27

def malloc(size, &block)
  raise ArgumentError, 'malloc\'s size most be positive.' if size <= 0

  @request << [size, block]
end