I have added DYNAMIC variant (with RVA operator available) and GNURELRO segment flag to fasm 1.73.07. You can now experiment yourself.

For instance, in my sample with writable section, you can replace WRITEABLE with GNURELRO, and example should still work. Not combined with DYNAMIC, though (because you have to remove INTERPRETER segment then).

Still, keep in mind that fasm's executable formatter was always supposed to be very simple, because I expected object ELF together with linker to be used for any more advanced things. I wonder if it would be possible to link fasm-produced ELF object with GCC and make a non-PIC PIE that way.

Small correction: PT_GNU_RELRO is actually an area inside another segment (a PT_LOAD one). Because of how segments are defined in fasm, such special kind of segment is merged with the next "regular" segment that follows it. So you need to define another segment after GNURELRO segment, and the GNURELRO one is going to be mapped as part of that later segment in memory.

Now if you look at Furs's GCC-made example, GNU_RELRO is actually a part of PT_LOAD segment that has RW attributes. So I was wrong when I wrote earlier that loader must be temporarily applying writable attribute. The segment is writable from the start, it is only after the relocations are applied that it is set to "read only". The description of PT_GNU_RELRO is actually quite accurate here.

Therefore that GCC executable does not in fact relocate the executable segment, it only applies relocations to an RW segment and then - because of PT_GNU_RELRO mapping - gets it changed to read-only.

Back to fasm: when I wrote that in my sample you can replace WRITABLE with GNURELRO, it only worked because there is actually a regular writable segment that follows. And to make this work cleanly, you should make it like this:

Now if you remove "writeable" from that "parent" segment, the relocation is going to fail (with segfault).

The simple formatter of fasm 1 is not really a good framework to play freely with all these settings, it is limited by its linear segment syntax. But with fasmg's macros I could make a different framework with more flexible options - perhaps in my tutorial's second chapter I'm going to make something like that.

With 1.73.07 the previous code I posted doesn't compile. It gives the message "error: invalid use of symbol." Which is a good thing. We are alerted to the fact that the address isn't knowable at compile time.

So one tiny change is applied; the RVA operator. Full code below shows this in action

Running at 0x56623000 Stack at 0xFFBA2850
Running at 0x56648000 Stack at 0xFF925310
Running at 0x56592000 Stack at 0xFFD23FA0
Running at 0x565E8000 Stack at 0xFFF24500
Running at 0x565E4000 Stack at 0xFFF77020
Running at 0x56651000 Stack at 0xFFC6DB00
Running at 0x56586000 Stack at 0xFFAB5F80
Running at 0x56652000 Stack at 0xFF877930
Running at 0x56620000 Stack at 0xFFC43AC0
Running at 0x565A8000 Stack at 0xFFE8CEA0

You'll have to ignore the 64-bit disassembly and just look at the lower 32-bits of the address. It still has the zero-based addresses in there. So this .so file will crash as it stands if there is no code to parse the '.rel.dyn' section.

When execution starts only the Linux interpreter and the main exe are loaded. All other library files are missing. So it is the interpreter that does all the dynamic linking and parses the relocations.

So all the loader is doing for us is to load the main exe and the interpreter. It then jumps to the interpreter entry point and its job is done.

It creates a reloc section manually by prefixing the affect instructions with the "r" macro. And at startup it runs a small loop to relocate all the affected places. It doesn't mark the segment un-writeable or link any .so libraries, but it does successfully relocate the immediate addressing instructions. Although it only works correctly when the origin is zero, but that could easily be fixed.

It still needs the rva in there. But if fasm could generate a reloc section like it does for PE then the rva requirement could be lifted and assume that it will be relocated.

This would also work for a normal executable (not dynamic) but since Linux won't use ASLR on such files there isn't any point.

I also discovered a crash bug in fasm.. Try enabling the line with the "align 4". It segfaults.

I think the best approach here is to have our own relocation code running, as in my example above. Even of we are linking to other libraries and the interpreter would do the relocations for us, it gives us less flexibility and requires us to manipulate the segments to match precisely the "proper" format.

The relocation code is only 11 instructions. We can set the write permissions according to our own requirements. We don't need any interpreter when our code is stand-alone and only needs the kernel. The only remaining task is to have the assembler automatically mark all the relocatable address and write the table for us.

The only remaining task is to have the assembler automatically mark all the relocatable address and write the table for us.

I know you have said that fasmg is not a good option for you because of macro conversion issues, but I should mention that it would be quite easy to do with it. The Adding relocations section of my PE tutorial demonstrates a simple method.

There are no execute permissions in the code. But Linux always sets the segments to executable. And using mprotect won't change that either.

So any and all data allocated by the program can also be executed. Including the stack. The only exceptions I can find are for file mappings that are opened as read-only and the vvar segment mapped from the kernel. Everything else is freely executable.

Last edited by revolution on 08 Feb 2019, 17:20; edited 1 time in total

This is where Linux is in fact similar to Windows, where "executable" attribute of PE section is not really respected unless you have IMAGE_DLLCHARACTERISTICS_NX_COMPAT flag set.
In Linux equivalent of this flag is inclusion of a segment of type PT_GNU_STACK. The attributes of this segment are supposed to define access permissions of the stack, but for some reason this also enables the NX feature for ELF segments overall.

A single line is enough to set this up (like, for example, in fasmg source):

This is where Linux is in fact similar to Windows, where "executable" attribute of PE section is not really respected unless you have IMAGE_DLLCHARACTERISTICS_NX_COMPAT flag set.
In Linux equivalent of this flag is inclusion of a segment of type PT_GNU_STACK. The attributes of this segment are supposed to define access permissions of the stack, but for some reason this also enables the NX feature for ELF segments overall.

A single line is enough to set this up (like, for example, in fasmg source):

So it would appear as though we are always stuck in the address range 0x56555000 to 0x56654000. However this isn't so. We can get another address range, but it requires changing a setting. Once again using setarch we can us the 3gb switch "setarch `uname -m` -3R <progname>"

Code:

Running at 0x41000000 Stack at 0xBFFFEF20
...
Running at 0x41000000 Stack at 0xBFFFEF20

And we are then constrained to the range 0x41000000 to 0x410ff000.

I find the chosen address ranges disappointing. It cuts a slice in the address space and will limit the maximum size of any memory allocation. I haven't looked for the source code but it seems that it is just applying this formula.

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot vote in polls in this forumYou cannot attach files in this forumYou can download files in this forum