0

I want to simulate a downward growing call stack in C and push the following onto the stack:

enter image description here

This is test code I wrote, where I only tried to push the strings, word align and then push the addresses to the strings I that were just pushed:

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

int main(){

    /*Initialize stack */
    size_t stack_size = (size_t) pow(2,10);
    uint8_t *esp;                             /*Use byte-addressable stack pointer */
    esp = (uint8_t *) malloc(stack_size);

    esp += stack_size - 1;                    /*Set esp to top of allocated memory,
                                            since stack grows downwards */

    /* Parse the string into its tokens */
    char s[]  = "/bin/ls -l foo bar";
    char *tokens[4];
    char *token = strtok(s, " ");
    int num_tokens = 0;                                
    while (token != NULL)
    {
        tokens[num_tokens++] = token;
        token = strtok(NULL, " ");
    }


    size_t esp_iter = 0;                      /*number of bytes pushed,
                                            needed for word alignment */    

    char *stack_pointers[num_tokens];         /* Array to store addresses of
                                               strings that were pushed */

    /* Push the char arrays on the stack */
    for (int j = 0; j < num_tokens; j++)
    {
        esp_iter += strlen(tokens[j]) + 1;      /* +1 because of ‘\0’, which is
                                                  included in strncpy */

        /* Address to store next string into */
        char *next_pointer = (char *) ((uint8_t *) ( esp - esp_iter));

        /* Store address in stack to which token j was pushed */
        stack_pointers[j] = strncpy(next_pointer, tokens[j],
                                    strlen(tokens[num_tokens]) + 1);
    }

    /* word aligning */
    size_t pad = 4 - esp_iter % 4;
    for (int j = 0; j < (int) pad; j++)
    {
        esp_iter += 1;
    }

    /* Push pointers to previously pushed strings */
    for (int j = 0; j < num_tokens; j++)
    {
        esp_iter -= sizeof(char *);

        /* Address on stack to store address of previously
           pushed token to */
        char *stack_pointer = (char *) (esp - esp_iter);
        stack_pointer = (char *) stack_pointers[j];
    }
    return 0;
}

I want to address the stack on byte-level, so I use (uint8_t *) for the stack pointer. Then I should be able to use the length of the string + 1 (for the '\0', which is included in strncpy) in the call to strncpy. But the strncpy yields a segmentation fault and I don't understand why. I malloced memory from 0x7fc4c5001000 to 0x7fc4c50013ff. Esp is set to 0x7fc4c50013ff, then I want to e.g push "bar" on the stack, so I decrement to the stack pointer (stack grows toward lower memory addresses) by 4 and call strncpy with destination address 0x7fc4c50013fb, which should be enough space to push those 4 characters. Why do I get a segfault here?

ryyker
  • 22,849
  • 3
  • 43
  • 87
eager2learn
  • 1,447
  • 4
  • 24
  • 47
  • 2
    Your code could *really* use some spacing... (and re-styling). – Marco Bonelli Sep 11 '19 at 13:07
  • 4
    I don't need to fully read all the code. I can't even manage to read it. I read what you are asking for and it could very well be a good question, if only it was formatted correctly and was providing a real [MCVE]. Down-vote arrows are there for a reason. – Marco Bonelli Sep 11 '19 at 13:33
  • This code doesn't compile. I'm guessing you've missed a closing bracket somewhere in main() – Cinder Biscuits Sep 11 '19 at 13:44
  • This latest edit makes the code even less valid and buildable. Please post the code that actually produces what you say it does. I've answered the question despite the latest changes. You're accessing outside of the bounds of `tokens` – Cinder Biscuits Sep 11 '19 at 14:07
  • 1
    Edited the code and fixed the compilation error now. Sorry for the badly edited question, hope this is at least readable now. – eager2learn Sep 11 '19 at 14:09

1 Answers1

2

Quick run after fixing your code so it would compile tells us the segfault is coming from strlen(), not strncpy():

stack_pointers[j] = strncpy(next_pointer, tokens[j], strlen(tokens[i]) + 1);

tokens[i] is null.

Earlier in your code, you do:

int i = 0;
while (token != NULL){
  tokens[i++] = token;
  printf("%s \n", token);
  token = strtok(NULL, " ");
}

This increments i to 4, since the array only contains 4 strings, and you're accessing the fifth position, naturally, strlen() segfaults when it accesses outside the array.

#0  __strlen_sse42 () at ../sysdeps/x86_64/multiarch/strlen-sse4.S:32
#1  0x00000000004007b8 in main () at main.c:32
(gdb) f 1
#1  0x00000000004007b8 in main () at main.c:32
32      stack_pointers[j] = strncpy(next_pointer, tokens[j], strlen(tokens[i]) + 1);
(gdb) print tokens[i]
$1 = 0x0
(gdb) print i
$2 = 4
(gdb) print tokens
$3 = {0x7fffffffe020 "/bin/ls", 0x7fffffffe028 "-l", 0x7fffffffe02b "foo", 0x7fffffffe02f "bar", 
  0x0}
Cinder Biscuits
  • 4,880
  • 31
  • 51