Join the Stack Overflow Community
Stack Overflow is a community of 6.4 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

Consider the following program (vul.c) with buffer overflow vulnerability.

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    char buf[10];
    strcpy(buf, argv[1]);
    printf("%s\n", buf);
    return 0;
}

Above program compiled using gcc -o vul vul.c and executed on arch linux - linux 4.4.16-1-lts x86-64 gave following output when executed in terminal with ./vul $(perl -e 'print "A"x100') command:

AAAAAAAAAAA...A
Segmentation fault (core dumped)

Then checking the program status using echo $? command gave 139 output.

Following program (exp.c) (for crashing the above program)

#include <stdlib.h>

int main(void)
{
    printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
    return 0;
}

compiled using gcc -o exp exp.c when executed with ./exp command on same system gave following output:

AAAAAAAAAAAA...A
139

I have two questions:

  1. Why no error message was generated by 2nd program? and,
  2. I need to compile the program with -fstack-protector flag to enable the *** stack smashing detected *** error messages in arch linux but not in Ubuntu. In Ubuntu, it might be that this flag is include by default in gcc or is there any other reason?
share|improve this question
1  
I'm not sure I understand the question... or your printf implementation... You do know system returns an int with the error code (0 if successful), it doesn't return a string. A simple if(system(...)) will give you the error. If you want to print it as anice looking message, you can probably use strerror. – Myst Aug 17 at 5:45
up vote 1 down vote accepted

As I pointed out in my comment,system returns an int with the programs's return value, which is normally it's error code (0 if successful).

If you want to print the error as a nice looking message, you can probably use strerror.

According to @rht's comment (see my next edit) and the answers to the question referenced in that comment, the returned value will be 0 on success and on error it will be error | 0x80. To get the original error code, use 128 - err_code.

try this:

#include <stdlib.h>
#include <errno.h>

int main(void)
{
    int tmp = system("./vul $(perl -e 'print \"A\"x100)");
    if(tmp < 0)
       error("Couldn't run system command");
    else if(tmp >0)
       printf(stderr, "System command returned error: %s", strerror(128 - tmp));
    else
       ; // nothing
    return 0;
}

The fact that vul.c does (or does not) print an error message should be irrelevant for your exp.c program, since it depends on vul.c's compile flags values and any default compiler flags - things exp.c can't control.

EDIT(2) - in answer to the comment.

It could be that the error message returned isn't an errno value, but a signal trap value.

These are sometimes hard to differentiate and I have no good advice about how you can tell which one it is without using memcmp against the answer.

In this case you know vul.c will never return it's errno value, which leaves you only with signal trap errors, so you can use strsignal to print the error message.

As pointed out in @rht's comment, which references this question:

Passing tmp to strsignal generates the same error message: "unknown signal 139". The reason is that there is no signal with this signal number. /usr/include/bits/s‌​ignum.h contains all the signals with their signal numbers. Passing tmp-128 to strsignal works.

i.e.

#include <stdlib.h>
#include <string>

int main(void)
{
    int tmp = system("./vul $(perl -e 'print \"A\"x100)");
    if(tmp < 0)
       error("Couldn't run system command");
    else if(tmp >0)
       printf(stderr, "System command returned error: %s", strsignal(tmp - 128));
    else
       ; // nothing
    return 0;
}

EDIT

The question was edited because it's code was mis-copied. I altered the answer to reflect that change.

share|improve this answer
    
On Ubuntu, first program generates *** stack smashing detected *** error message along with the output and the same happens in the second program. In arch linux too, including the -fstack-protector flag when compiling the vul.c program generates the same output and error messages in both the programs as in Ubuntu. And I don't understand why printf would crash as the system creates a new process for running vul.c program. If the new process crashes then it will simply return the control back to the system() and printf will print the status. Please correct if wrong. – rht Aug 17 at 6:04
    
When the control returns to system, then system returns a number to your program. When you use a number in printf it is translated to a string pointer, so printf prints whatever might be at the address of the error code... i.e. 0x0008a (for error-code 139). – Myst Aug 17 at 6:07
    
I am really sorry. I copied the wrong program. My mistake. Editing the program with correction. – rht Aug 17 at 6:14
    
@rht - No worries. I updated the answer to reflect the change. – Myst Aug 17 at 6:25
    
Thanks for updating the answer. I know the eror message is irrelevant for exp.c. But how can I get a useful error message for printing as printing the error using strerror() prints Unknown error 139? – rht Aug 17 at 6:47

From my comment to @Myst 's answer for "passing tmp-128 to strsignal()" function, after experimenting a little I found that it does not work in situations where the program exited normally but returned status other than 0.

Following are the contents of my /usr/include/bits/waitstatus.h:

/* If WIFEXITED(STATUS), the low-order 8 bits of the status.  */
#define __WEXITSTATUS(status)   (((status) & 0xff00) >> 8)

/* If WIFSIGNALED(STATUS), the terminating signal.  */
#define __WTERMSIG(status)      ((status) & 0x7f)

/* Nonzero if STATUS indicates normal termination.  */
#define __WIFEXITED(status)     (__WTERMSIG(status) == 0)

/* Nonzero if STATUS indicates termination by a signal.  */
#define __WIFSIGNALED(status) \
  (((signed char) (((status) & 0x7f) + 1) >> 1) > 0)

Above code show that, exit status of a program is a 16bit number, the high order 8 bits of which are the status that the program returned and some/all of the remaining bits are set if the program exited because of a signal, 7 bits of which denote the signal that caused the program to exit. That's why subtracting 128 from the exit status returned by system() will not work in the situation as described above.

System()'s source code

Since system() function too uses fork() to create a new process and waits for the termination of the process, the same method of checking a child process's status in parent process can also be applied here. Following program demonstrates this:

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>

int main(void)
{
    int status = system("prg_name");
    if (WIFEXITED(status))
        printf("Exited Normally, status = %d\n", WEXITSTATUS(status));
    else if (WIFSIGNALED(status))
        printf("Killed by Signal %d which was %s\n", WTERMSIG(status), strsignal(WTERMSIG(status)));
    return 0;
}
share|improve this answer

Answering my own 2nd question.

gcc -Q -v vul.c command displayed the options passed to the gcc. The options in Ubuntu included -fstack-protector-strong flag but not in arch-linux. So in Ubuntu, the flag is passed by default to gcc.

share|improve this answer

There exists two problems in your vul.c and exp.c.

In vul.c,

char buf[10];

10 is not sufficient in this case, since the argv[1], i.e., $(perl -e 'print "A"x100', is larger than the buffer to be allocated. Enlarge the buf size should fix the segmentation fault.

In exp.c, you're missing one single quote, and should be modified as followed:

printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
share|improve this answer
    
Thanks for pointing out missing single quote. I'll edit the question. And I am trying to get a segmentation fault error message. My question is why the second program is not printing any error messages. – rht Aug 17 at 6:52

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.