简体   繁体   English

调整gets()以避免缓冲区溢出

[英]Tweaking gets() to avoid buffer overflow

I am writing a small C code to take some user input, which would be a string. 我正在编写一个小的C代码以接受一些用户输入,这将是一个字符串。 Now I read at a lot of places that using gets() will be very unsafe as it may lead to buffer overflow attacks. 现在,我在很多地方读到,使用gets()将非常不安全,因为它可能导致缓冲区溢出攻击。 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. 在大多数地方,我找到的替代方法是使用fgets(),就缓冲区溢出而言,这更安全。

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 ? 因此,在这种情况下,fgets()会很方便吗?

Also, what is wrong if I make use of gets(), as shown below, to solve this problem ? 另外,如果我使用gets()来解决此问题,那是什么错误呢?

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 ? 那么上述gets()的用法是否仍然存在缓冲区溢出问题? 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 . 您将指针设置为NULL Hence there is no buffer at all and gets will fail with undefined behavior (probably a segmentation fault in practice). 因此,根本没有缓冲区,并且gets将因未定义的行为而失败(实际上可能是分段错误)。

gets requires that you present a valid pointer to a buffer. gets要求您提供一个指向缓冲区的有效指针。 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 . 它是如此糟糕, gets来自官方的标准中删除

The correct way is to use fgets . 正确的方法是使用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. fgets使用“我的所有情况都足够大”的缓冲区大小。 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. 重复使用fgets并连接到一些动态分配的数组(不要忘记根据需要调整该数组的大小!),直到到达定界符为止。 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: 如果您不知道缓冲区的大小,可以看一下getline() ,或者构建自己的函数并重新realloc字符串,例如:

#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 调整gets()以避免缓冲区溢出

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 . 标准C通过gets_s提供了gets的“更安全”的变体。 Its was added to the C Standard with ISO/IEC TR 24731-1 . 它已通过ISO / IEC TR 24731-1被添加到C标准中。 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. 除其他外,TR 24731-1的安全功能检查目标缓冲区的大小,以避免其“不安全”副本的许多缓冲区溢出问题。

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 ;) 您只需要使用正确的功能即可;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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