Bugs: Browse | Submit New | Admin
When SAFE is on, it is not possible to load a .mo-file. Reproduceable code: require "gettext" include GetText ENV["LANGUAGE"] = "da_DK" GetText.bindtextdomain("locales", File.dirname(__FILE__) + "/../locales", "da_DK") print _("Test") Fails with: index.rhtml:0: Insecure operation - initialize It does not help to untaint any of the variables given to bindtextdomain. No backtrace. I manually traced it back to the file: "gettext/runtime/mofile.rb" lines 273 - 281 the code: def load_from_file(filename) @filename = filename begin File.open(filename, 'rb'){|f| load_from_stream(f)} rescue => e e.set_backtrace("File: #{@filename}") raise e end end Since the variable "filename" is "frozen" it cannot be "untaint". Therefore the following replace solves the problem: def load_from_file(filename) @filename = filename fn = String.new(filename) fn.untaint begin File.open(fn, 'rb'){|f| load_from_stream(f)} rescue => e e.set_backtrace("File: #{@filename}") raise e end end Further more this would have been A LOT easier if there wasnt a "e.set_backtrace; raise e". Why is that there anyway? If you remove the begin-rescue-end an easy backtrace is shown. OS: Ubuntu 10.04, i386 Ruby -v: ruby 1.8.7 (2010-01-10 patchlevel 249) [i486-linux] gettext versions tried: The one from Ubuntu-packages and the one from gems
Add A Comment:
Date: 2011-09-24 10:44 Sender: Hleb Valoshka Kasper, your solution is incomplete, because in file runtime/mofile.rb, line 75 we have File.stat with that tainted filename (okay, it's inside begin-rescue, but we still need it to work). So it seems better to redefine GetText::MOFile.load (anyway, it's just a temporary solution) [Change 1]: module GetText class MOFile alias :oldload :load def load(arg) arg = arg.dup.untaint if arg.kind_of? String oldload(arg) end end end But the code responsible for the exception residents in gettext/runtime/locale_path.rb line 92 (the corresponding function is ``initialize''): 90 Dir.glob(rule %{:lang => "*", :name => name}).each do |path| 91 if /#{this_path_rules}/ =~ path 92 @locale_paths[$1] = path unless @locale_paths[$1] 93 end 94 end The fix is to change that line to [Change 2] @locale_paths[$1] = path.untaint unless @locale_paths[$1] It's because results of Dir.glob are considered to be insecure. But it's not enough, if we want to use ruby 1.9! The next problem is Locale.require_driver, we need to ``untaint'' argument to ``require'' [Change 3]: module Locale module_function def require_driver(name) #:nodoc: require File.join(ROOT, "locale/driver", name.to_s).untaint end end So, ``Change 1'' is a quick fix to make your program work under ruby 1.8. But it's under 1.9 we still have exception on File.stat at runtime/mofile.rb, line 75, and I don't know why. The library will basically work, but there will be issues with MOFile#update!. ``Change 3'' can be used as a quick fix in your program too. With ``Change 2'' (and 3 too) applied to library itself any program works with $SAFE=1.
Date: 2010-07-04 12:23 Sender: Kasper Johansen Hi Masao. Thank you for responding. I was running it through mod_ruby, where safe-mode is enabled by default. If the test should fail, then the mo-file has to exist, or else the spawning-code wont be called and you wont get the error, which I guess is why you cant reproduce. Any .mo-file should do it.
Date: 2010-07-04 01:10 Sender: Masao Mutoh > Further more this would have been A LOT easier if there wasnt a "e.set_backtrace; raise e". Why is that there anyway? I thought it' better to know know the filename which causes the error.
Date: 2010-07-04 00:52 Sender: Masao Mutoh How did you set SAFE to ON ? If you mean you set $SAFE=1, I couldn't reproduce your problem with your script. % cat test.rb $SAFE=1 require "gettext" include GetText ENV["LANGUAGE"] = "da_DK" GetText.bindtextdomain("locales", File.dirname(__FILE__) + "/../locales", "da_DK") puts _("Test") p GetText::VERSION [mutoh@linux]~/dev/git/gettext/test% ruby -v -rubygems test.rb ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux] Test "2.1.0" -- And what is index.rhtml ? Does it mean you use your sample code file name with something like a web framework? If so, how can I run it?