简体   繁体   中英

Tweaking gets() to avoid buffer overflow

I am writing a small C code to take some user input, which would be a string. Now I read at a lot of places that using gets() will be very unsafe as it may lead to buffer overflow attacks. And in most of the places what I found as an alternative was using fgets() instead, which is safer as far as buffer overflows are concerned.

Now I have a problem scenario, where in I do not know the buffer size before hand. It just can not be determined. It could be anything. So in this case, will fgets() be handy ?

Also, what is wrong if I make use of gets(), as shown below, to solve this problem ?

char * temp_buffer_to_hold_user_input = NULL;
cahr * actual_buffer_that_stores_user_input = NULL;
int length_of_user_input =0;

/* taking user input, irrespective of its length using gets() */

gets(temp_buffer_to_hold_user_input);

/* now finding the length of the user input string and allocating the required number of bytes for proper (safe) usage */

length_of_user_input=length(temp_buffer_to_hold_user_input);
actual_buffer_that_stores_user_input = (char*)malloc(length_of_user_input*sizeof(char));
strcpy(actual_buffer_that_stores_user_input, temp_buffer_to_hold_user_input);

/* and now we work with our actual buffer */

So does the above usage of gets() still have buffer overflow problem ? Because, in the above we are not declaring a fixed size buffer at all in the first place... so no buffer overflow is what I am expecting.

Please correct me if I am missing out on something!

char * temp_buffer_to_hold_user_input = NULL;

You set the pointer to NULL . Hence there is no buffer at all and gets will fail with undefined behavior (probably a segmentation fault in practice).

gets requires that you present a valid pointer to a buffer. A null pointer doesn't point to anything, hence this pre-condition is not satisfied. Since all buffers have finite length and user input is of unknown length, there's just no way at all to avoid getting a potential buffer overflow (and not to mention security risk). It's so bad that gets has been removed from the official standard .

The correct way is to use fgets . Dealing with a variable-sized input is tricky though, so you have two options:

  • Use fgets with a "large-enough for all my cases" buffer size. The easy way out. Worst case is you lose some input.
  • Repeatedly use fgets and concatenate to some dynamically allocated array (and don't forget to resize this array as needed!) until you reach the delimiter. Note: depending on what you're doing with the string though, you may not even need to hold the entire thing around, which simplifies things.

If you don't know the buffer size before hand you can take a look to getline() , or build your own function and realloc your string, something like:

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

int main(void)
{
    char buf[8], *s = NULL, *p;
    size_t i = 0;

    while (fgets(buf, sizeof buf, stdin)) {
        if (i++ == 0) {
            s = malloc(sizeof buf);
            if (s == NULL) {
                perror("malloc");
                exit(EXIT_FAILURE);
            }
            strcpy(s, buf);
        } else {
            s = realloc(s, (i + 1) * sizeof(buf));
            if (s == NULL) {
                perror("realloc");
                exit(EXIT_FAILURE);
            }
            strcat(s, buf);
        }
        if ((p = strchr(s, '\n'))) {
            *p = '\0';
            break;
        }
    }
    printf("%s\n", s);
    free(s);
    return 0;
}

Without an intermediate buffer:

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

#define BUF_LEN 8

int main(void)
{
    size_t len = BUF_LEN;
    char *s, *p;

    p = s = malloc(len);
    if (s == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    while (fgets(p, BUF_LEN, stdin)) {
        if ((p = strchr(p, '\n'))) {
            *p = '\0';
            break;
        } else {
            len += BUF_LEN - 1;
            s = realloc(s, len);
            if (s == NULL) {
                perror("realloc");
                exit(EXIT_FAILURE);
            }
            p = s + len - BUF_LEN;
        }
    }
    printf("%s\n", s);
    free(s);
    return 0;
}

Tweaking gets() to avoid buffer overflow

Others have addressed your questions in the body. Here's a quick answer that addresses the question in your title.

Standard C provides a "safer" variant of gets via gets_s . Its was added to the C Standard with ISO/IEC TR 24731-1 . Among other things, the safer function of TR 24731-1 check the destination buffer size to avoid many of the buffer overflow problems of their "unsafe" counterparts.

Here's from the document:

在此处输入图片说明

So you really don't need to tweak anything. You only need to use the correct function for the job ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM