3

When running the following intentional stack smashing code, strcat copies the value of source exactly ten times.

#include <stdio.h>
#include <stdlib.h>

int main() {
    char a[16];
    char b[16];
    char c[32];

    strcpy(a, "abcdefghijklmnop");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(b, "ABCDEFGHIJKLMNOP");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcat(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    return 0;
}

Output:

a = abcdefghijklmnop b = c =

a = abcdefghijklmnopABCDEFGHIJKLMNOP b = ABCDEFGHIJKLMNOP c =

a = abcdefghijklmnopABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP b = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP c = ABCDEFGHIJKLMNOP

a = abcdefghijklmnopABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP b = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP c = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP

** stack smashing detected *: ./strcpytest terminated

Building parameters:

gcc -O0 -g3 -Wall -c -fmessage-length=0

The code is run on a x86_64 architecture.

Why does it only concatenate ten times?

Forest
  • 33
  • 4

3 Answers3

2

The behaviour of strcpy() and strcat() is undefined for overlapping strings. Both of your writes to c[] are therefore suspect, and rather than just testing smashing the stack, you're also testing your compiler's treatment of this undefined behaviour.

I'd expect the strcpy(c, b) line to fail, but the implementation must somehow get b's length before it overwrites the trailing zero at the start of c. This could happen if it copies from the last byte to the first, for example.

strcat(c, b) may be implemented in a more straightforward manner. Maybe ten times the data is enough to hit some limit that terminates it.

If you want to just test corrupting the stack, don't use these methods. Instead just use one array, and write past the end of it with a loop, e.g. "for (i = 0; i < 1000000; i++) c[i] = 'h';"

John Bickers
  • 481
  • 2
  • 6
0

If your platform uses memory-protection and has its stack growing down, like x86 (What is the direction of stack growth in most modern systems?), picking any stack position and writing to increasing addresses from there (like for a string...) means you don't go in the direction of stack-expansion but origin of stack, eventually running over it and plunging to your death on an intentially non-mapped guard-page, in which case you get the nice error-message you mentioned.

The error message can and is personalised this way to give you a hint what happened.

Aside: Changing anything at all might change the behavior of your code, as the platform is not obligated to behave that way.
2nd aside: The astounding thing is that strcpy(c, b); behaves as if it did not overwrite the terminator of the string beginning in b and terminated in c.

Community
  • 1
  • 1
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
-1

I am getting output like this, using gcc compiler:

a = abcdefghijklmnop
b = 
c = 

a = abcdefghijklmnopABCDEFGHIJKLMNOP
b = ABCDEFGHIJKLMNOP
c = 

a = abcdefghijklmnopABCDEFGHIJKLMNOP
b = ABCDEFGHIJKLMNOP
c = ABCDEFGHIJKLMNOP

a = 
b = ABCDEFGHIJKLMNOP
c = ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP

It is because You are not providing required size for terminator. Just try it:

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

int main() {
    char a[17];
    char b[17];
    char c[33];

    strcpy(a, "abcdefghijklmnop");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(b, "ABCDEFGHIJKLMNOP");
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcpy(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    strcat(c, b);
    printf("a = %s\nb = %s\nc = %s\n\n", a, b, c);

    return 0;
}

Every thing is fine now. Thanks Baldrick.

jahan
  • 521
  • 1
  • 4
  • 15
  • Using a previous version of gcc (Kali, gcc 4.2?) on another system gives the output you mentioned. The output mentioned in the question was by using gcc 4.8.2 on Ubuntu. If it depends on the compiler, that is. – Forest May 09 '14 at 00:49
  • 1
    You should have given space forthe null terminator. – jahan May 09 '14 at 00:51
  • 1
    This is an intentional stack smashing code. The question is about the behaviour of strcat. – Forest May 09 '14 at 00:52
  • The reason for the behaviour of strcat is because of terminating character. C assumes that a string is a character array with a terminating null character. This null character has ASCII value 0 and can be represented as just 0 or '\0'. This value is used to mark the end of meaningful data in the string. If this value is missing, many C string functions will keep processing data past the end of the meaningful data and often past the end of the character array itself until it happens to find a zero byte in memory! – jahan May 09 '14 at 00:56
  • @Jahan: Please read the actual question. Also, it never found any 0-bytes, because **it overwrites them before**. – Deduplicator May 09 '14 at 00:57