One final useful topic is that of system call tracing. While not specifically a source auditing tool, it can be a very useful tool for understanding the underlying operation of a GNU/Linux application. The strace utility provides the capability to trace the execution of an application from the perspective of system calls (such as fopen or fwrite , to name just two).
Consider the application shown in Listing 26.4. This application violates many of the code hardening principles already discussed, but we ll see how we can still debug it using strace .
1 : #include <unistd.h> 2 : #include <fcntl.h> 3 : 4 : #define MAX_BUF 128 5 : 6 : int main() 7 : { 8 : int fd; 9 : char buf[MAX_BUF+ 1 ]; 10 : 11 : fd = open("myfile.txt", O_RDONLY); 12 : 13 : read(fd, buf, MAX_BUF); 14 : 15 : printf("read %s\n", buf); 16 : 17 : close(fd); 18 : }
The first thing to note about this application is that at line 11, where we attempt to open the file called myfile.txt , there is no checking to ensure that the file actually exists. Executing this application will give an unpredictable result:
$ gcc -o bad bad.c $ ./bad read @8Z@ $
This is not what we expected, so now let s use strace to see what s going on. We ll shrink the output a bit, since we re not interested in the libraries that are loaded and such.
$ strace ./bad execve(./bad, [./bad], [/* 20 vars */]) = 0 uname({sys=Linux, node=camus, ...}) = 0 ... open(myfile.txt, O_RDONLY) = -1 ENOENT (No such file or directory) read(-1, 0xbfffef20, 128) = -1 EBADF (Bad file descriptor) fstat64(1, {st_mode=S_IFCHR0620, st_rdev=makedev(136, 0), ...}) = 0 mmap2(NULL, 4096, PROT_READPROT_WRITE, MAP_PRIVATEMAP_ANONYMOUS, -1, 0) = 0x40017000 write(1, read 07778Z@\n, 14read /8z@) = 14 close(-1) = -1 EBADF (Bad file descriptor) munmap(0x40017000, 4096) = 0 exit_group(-1) = ? $
After executing our app, we see that the execve system call is used to actually start the program. We then see an open shortly after execution, which matches our source (line 11, Listing 26.4). We can see at the right that the open system call returned “1, with an error of ENOENT (the file doesn t exist). This tells us right away what s going on with our application. The attempted read also fails, with the error of a bad file descriptor (since the open call failed).
The strace tool can be useful not only to understand the operation of our programs, but also the operation of programs for which we may not have source. From the perspective of system calls, we can at some level understand what binary applications are up to.