Reputation: 394
I have come across this interesting StackOverflow post: How do you get the start and end addresses of a custom ELF section?
and I thought whether it might be possible to apply mprotect()
to the function which is stored in the custom ELF section.
However, I am getting a segmentation fault, and using the GDB leads to not very helpful information where I fail to understand its cause.
Here is a very simple test code:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#define PAGESIZE 4096
// Custom ELF section needs to be page-aligned to be mprotect
void foo() __attribute__((aligned(PAGESIZE))) __attribute__ ((section ("custom_sec")));
extern struct fun_info *__start_custom_sec;
extern struct fun_info *__stop_custom_sec;
int main()
{
// Sanity check.
printf("Custom section range: %p to %p\n",
(void *)&__start_custom_sec,
(void *)&__stop_custom_sec);
if(mprotect(&__start_custom_sec, getpagesize(), PROT_READ | PROT_WRITE) == -1) {
perror("mprotect()");
return 1;
}
}
void foo() { printf("Foo\n"); }
gcc stackoverflow.c -o so
./so
This will lead to the segmentation fault.
I noticed that instead of PROT_READ | PROT_WRITE
, I use PROT_EXEC
; I do not get such a segmentation fault. PROT_EXEC
, according to the documentation, simply means "this memory is enabled to be executed", so my conjecture is that when I use mprotect
to protect this custom ELF section with no execution permission, fini
function needs to execute the mprotect
ed memory region which is causing the segmentation fault. Hence, if I were to give PROT_EXEC
permission, this problem is fixed.
I got this conjecture based on the output from the GDB because even backtracing leads to very ambiguous results without much room for me to debug:
>>> bt
#0 0x0000555555555014 in _fini ()
#1 0x00007ffff7de8d88 in _dl_fini () at dl-fini.c:240
#2 0x00007ffff7a6f940 in __run_exit_handlers (status=0, listp=0x7ffff7dd35d8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true, run_dtors=run_dtors@entry=true) at exit.c:83
#3 0x00007ffff7a6f99a in __GI_exit (status=<optimized out>) at exit.c:105
#4 0x00007ffff7a5a2e8 in __libc_start_main (main=0x5555555547e0 <main>, argc=1, argv=0x7fffffffe518, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe508) at ../csu/libc-start.c:325
#5 0x00005555555546da in _start ()
Please let me know why this program leads to a segmentation fault? I am not even calling foo
in the code, which perplexes me.
The purpose of why I was looking to do this kind of thing was to see, for a lot bigger program, whether it is possible to align multiple functions into this custom section and together protect such a function with certain mprotect
flags.
UPDATE EDIT WITH A POTENTIAL SOLUTION:
@user253751's solution helped me able to think in a different direction, so I started working toward that direction to solve this problem. Then @Chris Dodd's gave me a hint on what I needed to do in order to solve this problem, which is how I was able to devise the following potential solution.
I'm not sure if I did it exactly correctly, but I tried to adhere to Chris's comment and created a linker script as follows:
so_linker.ld
SECTIONS
{
.custom_sec BLOCK(4096) : ALIGN(4096) {
_start_custom_sec = .;
*(.custom_sec)
_end_custom_sec = .;
}
}
INSERT AFTER .rodata;
and then modified the test code as this:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#define PAGESIZE 4096
void foo() __attribute__ ((section (".custom_sec")));
const void * _start_custom_sec;
const void * _end_custom_sec;
int main()
{
// Sanity check.
printf("Custom section range: %p to %p\t Foo: %p\n",
(void *)&_start_custom_sec,
(void *)&_end_custom_sec,
(void *)&foo);
if(mprotect(&foo, getpagesize(), PROT_READ | PROT_WRITE) == -1) {
perror("mprotect()");
return 1;
}
}
void foo() { printf("Foo\n"); }
Now, compile above program with the following command: gcc -T so_linker.ld stackoverflow.c -o so
and by checking the section arrangement, we can now see that this custom section is ensured to be pushed outside of any other code that may potentially touch it (using the command readelf --sections W so
).
[11] .init PROGBITS 0000000000000620 000620 000017 00 AX 0 0 4
[12] .plt PROGBITS 0000000000000640 000640 000060 10 AX 0 0 16
[13] .plt.got PROGBITS 00000000000006a0 0006a0 000008 00 AX 0 0 8
[14] .text PROGBITS 00000000000006b0 0006b0 000212 00 AX 0 0 16
[15] .fini PROGBITS 00000000000008c4 0008c4 000009 00 AX 0 0 4
[16] .rodata PROGBITS 00000000000008d0 0008d0 000044 00 A 0 0 8
[17] .custom_sec PROGBITS 0000000000001000 001000 000013 00 AX 0 0 4096
So there are a few reasons why I had to change many things in the code. The most important thing to note is that I need to create a section with .
in order to successfully re-align it using the linker script (e.g., custom_sec
-> .custom_sec
).
Edit 2: Fixed the linker script, now it should return correct beginning / end of the .custom_sec
section.
Upvotes: 3
Views: 185
Reputation: 58909
It looks like there is some code on the same page as your custom section. When you set the page to not executable, you crash when executing that code.
You might need to use a section attribute or a linker script to ensure the section goes on its own page that is shared with nothing else.
Upvotes: 3