Upstream has issued an advisory on December 16: https://www.ruby-lang.org/en/news/2015/12/16/unsafe-tainted-string-usage-in-fiddle-and-dl-cve-2015-7551/ The issue is fixed upstream in 2.2.4 and 2.0.0-p648: https://www.ruby-lang.org/en/news/2015/12/16/ruby-2-0-0-p648-released/ https://www.ruby-lang.org/en/news/2015/12/16/ruby-2-2-4-released/ Note that 2.0.0 will be EOL in February, so we really should upgrade Mageia 5 to 2.2.x if possible. Reproducible: Steps to Reproduce:
Whiteboard: (none) => MGA5TOO
Updated package uploaded for Cauldron by Pascal. Updated package uploaded for Mageia 5. Advisory: ======================== Updated ruby packages fix security vulnerability: There is an unsafe tainted string vulnerability in Fiddle and DL. This issue was originally reported and fixed with CVE-2009-5147 in DL, but reappeared after DL was reimplemented using Fiddle and libffi (CVE-2015-7551). References: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-7551 https://www.ruby-lang.org/en/news/2015/12/16/unsafe-tainted-string-usage-in-fiddle-and-dl-cve-2015-7551/ https://www.ruby-lang.org/en/news/2015/12/16/ruby-2-0-0-p648-released/ ======================== Updated packages in core/updates_testing: ======================== ruby-2.0.0.p648-1.mga4 libruby2.0-2.0.0.p648-1.mga4 ruby-doc-2.0.0.p648-1.mga4 ruby-devel-2.0.0.p648-1.mga4 ruby-tk-2.0.0.p648-1.mga4 ruby-irb-2.0.0.p648-1.mga4 from ruby-2.0.0.p648-1.mga4.src.rpm
Whiteboard: MGA5TOO => (none)Source RPM: ruby-2.2.3-10.mga6.src.rpm => ruby-2.0.0.p645-1.mga5.src.rpmAssignee: pterjan => qa-bugsVersion: Cauldron => 5CC: (none) => pterjan
mga5 x86_64 Mate [lcl@vega ~]$ sudo urpmi lib64ruby2.0 Package lib64ruby2.0-2.0.0.p645-1.mga5.x86_64 is already installed I have been trying to establish a proof of concept for this but have not got very far. Looking at the CVEs it appears that the security problem lies in the area of Fiddle and DL. First of all I tried to find out what fiddle is all about From CVE-2015-7551 handle = Fiddle::Handle.new(dangerous_user_input) handle = Fiddle::Handle.new(some_library) function_pointer = handle[dangerous_user_input] ----------------------------------------------- From Ruby doc site: standardlib = "/lib64/libc.so.6" => "/lib64/libc.so.6" @handle = Fiddle::Handle.new( standardlib ) => #<Fiddle::Handle:0x00000000d69ef8> # return symbol for address of method strcpy_ptr = @handle['strcpy'] # alternative strcpy_ptr = @handle.sym( 'strcpy' ) ----------------------------------------------- According to CVE-2015-7551 the fault affects "All ruby 2.0 versions prior to ruby 2.0.0 patchlevel 648", which means we are affected. From https://www.ruby-lang.org/en/news/2013/05/14/taint-bypass-dl-fiddle-cve-2013-2065/ I extracted some code and scripted it: #!/bin/env/ ruby require 'dl' require 'fiddle' def my_function(user_input) handle = DL.dlopen(nil) sys = Fiddle::Function.new(handle['system'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) sys.call user_input end $SAFE = 1 my_function "uname -rs".taint puts my_function [lcl@vega ~]$ ruby taint.rb DL is deprecated, please use Fiddle taint.rb:9:in `call': tainted parameter not allowed (SecurityError) from taint.rb:9:in `my_function' from taint.rb:13:in `<main>' I don't know what "tainted" actually means in this context but it looks like the system responds correctly to a "tainted" object but is unable to check taintedness for some types of objects. So I am guessing that the following might be a PoC. #!/bin/env/ ruby # unknown.rb require 'dl' require 'fiddle' def my_function(user_input) handle = DL.dlopen(nil) sys = Fiddle::Function.new(handle['system'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) sys.call user_input end $SAFE = 1 my_function "uname -rs".taint puts my_function [lcl@vega ~]$ ruby unknown.rb DL is deprecated, please use Fiddle Linux 4.1.15-tmb-desktop-1.mga5 unknown.rb:5:in `my_function': wrong number of arguments (0 for 1) (ArgumentError) from unknown.rb:14:in `<main>' Any advice?
CC: (none) => tarazed25
Sorry, the penultimate line should be: my_function "uname -rs" Copy and paste woes.
You are calling my_function a second time on the last line without argument, you probably want to combine the 2 lines into: puts my_function "uname -rs" or puts my_function("uname -rs")
Yes, I noticed that - our posts clashed in midair. #!/bin/env/ ruby # unknown.rb require 'dl' require 'fiddle' def my_function(user_input) handle = DL.dlopen(nil) sys = Fiddle::Function.new(handle['system'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) sys.call user_input end $SAFE = 1 my_function "uname -rs" [lcl@vega ~]$ ruby unknown.rb DL is deprecated, please use Fiddle Linux 4.1.15-tmb-desktop-1.mga5 Which proves nothing, leaving the question how to construct a tainted string?
Streamlined the scriptlet to get rid of DL. #!/bin/env/ ruby require 'fiddle' def my_function( user_input ) libc = Fiddle.dlopen( '/lib64/libc.so.6' ) handle = libc['system'] sys = Fiddle::Function.new( handle, [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT ) sys.call user_input end $SAFE = 1 my_function "uname -rs".taint
Installed the updates as listed and tried the amended test script again. Having read somewhere that user input is unsafe by default I inserted a line to wait for input of the command from the user, 'uname -rs' in this case. #!/bin/env ruby # poc.rb => poc require 'fiddle' def my_function( user_input ) libc = Fiddle.dlopen( '/lib64/libc.so.6' ) handle = libc['system'] sys = Fiddle::Function.new( handle, [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT ) sys.call user_input end $SAFE = 0 command = gets.chomp my_function command puts "User input is treated as unsafe" if command.tainted? $ chmod +x poc $ ./poc uname -rs Linux 4.1.15-tmb-desktop-1.mga5 User input is treated as unsafe Change the security level to 1 ($SAFE = 1) and run again. $ ./poc uname -rs ./poc:8:in `call': tainted parameter not allowed (SecurityError) from ./poc:8:in `my_function' from ./poc:12:in `<main>' So, no change in behaviour after the update. I had been hoping for a SecurityError whichever security level is applied. The script was run in irb as well. So I am letting go at this point and running general tests of ruby. The taintedness needs to be introduced into the Fiddle operations somehow else. Used 'ri Fiddle > fiddler' to dump documentation of the Fiddle extension to a file and tested gem install. Ran several of my own interactive gui ruby-tk scripts without any problem. [lcl@vega ~]$ sudo gem install mplayer-ruby Successfully installed mplayer-ruby-0.2.0 Parsing documentation for mplayer-ruby-0.2.0 Done installing documentation for mplayer-ruby after 0 seconds 1 gem installed No regressions noted so far so, with reservations regarding the PoC, I am marking this as OK for 64-bits.
Whiteboard: (none) => MGA5-64-OK
Reading about this, the difference seems to be when using $SAFE > 0 I understand it should raise SecurityErrror if the filename is tainted and you try to dlopen it
Ah sorry I had missed that in comment 2 you were already getting the security error with $SAFE=1, it's probably a specific case then
https://github.com/ruby/ruby/commit/073cc5e815fcf5178fe4e515fcde74dc3597adeb adds some tests for it: + def test_safe_handle_open + t = Thread.new do + $SAFE = 1 + Fiddle::Handle.new(LIBC_SO.taint) + end + assert_raise(SecurityError) { t.value } + end + + def test_safe_function_lookup + t = Thread.new do + h = Fiddle::Handle.new(LIBC_SO) + $SAFE = 1 + h["qsort".taint] + end + assert_raise(SecurityError) { t.value } + end
On Mageia 5: $ ruby -rfiddle -e 't = Thread.new{ $SAFE = 1; Fiddle::Handle.new("libc.so.6".taint)}; t.value' $ On cauldron: $ ruby -rfiddle -e 't = Thread.new{ $SAFE = 1; Fiddle::Handle.new("libc.so.6".taint)}; t.value' -e:1:in `initialize': Insecure operation - initialize (SecurityError) from -e:1:in `new' from -e:1:in `block in <main>' $
Thanks for those pointers. Shall have a look at these tests on another machine with respect to pre and post updates. We are not in too much of a hurry for these I hope.
mga5 x86_64 Mate Before the update the following two commands were accepted, without any security errors. $ ruby -rfiddle -e 't = Thread.new{ $SAFE = 1; Fiddle::Handle.new("libc.so.6".taint) }; t.value' $ ruby -rfiddle -e 't = Thread.new{ c = Fiddle::Handle.new("libc.so.6") $SAFE = 1; c["qsort".taint] }; t.value' After the update the unsafe operations were trapped. For the handle open: -e:1:in `initialize': Insecure operation - new (SecurityError) from -e:1:in `new' from -e:1:in `block in <main>' For the function lookup: -e:2:in `[]': Insecure operation: -r (SecurityError) from -e:2:in `block in <main>' The two commands can be regarded as a minimal PoC.
Created attachment 7334 [details] Minimal PoC for ruby Fiddle class Command line tests supplied with help from Pascal Terjan. Before the update unsafe input is not trapped. After the correction the commands should fail with a SecurityError.
Created attachment 7335 [details] Minimal PoC for ruby Fiddle class Thanks to Pascal Terjan for these commands. Before the update neither command should provide any error output. After the update they both trap the unsafe operations and raise a SecurityError.
Attachment 7334 is obsolete: 0 => 1
Created attachment 7336 [details] JPEG display test A simple test for ruby-tk. tkimg should be installed.
mga5 i586 vbox Mate Ran the minimal PoC test before and after the update with the same results as in the 64-bit case. Installed a gem, used irb and called rubyimage.rb on the command line. Everything looks OK.
Whiteboard: MGA5-64-OK => MGA5-64-OK MGA5-32-OK has_procedure
CC: (none) => sysadmin-bugsKeywords: (none) => validated_update
Advisory added using ruby-2.0.0.p648-1.mga5 source rpm.
CC: (none) => davidwhodginsWhiteboard: MGA5-64-OK MGA5-32-OK has_procedure => MGA5-64-OK MGA5-32-OK has_procedure advisory
An update for this issue has been pushed to Mageia Updates repository. http://advisories.mageia.org/MGASA-2016-0007.html
Status: NEW => RESOLVEDResolution: (none) => FIXED