<div dir="ltr"><div>Hi LucianC,</div><div><br></div><div>I am perfectly agree with your clarifications and managed to reproduce your example on my 32 bits system by changing SLEEP_GOT_OFFSET and SLEEP_LOADED_ADDR accordingly with the values where the got sleep starts.</div><div>I perfectly understand what is happening there and I think would be more clearly (just as an addition) if we see the assembly code compiled with o3 in the both scenarios:</div><div><br></div><div>- without the volatile qualifier</div><div><br></div><div> 80485df: 81 7a 18 80 b0 1c 00 cmp DWORD PTR [edx+0x18],0x1cb080</div><div> 80485e6: 74 08 je 80485f0 <main+0x100></div><div> 80485e8: eb fe jmp 80485e8 <main+0xf8><span class="Apple-tab-span" style="white-space:pre"> </span>(*)</div><div> 80485ea: 8d b6 00 00 00 00 lea esi,[esi+0x0]</div><div> 80485f0: c7 44 24 04 fa 87 04 mov DWORD PTR [esp+0x4],0x80487fa</div><div> 80485f7: 08</div><div><br></div><div>the compiler compares just once *(got_start+SLEEP_GOT_OFFSET) from memory with the SLEEP_LOADED_ADDR assuming </div><div>that *(got_start+SLEEP_GOT_OFFSET) in memory will never by updated and then it remains in while (1) (*).</div><div><br></div><div>- with the volatile qualifier</div><div> 80485e8: 8b 02 mov eax,DWORD PTR [edx]</div><div> 80485ea: 3d 80 b0 1c 00 cmp eax,0x1cb080</div><div> 80485ef: 75 f7 jne 80485e8 <main+0xf8></div><div>the compiler compares in each loop with the value from memory.</div><div><br></div><div>Thanks for your clarifications, and for the example of why is needed to use the volarile qualifier in relation with the GOT.</div><div><br></div><div>Alex</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 28, 2014 at 10:11 PM, Lucian Cojocar <span dir="ltr"><<a href="mailto:cojocar@rosedu.org" target="_blank">cojocar@rosedu.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 10/28/2014 01:43 PM, Lucian Mogosanu wrote:<br>
> On Tue, Oct 28, 2014 at 02:22:57PM +0200, Alex Teaca wrote:<br>
>> Hello,<br>
>><br>
>> I see in get_got routine that the plt_ptr, got_min and got_max<br>
>> variables are marked with the volatile keyword.<br>
>> What is its purpose, is there a danger for these variables<br>
>> to be modified, and the compiler don't see it ?<br>
><br>
> Not sure about got_min and got_max, but plt_ptr *must* be volatile. What the<br>
> volatile keyword does is it tells the compiler to not make any assumptions<br>
> about the data stored at that particular pointer (e.g. the compiler could make<br>
> the assumption that the value at plt_ptr doesn't change during execution, when<br>
> in fact it does/it may, only this is done transparently by the OS when some<br>
> plt-linked library function gets called).<br>
><br>
<br>
<br>
</span>got_{min,max} should not be volatile, error on our side.<br>
<br>
The PLT is actually code (trampoline code, but still code), so plt_ptr<br>
points to code region, no need for volatile keyword here, so another<br>
error on our side.<br>
<br>
The case that Lucian is mentioning relates with the GOT, the GOT is the<br>
only one that the 'OS' changes during execution, basically, the GOT<br>
holds the offsets (which are runtime information) of the called symbols.<br>
For this, we *should have marked* the 'got_start' pointer volatile,<br>
however, the code still works (even with -O3). Why is that?<br>
<br>
Let's look at how got_start is used, after it is computed.<br>
<br>
"""<br>
get_got_for_sleep(void)<br>
{<br>
...<br>
memcpy(old_got, got_start, size);<br>
sleep(1);<br>
memcpy(new_got, got_start, size);<br>
...<br>
}<br>
<br>
"""<br>
<br>
The call of sleep function is a 'sequence point'[1], meaning that all<br>
"the side effects of previous evaluations will have been performed".<br>
Memcopy is not a 'pure'[2] function, meaning that it has side effects.<br>
So this guarantees that memcpy will be actually called two times, with<br>
got_start as second parameter. Anyway, this behavior does not need<br>
advanced explanation.<br>
<br>
The second usage of got_start is here:<br>
<br>
"""<br>
*got_sleep = *got_puts;<br>
*got_kill = *got_system;<br>
<br>
my_func();<br>
<br>
"""<br>
So another sequence point.<br>
<br>
But how we can show that volatile can be useful?<br>
<br>
Use the code from here[3]. If you computed the offsets correctly and if<br>
compiled with O3, the code should block when got_start is not volatile<br>
and it should 'unblock' when got_start is volatile.<br>
<br>
P.S. [3]s/'sleep plt'/'sleep ptr'/g<br>
P.P.S you may want to disable ASLR in order to get the same address of<br>
sleep function each time the binary is loaded.<br>
P(3).S Here are some things that might go wrong with volatile[4], even<br>
at compiler level.<br>
<br>
Hope this helps,<br>
Lucian<br>
<br>
[1]<a href="http://en.wikipedia.org/wiki/Sequence_point" target="_blank">http://en.wikipedia.org/wiki/Sequence_point</a><br>
[2]<a href="http://en.wikipedia.org/wiki/Pure_function" target="_blank">http://en.wikipedia.org/wiki/Pure_function</a><br>
[3]<a href="http://paste.debian.net/129140" target="_blank">http://paste.debian.net/129140</a><br>
[4]<a href="http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf" target="_blank">http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf</a><br>
<br>
LucianC<br>
_______________________________________________<br>
<a href="http://elf.cs.pub.ro/oss/wiki/resources/mailing-list" target="_blank">http://elf.cs.pub.ro/oss/wiki/resources/mailing-list</a></blockquote></div><br></div>