[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

non-constant strings

Dmitry Bilunov

8/7/2007 9:41:00 PM

Hello. Why does Ruby have non-constant strings? It seems there is a way
to bypass object encapsulation paradigm and break object integrity. Here
is any example:

class SecureRunner
# This class implements a sudo-like
# runner

def initialize(command)
# Creates an instance. Guaranties, that a command is safe.
if command.safe?
@comamnd = command
else
raise RuntimeError, "Security check failed!"
end
end

def run
# Only safe commands should be run
system(@command)
end
end

# This class seems to be safe
# Here is a way to bypass security check:

command = "some_safe_command"
runner = SecureRunner.new(command)
# a command is safe, so check will be passed

command.replace("evil_command") # BYPASS THE CHECK

runner.run # runs evil_command, that is not safe

The same can be done to fields of instances, which are exported as
read-only (attr_reader). I know there is a way to fix it (using .clone
or .dup), but what is the reason Ruby has non-constant strings, as most
languages (Java, Python) do? Is there a way to disable such behaviour
($SAFE will not help, because internal class methods will not be able to
change instance-variable strings too).
--
Posted via http://www.ruby-....

12 Answers

skye.shaw

8/8/2007 7:42:00 AM

0

On Aug 7, 2:41 pm, Dmitry Bilunov <km...@kmeaw.com> wrote:
> Hello. Why does Ruby have non-constant strings? It seems there is a way
> to bypass object encapsulation paradigm and break object integrity. Here
> is any example:
>
> class SecureRunner
> # This class implements a sudo-like
> # runner
>
> def initialize(command)
> # Creates an instance. Guaranties, that a command is safe.
> if command.safe?

This will result in a no method error, no?

> @comamnd = command
> else
> raise RuntimeError, "Security check failed!"
> end
> end
>
> def run
> # Only safe commands should be run
> system(@command)
> end
> end
>
> # This class seems to be safe
> # Here is a way to bypass security check:
>
> command = "some_safe_command"
> runner = SecureRunner.new(command)
> # a command is safe, so check will be passed
>
> command.replace("evil_command") # BYPASS THE CHECK
> runner.run # runs evil_command, that is not safe

Well, this is not the fault of the language, rather your SecureRunner
class.

def run
# Only safe commands should be run
if @command.tainted?
raise RuntimeError, "Security check failed!"
end
system(@command)
end

> The same can be done to fields of instances, which are exported as
> read-only (attr_reader).

This is the case any language where arguments are passed by reference.

> but what is the reason Ruby has non-constant strings

You mean mutable strings. Ruby does have constant strings:

irb(main):001:0> CONST="assbasscass"
=> "assbasscass"
irb(main):002:0> CONST=123
(irb):2: warning: already initialized constant CONST
=> 123

The String class wraps an array of chars, realloc()'in as necessary
(ruby hackers correct me if I've mistakin).

Consider this in Java:

class SomeClassThatRequiredAlotOfTyping
{
private StringBuffer sb
//....
public void printBuffer() { System.out.println(sb); }
}

StringBuffer sb = new StringBuffer("Dont Chnage!");

SomeClassThatRequiredAlotOfTyping clazz = new
SomeClassThatRequiredAlotOfTyping(sb);
// I'll show that private "read-only" var who's in charge!
sb.delete(0,sb.length());
sb.append("VB6, its ByVal keyword rocked... Not!");
clazz.printBuffer();

Hope that helps.

Dmitry Bilunov

8/8/2007 7:58:00 AM

0

Skye Shaw!@#$ wrote:
> On Aug 7, 2:41 pm, Dmitry Bilunov <km...@kmeaw.com> wrote:
>> if command.safe?
> This will result in a no method error, no?
It is just an example, assume that you have some safety-checking code
here.

> Well, this is not the fault of the language, rather your SecureRunner
> class.
Yes, it is not fault of Ruby, I am just trying to understand, why do the
strings work in a such way. Most operations can be done with immutable
strings - an operation can return a new string, constructed from method
caller and, optionally, arguments.

> This is the case any language where arguments are passed by reference.
>> but what is the reason Ruby has non-constant strings
> You mean mutable strings. Ruby does have constant strings:
>
> irb(main):001:0> CONST="assbasscass"
> => "assbasscass"
> irb(main):002:0> CONST=123
> (irb):2: warning: already initialized constant CONST
> => 123
>
> The String class wraps an array of chars, realloc()'in as necessary
> (ruby hackers correct me if I've mistakin).
Ruby string has array of chars, length (logical array size) and capacity
(physical array size, probably larger, that logical) as Java's
StringBuffer does.

>
> Consider this in Java:
>
> class SomeClassThatRequiredAlotOfTyping
> {
> private StringBuffer sb
> //....
> public void printBuffer() { System.out.println(sb); }
> }
>
> StringBuffer sb = new StringBuffer("Dont Chnage!");
>
> SomeClassThatRequiredAlotOfTyping clazz = new
> SomeClassThatRequiredAlotOfTyping(sb);
> // I'll show that private "read-only" var who's in charge!
> sb.delete(0,sb.length());
> sb.append("VB6, its ByVal keyword rocked... Not!");
> clazz.printBuffer();
>
> Hope that helps.

But Java has also String, not just StringBuffer. Is there anything like
String to protect a program against such things? Or some version of
freeze, which freezes a variable (field) to anyone, except instance
methods?
--
Posted via http://www.ruby-....

Eric Hodel

8/8/2007 9:31:00 AM

0

On Aug 7, 2007, at 14:41, Dmitry Bilunov wrote:
> Hello. Why does Ruby have non-constant strings? It seems there is a
> way
> to bypass object encapsulation paradigm and break object integrity.

Ruby lets you shoot yourself in the foot.

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-...

> Is there a way to disable such behaviour ($SAFE will not help,
> because internal class methods will not be able to change instance-
> variable strings too).

Nope.

You can search the mailing list archives for further discussion on
the mutability of strings:

http://blade.nagaokaut.ac.jp/ruby/ruby-talk/i...

--
Poor workers blame their tools. Good workers build better tools. The
best workers get their tools to do the work for them. -- Syndicate Wars



Dmitry Bilunov

8/8/2007 9:37:00 AM

0

Eric Hodel wrote:
> On Aug 7, 2007, at 14:41, Dmitry Bilunov wrote:
>> Hello. Why does Ruby have non-constant strings? It seems there is a
>> way
>> to bypass object encapsulation paradigm and break object integrity.
>
> Ruby lets you shoot yourself in the foot.
>
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-...
>
>> Is there a way to disable such behaviour ($SAFE will not help,
>> because internal class methods will not be able to change instance-
>> variable strings too).
>
> Nope.
>
> You can search the mailing list archives for further discussion on
> the mutability of strings:
>
> http://blade.nagaokaut.ac.jp/ruby/ruby-talk/i...

Thanks. Mailing list discussion has exactly what I was looking for - the
explanation of the reason Ruby has mutable strings.
--
Posted via http://www.ruby-....

Dmitry Bilunov

8/8/2007 11:21:00 AM

0

dohzya wrote:
> Hi,
>
> 2007/8/7, Dmitry Bilunov <kmeaw@kmeaw.com>:
>> # Creates an instance. Guaranties, that a command is safe.
>> end
>>
>>
>>
> You want to freeze the object @command, not the class String, don't
> you ?
> So you don't need to use an Immutable_String class, just add
> @command.freeze in your code

It will make impossible changing @command inside instance methods (which
can be guaranteed to be safe). If there is a way to unfreeze a frozen
object, then this method could be called externally and one can gain
write access to an internal instance variable.
--
Posted via http://www.ruby-....

Jano Svitok

8/8/2007 11:51:00 AM

0

On 8/8/07, Dmitry Bilunov <kmeaw@kmeaw.com> wrote:
> dohzya wrote:
> > Hi,
> >
> > 2007/8/7, Dmitry Bilunov <kmeaw@kmeaw.com>:
> >> # Creates an instance. Guaranties, that a command is safe.
> >> end
> >>
> >>
> >>
> > You want to freeze the object @command, not the class String, don't
> > you ?
> > So you don't need to use an Immutable_String class, just add
> > @command.freeze in your code
>
> It will make impossible changing @command inside instance methods (which
> can be guaranteed to be safe). If there is a way to unfreeze a frozen
> object, then this method could be called externally and one can gain
> write access to an internal instance variable.

Not exactly.

@command is just a pointer to a string, incidentally pointing to same
string as command pointer points to.

So you have three things: 1. the string "safe_command" 2. variable
(=pointer) command, 3. member variable (=pointer) @command.

Now, if you issue @command.freeze, you are not freezing the pointer
@command, but the string it points to, i.e. "safe_command". So if you
do @command.freeze, it is the same as doing "safe_pointer".freeze.

After @command.freeze, you cannot do command.replace - because command
points to a frozen string. However, you can still do command = "abc",
i.e. make command point to another string.

Finally after @command.freeze, you can't do @command.replace either.
But you can do @command = "adsfg" and thus make the pointer point to
another string.

In fact, Hash#[]= dups and freezes String keys, just for the same reason.

Jano

Dmitry Bilunov

8/8/2007 11:57:00 AM

0

Jano Svitok wrote:
> On 8/8/07, Dmitry Bilunov <kmeaw@kmeaw.com> wrote:
>> It will make impossible changing @command inside instance methods (which
>> can be guaranteed to be safe). If there is a way to unfreeze a frozen
>> object, then this method could be called externally and one can gain
>> write access to an internal instance variable.
>
> Not exactly.
>
[cut]
>
> In fact, Hash#[]= dups and freezes String keys, just for the same
> reason.
>
> Jano

Thanks, now it makes sense for me.
--
Posted via http://www.ruby-....

Robert Klemme

8/8/2007 12:08:00 PM

0

2007/8/7, Dmitry Bilunov <kmeaw@kmeaw.com>:
> Hello. Why does Ruby have non-constant strings? It seems there is a way
> to bypass object encapsulation paradigm and break object integrity. Here
> is any example:
>
> class SecureRunner
> # This class implements a sudo-like
> # runner
>
> def initialize(command)
> # Creates an instance. Guaranties, that a command is safe.
> if command.safe?
> @comamnd = command
> else
> raise RuntimeError, "Security check failed!"
> end
> end
>
> def run
> # Only safe commands should be run
> system(@command)
> end
> end
>
> # This class seems to be safe
> # Here is a way to bypass security check:
>
> command = "some_safe_command"
> runner = SecureRunner.new(command)
> # a command is safe, so check will be passed
>
> command.replace("evil_command") # BYPASS THE CHECK
>
> runner.run # runs evil_command, that is not safe

That is easily fixed:

# Creates an instance. Guaranties, that a command is safe.
def initialize(command)
# side effect free fix:
command = command.dup
# alternative fix: command.freeze
if command.safe?
@comamnd = command
else
raise RuntimeError, "Security check failed!"
end
end

Now you can change the original string in as many ways as you like
without doing any harm. As easy as that.

And I'd like to add it's not the fault of the language if code like
this fails. In fact there are numerous arguments in favor of having
mutable *and* immutable strings vs. having mutable strings only.

Kind regards

robert

Kaldrenon

8/8/2007 1:52:00 PM

0

On Aug 8, 7:51 am, "Jano Svitok" <jan.svi...@gmail.com> wrote:
> On 8/8/07, Dmitry Bilunov <km...@kmeaw.com> wrote:
> > If there is a way to unfreeze a frozen
> > object, then this method could be called externally and one can gain
> > write access to an internal instance variable.
>
> Not exactly.

Shortest, closest thing I can think of for unfreezing an object is to
dup it.

a = "test" --> "test"
a.freeze --> 1
a << "test" --> TypeError
a = a.dup --> 1
a << "test" --> "testtest"

(sorry about the non-irb format...default command shell in WinXP
doesn't allow copy/paste. *sigh*)


Robert Klemme

8/8/2007 2:05:00 PM

0

2007/8/8, Kaldrenon <kaldrenon@gmail.com>:
> On Aug 8, 7:51 am, "Jano Svitok" <jan.svi...@gmail.com> wrote:
> > On 8/8/07, Dmitry Bilunov <km...@kmeaw.com> wrote:
> > > If there is a way to unfreeze a frozen
> > > object, then this method could be called externally and one can gain
> > > write access to an internal instance variable.
> >
> > Not exactly.
>
> Shortest, closest thing I can think of for unfreezing an object is to
> dup it.
>
> a = "test" --> "test"
> a.freeze --> 1
> a << "test" --> TypeError
> a = a.dup --> 1
> a << "test" --> "testtest"

Just to make it clear: this is not unfreezing - it will just create a
new instance that is not frozen so the original is still safe.

> (sorry about the non-irb format...default command shell in WinXP
> doesn't allow copy/paste. *sigh*)

You can copy and past from any Windows command line shell. You can
even configure it so you can directly mark with the mouse and copy by
pressing enter.

Kind regards

robert