0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-11 02:59:07 +08:00
discourse/lib/freedom_patches/image_optim_sandbox.rb
David Taylor 7933776575
DEV: Tighten image_optim sandbox (#42473)
Create a dedicated tmp directory so that we don't have to grant
read/write access to the system-level tmp directory.
2026-08-10 14:31:37 +01:00

54 lines
1.7 KiB
Ruby
Vendored

# frozen_string_literal: true
require "image_optim/cmd"
require "image_optim/path"
require "tmpdir"
# Route image_optim's optimizer binaries through the Landlock sandbox, confining
# them to the file being optimized with no network. Cmd.capture (version/CPU
# probes, no untrusted input) is intentionally not patched.
class ImageOptim
# Per-thread tmp directory, so that we don't have to grant access to the global tmpdir
def self.discourse_tmp_root
Thread.current[:discourse_image_optim_tmp_root] ||= Dir.mktmpdir("discourse-image-optim-")
end
module DiscourseScratchDestination
def temp_path(*args, &block)
return super if args.any?
super(ImageOptim.discourse_tmp_root, &block)
end
end
ImageOptim::Path.prepend(DiscourseScratchDestination)
module Cmd
class << self
def run(*args)
options = args.last.is_a?(Hash) ? args.pop : {}
env = args.first.is_a?(Hash) ? args.shift : {}
files = args.select { |arg| arg.is_a?(String) && File.file?(arg) }
Discourse::SafeExec.capture(
*args,
env: {
**env,
"MALLOC_ARENA_MAX" => "2",
},
unsetenv_others: true,
read: [*Discourse::SafeExec.default_read_paths, *files],
write: [ImageOptim.discourse_tmp_root],
execute: Discourse::SafeExec.default_execute_paths,
timeout: options[:timeout]&.to_f || ImageMagick::DEFAULT_TIMEOUT,
rlimits: ImageMagick::RLIMITS,
seccomp_deny_network: true,
)
true
rescue Discourse::Utils::CommandError
# non-zero exit means "kept the original", like system(*args) => false
false
end
end
end
end