image_processing 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a11a590332eebc08eff9b2cc0ff0436ff8ab42c6bee6e85034232d8e5425700
4
- data.tar.gz: 983201e5b89000e91f299f4f25cfa861673e6a552f5f751d336bf45b12f3b534
3
+ metadata.gz: a52c42f1463cc15caf0dfe57bc8a5efeb464006a2a29bbf1b8c842ada339e4aa
4
+ data.tar.gz: 2344e1015b02f4b24363371d8877bdcc4fb28b9fb820e15d2e2446f7874443c6
5
5
  SHA512:
6
- metadata.gz: 762c39caba0bfba8f5b00eb3334308a0a3fd79f602301e087cc7e53acb38dc416ad8bd547d6779636c966c25fbf689c75d306394ca01a93d8dfe13e5fb902ac6
7
- data.tar.gz: 94e92fff8dddd41a3651ee85e58bdcdc94d293fbacf573e62a2ca560ad9c5546f9e79e9e97736948b7daf65478938e15e2e7ffa8a4d7f8a6b55a7ed24e930f14
6
+ metadata.gz: 90c29ed45d475cc54f814a368e894504f5bc012835ef989d3678568dfb3cd29aca144e88cb17d102ffc82dcbd94c4d46de7d9a5fbc0474c0f6b15c481a1f4bb3
7
+ data.tar.gz: 8a7f991cf00725e1d5618add34f9b57814e2e273d8b9575f49e61701e80259ac8c2cd61028cdaefc6b4a6694a8a922d2246f5f6b8f7ee7184ff31bd0f8644813
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 2.1.0 (2026-09-01)
2
+
3
+ * [minimagick] Add `inherit_fds:` so a loader can name an already-open input (thanks to @flavorjones)
4
+
5
+ ## 2.0.3 (2026-08-06)
6
+
7
+ * Prevent remote code execution when operation names come from user input, closing bypasses through the `#operation` meta-builder, `#method_missing`, and nested `#send` calls (reported by @szymonsec)
8
+
9
+ * [minimagick] Prevent remote code execution through unsafe public methods (e.g. `#instance_eval`, `#send`) passed as loader/saver option names
10
+
1
11
  ## 2.0.2 (2026-06-03)
2
12
 
3
13
  * Raise `LoadError` instead of `ImageProcessing::Error` when soft dependencies are missing (@bdewater-thatch)
@@ -86,25 +86,24 @@ module ImageProcessing
86
86
  private
87
87
 
88
88
  # This prevents calling unsafe Ruby core methods such as `Kernel#system`,
89
- # which would allow for remote shell execution.
89
+ # which would allow for remote shell execution. The processor enforces the
90
+ # same guard when operations are dispatched, which also covers paths that
91
+ # bypass this early check (e.g. the #operation meta-builder).
92
+ #
93
+ # Bang names are rejected here because they are Chainable's execution
94
+ # shortcut (see #method_missing), not operations to chain.
90
95
  def invalid_operation?(name)
91
- return true if name.end_with?("!")
92
-
93
- owner = method(name).owner
94
- [BasicObject, Kernel, Object, Module].include?(owner)
95
- rescue NameError
96
- false
96
+ name.end_with?("!") || ImageProcessing.unsafe_method?(self, name)
97
97
  end
98
98
 
99
99
  # Assume that any unknown method names an operation supported by the
100
100
  # processor. Add a bang ("!") if you want processing to be performed.
101
- def method_missing(name, *args, &block)
102
- return super if name.to_s.end_with?("?")
103
- return public_send(name.to_s.chomp("!"), *args, &block).call if name.to_s.end_with?("!")
101
+ def method_missing(name, ...)
102
+ return super if name.end_with?("?")
103
+ return public_send(name.to_s.chomp("!"), ...).call if name.end_with?("!")
104
104
 
105
- operation(name, *args, &block)
105
+ operation(name, ...)
106
106
  end
107
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
108
107
 
109
108
  # Empty options which the builder starts with.
110
109
  DEFAULT_OPTIONS = {
@@ -9,11 +9,20 @@ module ImageProcessing
9
9
  module MiniMagick
10
10
  extend Chainable
11
11
 
12
- def self.convert_shim(&block)
12
+ # mini_magick gained `inherit_fds:` on MiniMagick::Shell#execute in 5.4.0.
13
+ INHERIT_FDS_MINIMUM_VERSION = Gem::Version.new("5.4.0")
14
+
15
+ def self.convert_shim(inherit_fds: nil, &block)
16
+ if inherit_fds && ::MiniMagick.version < INHERIT_FDS_MINIMUM_VERSION
17
+ raise LoadError, "The `inherit_fds` loader option requires mini_magick #{INHERIT_FDS_MINIMUM_VERSION} or newer, but mini_magick #{::MiniMagick.version} is loaded. Please upgrade the gem."
18
+ end
19
+
20
+ options = inherit_fds ? { inherit_fds: inherit_fds } : {}
21
+
13
22
  if ::MiniMagick.respond_to?(:convert)
14
- ::MiniMagick.convert(&block)
23
+ ::MiniMagick.convert(**options, &block)
15
24
  else
16
- ::MiniMagick::Tool::Convert.new(&block)
25
+ ::MiniMagick::Tool::Convert.new(**options, &block)
17
26
  end
18
27
  end
19
28
 
@@ -37,12 +46,16 @@ module ImageProcessing
37
46
  # Initializes the image on disk into a MiniMagick::Tool object. Accepts
38
47
  # additional options related to loading the image (e.g. geometry).
39
48
  # Additionally auto-orients the image to be upright.
40
- def self.load_image(path_or_magick, loader: nil, page: nil, geometry: nil, auto_orient: true, **options)
49
+ # `inherit_fds` names IO objects the tool inherits, so the source may be a
50
+ # `/dev/fd/N` path. The source stays a path, so `loader`, `page` and
51
+ # `geometry` still apply to it, which they would not if the caller passed
52
+ # a pre-built MiniMagick::Tool carrying the descriptor.
53
+ def self.load_image(path_or_magick, loader: nil, page: nil, geometry: nil, auto_orient: true, inherit_fds: nil, **options)
41
54
  if path_or_magick.is_a?(::MiniMagick::Tool)
42
55
  magick = path_or_magick
43
56
  else
44
57
  source_path = path_or_magick
45
- magick = ::ImageProcessing::MiniMagick.convert_shim
58
+ magick = ::ImageProcessing::MiniMagick.convert_shim(inherit_fds: inherit_fds)
46
59
 
47
60
  Utils.apply_options(magick, **options)
48
61
 
@@ -225,6 +238,13 @@ module ImageProcessing
225
238
  # Applies options from the provided hash.
226
239
  def apply_options(magick, define: {}, **options)
227
240
  options.each do |option, value|
241
+ # Loader/saver option names may come from user input, so guard
242
+ # against dispatching to unsafe Ruby core methods (e.g. #send,
243
+ # #instance_eval) that public_send does not block on its own.
244
+ if ImageProcessing.unsafe_method?(magick, option)
245
+ raise Error, "#{option.inspect} is not a valid option"
246
+ end
247
+
228
248
  case value
229
249
  when true, nil then magick.public_send(option)
230
250
  when false then magick.public_send(option).+
@@ -53,6 +53,15 @@ module ImageProcessing
53
53
  # operation directly on the accumulator object. This provides a common
54
54
  # umbrella above defined macros and direct operations.
55
55
  def apply_operation(name, *args, &block)
56
+ # Chainable performs the same check when operations are built, but that
57
+ # guard only sees the outer builder method name, so it can be routed
58
+ # around via the #operation meta-builder, #method_missing, or a nested
59
+ # #send. This is the single point every operation is finally dispatched
60
+ # through, so enforcing the guard here closes all of those paths.
61
+ if ImageProcessing.unsafe_method?(self, name)
62
+ fail Error, "#{name.inspect} is not a valid operation"
63
+ end
64
+
56
65
  receiver = respond_to?(name) ? self : @accumulator
57
66
 
58
67
  if args.last.is_a?(Hash)
@@ -1,3 +1,3 @@
1
1
  module ImageProcessing
2
- VERSION = "2.0.2"
2
+ VERSION = "2.1.0"
3
3
  end
@@ -7,6 +7,25 @@ require "image_processing/version"
7
7
  module ImageProcessing
8
8
  Error = Class.new(StandardError)
9
9
 
10
+ # Method owners considered unsafe to dispatch to when a method name comes
11
+ # from user input, because they expose Ruby's metaprogramming and shell
12
+ # primitives (e.g. Kernel#send, Kernel#eval, BasicObject#instance_eval,
13
+ # Kernel#system). Any name whose implementation is inherited from one of
14
+ # these should never be treated as an image operation or a loader/saver
15
+ # option.
16
+ UNSAFE_METHOD_OWNERS = [BasicObject, Kernel, Object, Module].freeze
17
+
18
+ # Whether calling +name+ on +receiver+ would dispatch to an unsafe Ruby core
19
+ # method rather than a genuine operation. Used as a single, shared guard at
20
+ # every place where a user-provided name is dispatched via +public_send+.
21
+ def self.unsafe_method?(receiver, name)
22
+ UNSAFE_METHOD_OWNERS.include?(receiver.method(name.to_s).owner)
23
+ rescue NameError
24
+ # An unknown name is not a Ruby core method, so it is safe to forward to
25
+ # the receiver (which will reject it if it is not a real operation).
26
+ false
27
+ end
28
+
10
29
  autoload :MiniMagick, "image_processing/mini_magick"
11
30
  autoload :Vips, "image_processing/vips"
12
31
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: image_processing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 4.0.3
108
+ rubygems_version: 4.0.13
109
109
  specification_version: 4
110
110
  summary: High-level wrapper for processing images for the web with ImageMagick or
111
111
  libvips.