I really don't understand why this doesn't crash

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

I really don't understand why this doesn't crash

Mariano Martinez Peck
 
Hi guys. I would really appreciate if someone could explain me the following. I have this class:

Object subclass: #FooClass
    instanceVariableNames: 'var1 var2 var3 var4 var5'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Prueba'

With this method:

FooClass >> foo
    Transcript show: var5 asString.

And then I have this class:

Object subclass: #AnotherClass
    instanceVariableNames: 'age'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Prueba'


Now, I run this test:

    | inst |
    inst := AnotherClass new.
    inst age: 42.
    (FooClass >> #foo) valueWithReceiver: inst arguments: #()
   

So...I am evaluating the CompiledMethod installed on #foo on "inst". The compiledMethod has a bytecode (04) for accessing the var5. But "inst" only have one instVar. So....shouldn't that be a crash? because the VM is accessing outside the object... so, the test doesn't crash and in fact, it prints "1". I don't know what number means.

I took a look to

StackInterpreter >> pushReceiverVariable: fieldIndex

    self internalPush: (objectMemory fetchPointer: fieldIndex ofObject: self receiver).

But I guess that should crash.

Thanks for any tip,


--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

Re: I really don't understand why this doesn't crash

Gerardo Richarte
 
On 05/18/2011 05:40 AM, Mariano Martinez Peck wrote:

> Now, I run this test:
>
>     | inst |
>     inst := AnotherClass new.
>     inst age: 42.
>     (FooClass >> #foo) valueWithReceiver: inst arguments: #()
>    
>
> So...I am evaluating the CompiledMethod installed on #foo on "inst".
> The compiledMethod has a bytecode (04) for accessing the var5. But
> "inst" only have one instVar.
may be it IS accessing outside the bounds of the object, but "luckily"
peeking at another object, where there is a 1. var5 is the 5th slot, and
that'll probably be in the middle of the next object. Try other's, for
example, var2, which would be the bytes just after the object, and quite
likely the pre-header of the next object, which, may or may not be a
valid oop... what's in the first word of Squeak objects? does it look
like a tagged object (integer)? I know there are different formats of
objects, and I don't really need an answer, but that's the question you
should be answering :)

of course another option is if fetchPointer:ofObject: does any bounds
checking, in which case I don't understand what the 1 means.

and lastly but not less, you have found 2 security problems in the VM
(may be just one, ok).

The first one is at a language level, where you can break the
encapsulation of objects by executing an arbitrary CompiledMethod in any
object.

The second is more severe in my opinion, and it's that you can access
(read and also write) arbitrary memory addresses in the VM process, and
that normally means arbitrary native code execution. This bug is not due
to valueWithReceiver: but rather because fetchPointer:ofObject: and the
writing counterpart, don't check bounds.

    gera

    gera
Reply | Threaded
Open this post in threaded view
|

Re: I really don't understand why this doesn't crash

Mariano Martinez Peck
 


On Wed, May 18, 2011 at 2:12 PM, Gerardo Richarte <[hidden email]> wrote:

On 05/18/2011 05:40 AM, Mariano Martinez Peck wrote:
> Now, I run this test:
>
>     | inst |
>     inst := AnotherClass new.
>     inst age: 42.
>     (FooClass >> #foo) valueWithReceiver: inst arguments: #()
>
>
> So...I am evaluating the CompiledMethod installed on #foo on "inst".
> The compiledMethod has a bytecode (04) for accessing the var5. But
> "inst" only have one instVar.
may be it IS accessing outside the bounds of the object, but "luckily"
peeking at another object, where there is a 1. var5 is the 5th slot, and
that'll probably be in the middle of the next object. Try other's, for
example, var2, which would be the bytes just after the object, and quite
likely the pre-header of the next object, which, may or may not be a
valid oop... what's in the first word of Squeak objects? does it look
like a tagged object (integer)? I know there are different formats of
objects, and I don't really need an answer, but that's the question you
should be answering :)

That's exactly what I think it is happening. I am just accessing slot of other object. Likely I am still inside the ObjectMemory of the VM.
Maybe if this happens to the last object I could go outside and crash.


of course another option is if fetchPointer:ofObject: does any bounds
checking, in which case I don't understand what the 1 means.

and lastly but not less, you have found 2 security problems in the VM
(may be just one, ok).

The first one is at a language level, where you can break the
encapsulation of objects by executing an arbitrary CompiledMethod in any
object.

Yes, but this is already possible with some other primitives ;)
 

The second is more severe in my opinion, and it's that you can access
(read and also write) arbitrary memory addresses in the VM process, and
that normally means arbitrary native code execution. This bug is not due
to valueWithReceiver: but rather because fetchPointer:ofObject: and the
writing counterpart, don't check bounds.


yes.
What I wonder, and what I would really like to know is the reason why NOT to check bounds. Is all about speed?

Thanks


--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

Re: I really don't understand why this doesn't crash

Gerardo Richarte
 
On 06/15/11 05:05, Mariano Martinez Peck wrote:

and lastly but not less, you have found 2 security problems in the VM
(may be just one, ok).

The first one is at a language level, where you can break the
encapsulation of objects by executing an arbitrary CompiledMethod in any
object.

Yes, but this is already possible with some other primitives ;)
It'd be very interesting to build a list of those primitives, what others
do you have in mind? In any case, I think there is a subtle difference
between a bytecode and a primitive.  A primitive can be effectively
stopped at language level, by not exposing a method, or discretionary
exposing it, or not making reachable the object implementing it. A
bytecode is different, and has to be checked by the interpreter-jit
(runtime environment in general). Well, I think


What I wonder, and what I would really like to know is the reason why NOT to check bounds. Is all about speed?

I think yes, it is speed: if every bytecode had to check it, it'd be a
strong degradation of performance. A more complex implementation
could have a /bytecode verifier/, to check, when then native code is
emitted, if the structure of the receiver, in this case, is suitable for
the code. In an interpreter similar checks could be done, once the
first time a method is going to be activated in a certain receiver
(if instance methods are not possible in the system, this could be
cached per class, otherwise some little more complex checks have
to be implemented.

As a note, the Java VM and the Flash VM, at least, have strong bytecode
verifiers specifically for security reasons.

    gera


Thanks


--
Mariano
http://marianopeck.wordpress.com


Reply | Threaded
Open this post in threaded view
|

Re: I really don't understand why this doesn't crash

Mariano Martinez Peck
 


On Sat, Jun 18, 2011 at 4:20 PM, Gerardo Richarte <[hidden email]> wrote:
 
On 06/15/11 05:05, Mariano Martinez Peck wrote:

and lastly but not less, you have found 2 security problems in the VM
(may be just one, ok).

The first one is at a language level, where you can break the
encapsulation of objects by executing an arbitrary CompiledMethod in any
object.

Yes, but this is already possible with some other primitives ;)
It'd be very interesting to build a list of those primitives, what others
do you have in mind?

mmmm I have in mind only yhe two that are for executing CompiledMethod in an object. Those are primitive 188 and 189.
    "Perform method directly"
        (188 primitiveExecuteMethodArgsArray)
        (189 primitiveExecuteMethod)

But that ony happens by using the bytecode as we saw in this example. I have no idea whether the same can happens from another place.


 
In any case, I think there is a subtle difference
between a bytecode and a primitive. 

+1
 
A primitive can be effectively
stopped at language level, by not exposing a method, or discretionary
exposing it, or not making reachable the object implementing it. A
bytecode is different, and has to be checked by the interpreter-jit
(runtime environment in general). Well, I think


What I wonder, and what I would really like to know is the reason why NOT to check bounds. Is all about speed?

I think yes, it is speed: if every bytecode had to check it, it'd be a
strong degradation of performance.

Do you know what happens in other Smalltalk VMs in this concrete case for example?
 
A more complex implementation
could have a /bytecode verifier/, to check, when then native code is
emitted, if the structure of the receiver, in this case, is suitable for
the code. In an interpreter similar checks could be done, once the
first time a method is going to be activated in a certain receiver
(if instance methods are not possible in the system, this could be
cached per class, otherwise some little more complex checks have
to be implemented.

As a note, the Java VM and the Flash VM, at least, have strong bytecode
verifiers specifically for security reasons.


thanks, interesting :)

 
    gera


Thanks


--
Mariano
http://marianopeck.wordpress.com






--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

Re: I really don't understand why this doesn't crash

stephane ducasse-2
In reply to this post by Gerardo Richarte

>
>
> As a note, the Java VM and the Flash VM, at least, have strong bytecode
> verifiers specifically for security reasons.
>
>     gera

Gera

do they verify at execution time and cache?
I checked a while ago but there were essentially checking that the stack was balanced...
but it was long time ago.

Stef

Reply | Threaded
Open this post in threaded view
|

Re: I really don't understand why this doesn't crash

Michael Haupt-3

Hi,

Am 18.06.2011 um 20:43 schrieb stephane ducasse <[hidden email]>:
>
>>
>> As a note, the Java VM and the Flash VM, at least, have strong bytecode
>> verifiers specifically for security reasons.
>
> do they verify at execution time and cache?

verification takes place at load time, for all classes as they are loaded. Not afterwards. Also, keep in mind that Java's type system allows some guarantees once code is verified. (What do you mean by "cache"?)

> I checked a while ago but there were essentially checking that the stack was balanced...
> but it was long time ago.

They do a lot more than that. :-)
>

Check the spec:
http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html#71817
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#40222
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88597

Especially the second link is worthwhile.

Best,

Michael