|
From: Chang-Jae L. <sik...@gm...> - 2013-09-05 07:01:53
|
Hi, I am a grad-student in KAIST, and I'm working on a project for finding bugs or errors. Currently I'm following a routine from the paper "Execution Suppression: An Automated Iterative Technique for Locating Memory Errors." It is about finding the root cause of memory error(s) when a program shows a crash, by suppressing the code statement which defines that memory location and subsequent statements using the location and restart the program, until no crash happens. So what I need here is, - How can I handle target application's segmentation fault in my tool? First I ran my target with Lackey and it gets SIGSEGV, alerts to me, and returns 0, but the last thing it does is saying that it was terminated with segmentation fault. here I attached the log of Lackey. < ==16834== Lackey, an example Valgrind tool ==16834== Copyright (C) 2002-2012, and GNU GPL'd, by Nicholas Nethercote. ==16834== Using Valgrind-3.9.0.SVN and LibVEX; rerun with -h for copyright info ==16834== Command: ./test1_x64 ==16834== ==16834== ==16834== Process terminating with default action of signal 11 (SIGSEGV) ==16834== Bad permissions for mapped region at address 0x4005D8 ==16834== at 0x400503: main (test1.c:13) ==16834== ==16834== Counted 1 call to main() ==16834== ==16834== Jccs: ==16834== total: 14,169 ==16834== taken: 5,874 ( 41%) ==16834== ==16834== Executed: ==16834== SBs entered: 14,440 ==16834== SBs completed: 9,214 ==16834== guest instrs: 82,505 ==16834== IRStmts: 483,662 ==16834== ==16834== Ratios: ==16834== guest instrs : SB entered = 57 : 10 ==16834== IRStmts : SB entered = 334 : 10 ==16834== IRStmts : guest instr = 58 : 10 ==16834== ==16834== Exit code: 0 Segmentation fault (core dumped) > - I need to suppress instructions which stands for a single code statement, like defining pointers or accessing particular memory addresses. Looks like the core connects debug information if there is one. Then, how does the tool recognize it (like memcheck does)? Is VEX IR superblock contains about it? Thank you in advance. |
|
From: Philippe W. <phi...@sk...> - 2013-09-05 20:43:26
|
On Thu, 2013-09-05 at 16:01 +0900, Chang-Jae Lee wrote:
> Hi,
>
>
> I am a grad-student in KAIST, and I'm working on a project for
> finding bugs or errors.
> Currently I'm following a routine from the paper "Execution
> Suppression: An Automated Iterative Technique for Locating Memory
> Errors."
> It is about finding the root cause of memory error(s) when a program
> shows a crash,
> by suppressing the code statement which defines that memory location
> and subsequent statements using the location and restart the program,
> until no crash happens.
> So what I need here is,
>
>
> - How can I handle target application's segmentation fault in my tool?
> First I ran my target with Lackey and it gets SIGSEGV, alerts to me,
> and returns 0, but the last thing it does is saying that it was
> terminated with segmentation fault. here I attached the log of Lackey.
>From what I can see, you will have to modify Valgrind "core" to let
the tool "intercept" the guest signals.
At first sight, your tool might install a fault_catcher
using VG_(set_fault_catcher).
However, currently, such a fault catcher can only run in non generated
code (see sync_signalhandler_from_kernel). You might have to change
that.
Maybe some other changes will be needed (such as allowing the fault
catcher to indiate that the signal is not to be propagated.
You will find a current use of such a fault catcher in memcheck
(mc_leakcheck.c), but however not in generated code.
>
> - I need to suppress instructions which stands for a single code
> statement, like defining pointers or accessing particular memory
> addresses.
> Looks like the core connects debug information if there is one. Then,
> how does the tool recognize it (like memcheck does)? Is VEX IR
> superblock contains about it?
Not too sure about what you mean with the above. Valgrind works
at binary level, it does not really have a notion of "statement".
For example, if in the code you have:
f()
{
char *ptr1;
char *ptr2;
these two "statements" will just be part of the stack setup
(e.g. change the stack pointer) and so there is no way to
"remove" the instruction corresponding to
e.g. only the first "ptr definition".
As I do not understand the tool you have to write, I have no idea
how to best do what you need.
Philippe
|
|
From: Chang-Jae L. <sik...@gm...> - 2013-09-09 01:50:46
|
On Fri, Sep 6, 2013 at 5:43 AM, Philippe Waroquiers <
phi...@sk...> wrote:
> On Thu, 2013-09-05 at 16:01 +0900, Chang-Jae Lee wrote:
>
>
> Not too sure about what you mean with the above. Valgrind works
> at binary level, it does not really have a notion of "statement".
> For example, if in the code you have:
> f()
> {
> char *ptr1;
> char *ptr2;
>
> these two "statements" will just be part of the stack setup
> (e.g. change the stack pointer) and so there is no way to
> "remove" the instruction corresponding to
> e.g. only the first "ptr definition".
>
>
> As I do not understand the tool you have to write, I have no idea
> how to best do what you need.
>
>
>
Here I brought an example of the execution suppression from the paper:
-------------------------
- Let x and y be pointers to two malloc'ed memory regions, each able to
hold two integers.
- Let intArray be a heap array of integers.
- Let structArray be a heap array of pointers to structs with a f ield f.
1: int * p1 = &x[1];
2: int * p2 = &x[0];
3: int * q1 = &y[1];
4: int * q2 = &x[0]; // copy-paste error: should be &y[0]
5: *p1 = readInt();
6: *p2 = readInt(); // gets clobbered at line 8
7: *q1 = readInt();
8: *q2 = readInt(); // clobbers line 6 defi nition
9: int a = *p1 + *p2; // uses infected *p2/*q2
10: int b = *q1 + *q2; // uses infected *p2/*q2
11: int c = a + b + 1; // uses infected a and b
12: intArray[c] = 0; // potential buff er overfow
13: structArray[*p2]->f = 0; // potential NULL dereference
14: free(p2);
15: free(q2); // potential double free
-------------------------
The line 4 has a copy-paste error, corrupting a pointer q2.
>From there, several reads/writes exist on the corrupted location.
Let's suppose that at first the crash occurs at line 12, because of reading
illegal memory address.
The first definition of variable c is at line 11. We then suppress the line
11, and subsequent use of variable c(at line 12)
Now running this program results another crash at line 13. Use of p2/q2
results crash, so we suppress the definition of q2 at line 8, and
subsequent use of q2 - line 9 and 10.
Running this program again still have a crash, in line 15 because of double
free.
Suppressing the definition of q2 in line 4, and use of q2 in line 15,
running again then no crash occur,
So we can conclude that line 4 is the first location of memory corruption.
And about uninitialized pointers like Philippe you mentioned, you're right.
In that case it's not suppress-able.
But if there's a code like this -
--------------------------
void foo()
{
char* pt1;
char* pt2;
pt1[0] = 'X';
printf("%s\n", pt1);
}
--------------------------
The crash occurs at " pt1[0] = 'X'; " so we suppress this statement(since
there's no value assignment of pt1, this is the only suppression point)
and on the next run there would be no crash.
Therefore we can conclude using uninitialized pointer is the root cause of
the crash.
>
|
|
From: Philippe W. <phi...@sk...> - 2013-09-09 22:08:31
|
On Mon, 2013-09-09 at 10:50 +0900, Chang-Jae Lee wrote: > > The first definition of variable c is at line 11. We then suppress the > line 11, and subsequent use of variable c(at line 12) The above defines what to do speaking in terms of source lines, while valgrind works at binary level. There is not necessarily a one to one mapping between a source line and a (contiguous) range of instructions. Also what if the source code has more than one statement on one single line (either because that is how it was typed or due to pre-processors macros) ? At this stage, how to implement what you describe in a valgrind tool looks quite a challenge to me. Sorry to not be able to help on this. Philippe |