memory_locker 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39ab9db08583b52b0d784c5d9f9cc259ca4233523cd1389be309f55339add449
4
- data.tar.gz: 5756d015e348eb03f69e23c6c2ee214f9d9db736cb0de50a00e38bb3f81570c7
3
+ metadata.gz: a4bc016f2294342753deae3eda56b89e55b5345474f12603919b5063dc441045
4
+ data.tar.gz: ac399821325952ee575fcc226de9edc41c14139a078ae33eb1c7584f24033f54
5
5
  SHA512:
6
- metadata.gz: d85352a114f15abd76ec140ca38a15c828a8c4cf4a21f8709db8a9a2f3b0bfd3dd686e6bc9a510b97cccb7a19ca08475fbdcc3e2ac47440fca5df7104815744c
7
- data.tar.gz: f68c19229a9127e740a6e54cfd4fa3a2c3bb2f3faec579d8a2eb3c5456d6f0a9ac7a12ae46a3ef6c5c6d8de3f5d0960855b2e12ff07d817afecc4a8ceaf0ea1c
6
+ metadata.gz: 4a9ad9fc290ccbe7ce4fc0fe6a52d1bce11b0fb0899721c5e4e6492f14f54811f4f630faf632dc9e7b6afc944cc22a7b188d90b3dbd6065d79b98f17e5805944
7
+ data.tar.gz: d92c5be22a0b00041829053f32bc61a6c46ce63987062584956413da81832b44046dbe50b0d14e6c8bdc9b3a1c9b121b0f76612a9741c1ec65a985fa731a760a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## [1.0.3] - 2023-11-12
2
+
3
+ - Use Fiddle (part of Ruby standard library) instead of FFI gem
4
+
1
5
  ## [1.0.2] - 2023-07-28
2
6
 
3
7
  - Don't load libc if already loaded in the current process
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # MemoryLocker
2
+
2
3
  [![Gem Version](https://badge.fury.io/rb/memory_locker.svg)](https://badge.fury.io/rb/memory_locker)
3
4
 
4
5
  Lock memory containing sensitive data (such as passwords or cryptographic keys) to prevent it from being swapped
@@ -7,7 +8,7 @@ by the kernel, which allows the attacker with access to swap space to recover se
7
8
  ## How it works
8
9
 
9
10
  Ruby doesn't allow granular memory management, therefore the approach is to lock the entire memory of a current
10
- process using `mlockall()`.
11
+ process using [mlockall()](https://linux.die.net/man/2/mlockall).
11
12
 
12
13
  The memory will stay locked until the process terminates. Although unlocking memory is technically possible,
13
14
  the gem doesn't allow it. The reason is Ruby doesn't support reliable removal of secrets from memory,
@@ -19,47 +20,31 @@ Subprocesses don't inherit memory locking. Make sure to lock memory in each one
19
20
 
20
21
  ## Requirements
21
22
 
22
- This gem requires [ffi gem](https://github.com/ffi/ffi), which needs to be built on install.
23
- In case of build-related issues, make sure you have the compiler installed.
24
- Refer to gem documentation for instructions.
25
-
26
- Also, an OS supporting `mlockall()` is required. Those include most Unixes except macOS. Windows is not supported.
23
+ OS support for [mlockall()](https://linux.die.net/man/2/mlockall) is required.
24
+ Will work on most Unixes except macOS. Windows is not supported.
27
25
 
28
26
  ## Installation
29
27
 
30
- $ gem install memory_locker
28
+ gem install memory_locker
31
29
 
32
30
  ## Usage
33
31
 
34
- ### Enforced installation
35
-
36
32
  To lock the memory of your process, add the following code early in the app lifetime:
37
33
 
38
34
  require 'memory_locker'
39
- MemoryLocker.call
40
-
41
- ### Optional installation
42
-
43
- If you don't want to force the user to install `memory_locker` gem, you can make it optional.
44
- If the user doesn't have it installed, the warning will appear, but your app will run.
45
-
46
- begin
47
- require 'memory_locker'
48
- rescue LoadError
49
- warn 'Failed to lock memory. To fix install `memory_locker` gem.'
50
- else
51
- MemoryLocker.call
52
- end
35
+ MemoryLocker.call # short syntax
36
+ MemoryLocker.new.call # if you prefer to use instance explicitly
53
37
 
54
38
  ## Exceptions
55
39
 
56
- If your OS is unsupported or there was a locking error, you will get an exception descending from MemoryLocker::Error.
40
+ If your OS is unsupported or there is a locking error, you will get an exception descending from `MemoryLocker::Error`.
57
41
 
58
42
  ## Testing
59
43
 
60
- Locking the memory of your app when testing is not needed, and if you use an unsupported OS will brake your app.
44
+ Locking the memory of your app when testing is not needed, and if you use an unsupported OS will break your app.
61
45
 
62
- As only the `#call` method is being used, you can easily replace `MemoryLocker` with empty lambda `->{}`.
46
+ As only the `#call` method is being used, you can easily replace `MemoryLocker` class or instance with an empty
47
+ lambda `->{}` in your tests.
63
48
 
64
49
  ## Development
65
50
 
@@ -72,7 +57,7 @@ push git commits and the created tag, and push the `.gem` file to [rubygems.org]
72
57
 
73
58
  ## Contributing
74
59
 
75
- Bug reports and pull requests are welcome on GitHub at https://github.com/phantom-node/memory_locker.
60
+ Bug reports and pull requests are welcome on GitHub at <https://github.com/phantom-node/memory_locker>.
76
61
  This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
77
62
  the [code of conduct](https://github.com/phantom-node/memory_locker/blob/master/CODE_OF_CONDUCT.md).
78
63
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class MemoryLocker
4
- VERSION = '1.0.2'
4
+ VERSION = "1.0.3"
5
5
  end
data/lib/memory_locker.rb CHANGED
@@ -1,39 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'memory_locker/version'
4
- require 'ffi'
3
+ require_relative "memory_locker/version"
4
+ require "fiddle"
5
5
 
6
6
  # Lock process memory, so it won't be swapped by the kernel.
7
7
  # It is implemented as a one-way operation: there is no unlock.
8
8
  # That's because it's hard to properly clean memory in Ruby.
9
9
  class MemoryLocker
10
- Error = Class.new StandardError
11
- UnsupportedError = Class.new Error
12
- LibcNotFoundError = Class.new Error
13
- LockingError = Class.new Error
10
+ Error = Class.new StandardError
11
+ LockingError = Class.new Error
12
+ UnsupportedError = Class.new Error
13
+
14
+ # Those values should remain the same on all POSIX systems
15
+ MCL_CURRENT = 1
16
+ MCL_FUTURE = 2
17
+ private_constant :MCL_CURRENT, :MCL_FUTURE
14
18
 
15
19
  def call
16
- result, errno = libc.mlockall
17
- raise LockingError, "Locking of memory failed with errno #{errno}" unless result.zero?
20
+ raise LockingError, "Locking of memory failed" unless function.call(MCL_CURRENT | MCL_FUTURE).zero?
18
21
  end
19
22
 
20
23
  def self.call
21
- new.call
24
+ new.send :call
22
25
  end
23
26
 
24
27
  private
25
28
 
26
- attr_reader :libc
27
-
28
- def initialize(libc_loader: -> { require_relative 'memory_locker/libc' },
29
- libc_fetcher: -> { Libc },
30
- unsupported_error: FFI::NotFoundError,
31
- libc_not_found_error: LoadError)
32
- libc_loader.call
33
- @libc = libc_fetcher.call
29
+ def function
30
+ lazy_function.call
34
31
  rescue unsupported_error => e
35
- raise UnsupportedError, 'System does not support mlockall()', cause: e
36
- rescue libc_not_found_error => e
37
- raise LibcNotFoundError, 'Failed to find C library', cause: e
32
+ raise UnsupportedError, "Memory locking not supported: #{e.message}", cause: e
33
+ end
34
+
35
+ attr_reader :lazy_function, :unsupported_error
36
+
37
+ def initialize(
38
+ libc_path: nil,
39
+ function_name: "mlockall",
40
+ lazy_handle: -> { Fiddle.dlopen(libc_path)[function_name] },
41
+ lazy_function: -> { Fiddle::Function.new(lazy_handle.call, [Fiddle::TYPE_INT], Fiddle::TYPE_INT) },
42
+ unsupported_error: Fiddle::DLError
43
+ )
44
+
45
+ @lazy_function = lazy_function
46
+ @unsupported_error = unsupported_error
38
47
  end
39
48
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memory_locker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paweł Pokrywka
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-28 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: ffi
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 1.0.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: 1.0.0
11
+ date: 2023-11-12 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description:
28
14
  email:
29
15
  - pepawel@users.noreply.github.com
@@ -35,7 +21,6 @@ files:
35
21
  - LICENSE.txt
36
22
  - README.md
37
23
  - lib/memory_locker.rb
38
- - lib/memory_locker/libc.rb
39
24
  - lib/memory_locker/version.rb
40
25
  homepage: https://github.com/phantom-node/memory_locker
41
26
  licenses:
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class MemoryLocker
4
- # Low level interface to libc
5
- module Libc
6
- # Those values should remain the same on all POSIX systems
7
- MCL_CURRENT = 1
8
- MCL_FUTURE = 2
9
-
10
- extend FFI::Library
11
- # Try to load already loaded libc from the current process, use system libc as a fallback
12
- ffi_lib [FFI::CURRENT_PROCESS, FFI::Library::LIBC]
13
- attach_function :real_mlockall, :mlockall, [:int], :int
14
-
15
- def self.mlockall
16
- result = real_mlockall(MCL_CURRENT | MCL_FUTURE)
17
- [result, FFI.errno]
18
- end
19
- end
20
-
21
- private_constant :Libc
22
- end