How to avoid buffer overflow using scanf

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

int main(int argc, char **argv) {
    char first_name[20];
    char last_name[20];
    int student_num;
    char debts[1];

    printf("Enter name:");
    scanf("%s", first_name);
    printf("Enter lastname:");
    scanf("%s", last_name);
    printf("Enter six bits length student ID:");
    scanf("%d", &student_num);
    printf("Do you have debts for university [Y/N]?");
    scanf("%s", debts);

    printf("\nYour name is %s %s.\n", first_name, last_name);
    printf("Your Student ID is %d.\n", student_num);
    printf("Debts: %s.\n", debts);
    return (EXIT_SUCCESS);
}

How to avoid buffer overflow in this code? I want my code to produce such an output:

Enter name:Enescekilokoneyasharrontannamyantoniaaquin
Enter lastname:Basenau
Enter six bits length student ID:456789
Do you have debts for university [Y/N]?YES

Your name is **Enescekilokoneyashar** (only 20 bits from name input) *Basenau*.
Your Student ID is **393299**.
Debts: **Y**.

Process returned -1073741819 (0xC0000005)   execution time : 36.336 s
Press any key to continue.

I have tried to use:

scanf("%19s", first_name);

But it does not work as I expect. I need to find some another way to validate input parameters to prevent buffer overflow attack and limit input to buffers size.

c
buffer-overflow
asked on Stack Overflow Oct 15, 2020 by Adomas Ba • edited Oct 15, 2020 by anastaciu

2 Answers

3

You can maintain the use of scanf but you need to limit the size of what it can take to the size of the destination buffer, something like:

scanf(" %19[^\n]", first_name); //last destination buffer element is for null byte

Note that this specifier can parse spaces so you can take an input with more than one word.

It will, however, leave a \n character in the stdin buffer, or the remaining characters that were not parsed in case you input a larger string, so you need to clear it every time you want to parse a new input, you can make a handy function that you can call when you need such clearence, making it a pattern:

void clear_buffer(){
    int c;
    while ((c = getchar()) != '\n' && c != EOF){
        continue;
    }
}

Your char debts[1] buffer is also problematic, it's too small to store a string, it needs to have at least 2 characters to be able to store the null terminator:

char debts[2];

And the call will be:

clear_buffer();
scanf(" %1[^\n]", debts);

Lastly you should verify the return of scanf, for instance, in scanf("%d", &student_num), if you input alphabetical characters instead of digits, the function will fail to parse and return 0, you can also make it parse at most 6 digits, something along the lines of:

clear_buffer();
if(scanf("%6d", &student_num) == 0){ // %6d limit the input to 6 digits
    //handle error
}

Live demo

answered on Stack Overflow Oct 15, 2020 by anastaciu • edited Oct 15, 2020 by anastaciu
2

If you are on windows you can use scanf_s() as described in the Microsoft documentation here. There is also an example given:

char s[10];
scanf_s("%9s", s, (unsigned)_countof(s));
answered on Stack Overflow Oct 15, 2020 by Michael

User contributions licensed under CC BY-SA 3.0