Bug #5374

Weird SecurityError with ruby1.9, File.stat/Dir.glob and $SAFE=1

Added by Hleb Valoshka almost 4 years ago. Updated almost 3 years ago.

[ruby-core:39745]
Status:Closed
Priority:Normal
Assignee:Yusuke Endoh
ruby -v:ruby 1.9.2p180 (2011-02-18) [i386-mingw32] Backport:

Description

Preface.

I've tried to find workaroud for one GetText-Ruby bug with untainted data from Dir.glob (http://rubyforge.org//tracker/?func=detail&atid=3377&aid=28336&group_id=855).

Here it is (full text is in gettext-test.rb):

module GetText
class MOFile
alias :oldload :load
def load(arg)
arg = arg.dup.untaint if arg.kind_of? String
oldload(arg)
end
end
end

It works fine with ruby 1.8, but with 1.9 with debug enabled there is a
message about exception SecurityError:

Exception `SecurityError' at /usr/lib/ruby/1.9.1/gettext/runtime/mofile.rb:75 - Insecure operation - stat

The corresponding code is
74 begin
75 st = File.stat(arg)
76 @last_modified = [st.ctime, st.mtime]
77 rescue Exception
78 end

I've put line
warn "$SAFE == #{$SAFE}; arg.tainted? == #{arg.tainted?}"
before it, and it says:

$SAFE == 1; arg.tainted? == false

So why the exception is if arg is NOT tainted? Note: it was discovered on Debian
GNU/Linux box with 1.9.3preview1. Full log is in gettext-debian.log

Going further.

I've made very simple test program which mimics GetTExt-Ruby and workaround for
it, see test.rb in attachment.

This program was tested on Win32 box with 1.9.2-p180 and -p290.

Been run as "ruby -T1 test.rb u" output was clean. But been run as "ruby -T1
test.rb t" or "ruby -T1 test.rb t" is had an exception on files test1234.txt
and test12345.txt (see full test.log in attachment). 't' means "send tainted
object to function", 'u' means "send untainted", 'b' means "send tainted, then
untainted". But on Debian box it outputs NO error.

At last, I have run test for GetText on win box, and it failed with exception

Exception `SecurityError' at C:/fsc.tmp/gettext/runtime/locale_path.rb:90 - Insecure operation - glob

Log is in gettext-win.log

But whether Dir.glob is insecure with $SAFE==1?

test.rb Magnifier - tests for File.stat with (un)tainted arg (891 Bytes) Hleb Valoshka, 09/28/2011 04:02 AM

test.log Magnifier - output of test.rb on win32 (4.77 KB) Hleb Valoshka, 09/28/2011 04:02 AM

gettext-test.rb Magnifier - test for gettext workaround (470 Bytes) Hleb Valoshka, 09/28/2011 04:02 AM

gettext-debian.log Magnifier - output of former rb on debian... (1.73 KB) Hleb Valoshka, 09/28/2011 04:02 AM

gettex-win.log Magnifier - and on win32 (1.12 KB) Hleb Valoshka, 09/28/2011 04:02 AM

Associated revisions

Revision 36373
Added by Nobuyoshi Nakada almost 3 years ago

rb_str_new_frozen: new object if tainted/untrusted unmatch

  • string.c (rb_str_new_frozen): since the result object should have same tainted/untrusted bits with the original object, return new object if the shared object unmatch. [Bug #5374]

Revision 36373
Added by Nobuyoshi Nakada almost 3 years ago

rb_str_new_frozen: new object if tainted/untrusted unmatch

  • string.c (rb_str_new_frozen): since the result object should have same tainted/untrusted bits with the original object, return new object if the shared object unmatch. [Bug #5374]

History

#1 Updated by Hleb Valoshka almost 4 years ago

#2 Updated by Koichi Sasada over 3 years ago

  • Assignee set to Yusuke Endoh

#3 Updated by Nobuyoshi Nakada over 3 years ago

  • Status changed from Open to Feedback

Does this happen with recent versions?

#4 Updated by Hleb Valoshka almost 3 years ago

nobu (Nobuyoshi Nakada) wrote:

Does this happen with recent versions?

Yes, at least with 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux].

And today I've made some investigations.

File.stat is rb_file_s_stat, which calls rb_get_path, which calls rb_get_path_check, which at very end calls rb_str_new4, which actually is rb_str_new_frozen.

As value passed to rb_str_new_frozen (filename) isn't frozen, it creates new string (see file string.c, line 679):
if (STR_SHARED_P(orig) && (str = RSTRING(orig)->as.heap.aux.shared)) {...} and that "new" string is returned to rb_get_path_check.

This str is tainted!

I also have found more simple way to reproduce the bug:

ruby -e '$SAFE=1;File.stat(("12345678901234567890123"+"4".taint).dup.untaint)'

Argument to stat sh'ld be at least 24 bytes on 64bit box.

I haven't checked again bug with glob on Win32, but suppose that it has the same nature but it didn't expressed itself on my Debian boxes cause they are 64bit. In few days I can check it on 32bit Debian.

#5 Updated by Nobuyoshi Nakada almost 3 years ago

  • Status changed from Feedback to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r36373.
Hleb , thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


rb_str_new_frozen: new object if tainted/untrusted unmatch

  • string.c (rb_str_new_frozen): since the result object should have same tainted/untrusted bits with the original object, return new object if the shared object unmatch. [Bug #5374]

Also available in: Atom PDF