Ok, understood. But I see you do have short downtime of a service as process has to be restarted. We don't know what is the justification against gdb in your live environment but seems you do have case for it here.
To elaborate on my code above a bit further. The saved context (3rd param in handler) is the context handler will used to sigreturn (i.e. return from handler). There you can examine and possibly control the flow. But this does require you to know what is the program doing, i.e.:
Code:
./mprotect
Starting ....0x800a09700 : size = 16384
signum: 11, count: 1, returning to: 0x201cc1
something tried to write to ptr @ 0x201cc1
signum: 11, count: 2, returning to: 0x201cc1
something tried to write to ptr @ 0x201cc1
signum: 11, count: 3, returning to: 0x201cc1
something tried to write to ptr @ 0x201cc1
signum: 11, count: 4, returning to: 0x201cc1
something tried to write to ptr @ 0x201cc1
signum: 11, count: 5, returning to: 0x201cc1
something tried to write to ptr @ 0x201cc1
ptr: 0
All completed...
Let's see what that is with
objdump -d mprotect
:
Code:
201c69: 48 8b 04 25 d8 3f 20 mov rax,QWORD PTR ds:0x203fd8
201c70: 00
201c71: c7 00 00 00 00 00 mov DWORD PTR [rax],0x0
I've compiled the binary with debug symbols so I can easily verify that with
readelf -Wa mprotect | grep 203fd8
Code:
40: 0000000000203fd8 8 OBJECT GLOBAL DEFAULT 24 ptr
and confirmed that it's the code:
From the asm output you can see the value 0 is used as immediate, i.e. you won't find this value in saved context.
If you are using threads you can have race condition in handler and you need to have some logic (mutex) to control the mprotect. With this handler you should also take care of other possibilities of SIGSEGV. Simplest case would be to compare si_addr to ptr, if it's not it do exit.
Handler I used in my code is pretty much the same, pasting for completeness:
Code:
void handler(int sig_num, siginfo_t *sig, void *unused) {
cnt++;
ucontext_t *uc = (ucontext_t *)unused;
printf("signum: %d, count: %lu, returning to: 0x%lx\n", sig_num, cnt, uc->uc_mcontext.mc_rip);
if (sig->si_addr == ptr) {
printf("something tried to write to ptr @ 0x%lx\n", uc->uc_mcontext.mc_rip);
}
if (cnt == 5) {
mprotect(ptr, size, PROT_READ | PROT_WRITE);
}
}
I like this problem as an idea. I went through this thread again but didn't find the answer: why is it a problem first just to do a printf debugging to see what is being written where? You know all locations in code where arr is being used and written to. Just use printf before it to print within what function what is being written.