Home > Software engineering >  String with buffer overflow
String with buffer overflow

Time:11-30

I'm trying to create a program that reads some string, but when I test a very long string, an overflow occurs, and all the solutions I've already seen do not work. The following code is:

#include <stdio.h>

int main()
{
    char nome[201] = {0};
    char cpf[15] = {0};
    char senha[101] = {0};
    scanf(" 0s", nome);
    scanf("s", cpf);
    scanf("0s", senha);
    printf("nome: %s\n", nome);
    printf("cpf: %s\n", cpf);
    printf("senha: %s\n", senha);
    return 0;
}

This code is supposed to prevent the overflow, but the following string:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss

I'm trying to put the string in all inputs and when it comes to the second the program is finished and the overflow content goes to the third string.

CodePudding user response:

You asked for inputs in order. The first one has a maximum length of 200 characters, the second 14, and the third 100. You input a string of 160.

Ignoring the first variable for now (since there's no overflow), C takes the first 14 characters from the input buffer and puts them in the second variable. It terminates this with a null terminator. No overflow has occurred.

Now we need to get data for the third variable. Specifically, we need to get the next 100 characters, or all of the characters up to the next whitespace, whichever is shorter. We put 160 characters into the input buffer (your keyboard smash) and took 14 out. Therefore, there are still 144 characters in the input buffer. No need to interactively wait for input anymore; C takes the first 100 of those characters and puts them into the third variable, terminated with a null terminator. Now all of our inputs have been completed, so the program continues.

There is no buffer overflow vulnerability here. The program is well-defined and does what you asked it to. You asked it to read from the input buffer three times. You never said "from three different lines". If you want to do that, then you need to handle delimiters yourself. In C , there's a function called std::getline that will do it for you, but in C, you'll need to manually read (and discard) the rest of the line yourself. Something like this would suffice.

scanf(" 0s%*[^\n]", nome);

The * indicates that the newly-read value should not be stored anywhere, and the [^\n] indicates that zero or more non-newline characters should be read, until the pattern doesn't match anymore (i.e. until the next character is a newline or we hit the end-of-file)

CodePudding user response:

Your posted code does not have a buffer overflow, but you are right that the input from one input prompt "overflows" into the next input prompt.

What is happening is the following:

Since your input string consists of 160 characters (161 characters including the null terminating character), when you first enter that input, it will fit entirely inside the array nome, so the line

scanf(" 0s", nome);

will read this input entirely.

However, when you enter that input a second time, this time at the second input prompt, the line

scanf("s", cpf);

will only read the first 14 characters of that input and leave all other characters on the input stream.

Therefore, the line

scanf("0s", senha);

will read the remaining 146 characters of the input and write them into senha. So you are correct in saying that the second input prompt "overflows" into the third input prompt.

If you want to prevent this "overflow" from happening, you will have to discard all remaining characters on the line before the next input prompt, for example by calling:

scanf( "%*[^\n]" );

However, I generally do not recommend using the function scanf for user input, as that is not what it is designed to be used for.

Also, judging form the comments you made in the comments section, you want to be able to read entire lines that may be separated by spaces, instead of reading single words. However, the %s scanf format specifier will only read a single word.

For this reason, it is probably better for you to use the funtion fgets. This function will always attempt to read an entire line at once, including the newline character, instead of only a single word.

However, when using fgets, you will probably want to remove the newline character from the input. See the following question on how to do that:

Removing trailing newline character from fgets() input.

In the program below, I have created a function get_line_from_user which will read a single line from the user using fgets, discard the newline character, and if the line does not fit into the buffer, it willl also discard the rest of the line:

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

void get_line_from_user( char *buffer, int buffer_size );

int main()
{
    char nome[201] = {0};
    char cpf[15] = {0};
    char senha[101] = {0};

    //read inputs
    printf( "Nome: " );
    get_line_from_user( nome, sizeof nome );
    printf( "Cpf: " );
    get_line_from_user( cpf, sizeof cpf );
    printf( "Senha: " );
    get_line_from_user( senha, sizeof senha );

    //output the results
    printf("nome: %s\n", nome);
    printf("cpf: %s\n", cpf);
    printf("senha: %s\n", senha);

    return 0;
}

//This function will read exactly one line of input from the
//user and discard the newline character. If the line does
//not fit into the buffer, it will also discard the rest of
//the line.
void get_line_from_user( char *buffer, int buffer_size )
{
    char *p;

    //attempt to read one line of input
    if ( fgets( buffer, buffer_size, stdin ) == NULL )
    {
        printf( "Error reading from input\n" );
        exit( EXIT_FAILURE );
    }

    //attempt to find newline character
    p = strchr( buffer, '\n' );

    //determine whether entire line was read in (i.e. whether
    //the buffer was too small to store the entire line)
    if ( p == NULL )
    {
        int c;

        //discard remainder of line from input stream
        do
        {
            c = getchar();
        
        } while ( c != EOF && c != '\n' );
    }
    else
    {
        //remove newline character by overwriting it with
        //null character
        *p = '\0';
    }
}
  •  Tags:  
  • c
  • Related