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

时间:2014-07-22 09:44:42

标签: c string malloc fgets gets

我正在编写一个小的C代码来获取一些用户输入,这将是一个字符串。现在我在许多地方读到使用gets()将非常不安全,因为它可能导致缓冲区溢出攻击。在大多数地方,我发现替代方法是使用fgets(),就缓冲区溢出而言,这更安全。

现在我遇到了一个问题场景,其中我不知道手前的缓冲区大小。它只是无法确定。它可能是任何东西。那么在这种情况下,fgets()会派上用场吗?

另外,如果我使用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 */

上面的gets()用法是否还有缓冲区溢出问题?因为,在上面我们根本没有声明一个固定大小的缓冲区......所以没有缓冲区溢出是我所期待的。

如果我错过了什么,请纠正我!

3 个答案:

答案 0 :(得分:5)

char * temp_buffer_to_hold_user_input = NULL;

您将指针设置为NULL。因此根本没有缓冲区gets会因未定义的行为而失败(实际上可能是分段错误)。

gets要求您提供指向缓冲区的有效指针。空指针不指向任何内容,因此不满足此前提条件。由于所有缓冲区都具有有限长度且用户输入长度未知,因此根本无法避免潜在的缓冲区溢出(更不用说安全风险)了。这是非常糟糕的,gets 已从官方标准中删除。

正确的方法是使用fgets。处理可变大小的输入很棘手,所以你有两个选择:

  • fgets与“我所有情况下足够大”缓冲区大小一起使用。简单的出路。最糟糕的情况是你失去了一些投入。
  • 反复使用fgets并连接到一些动态分配的数组(并且不要忘记根据需要调整此数组的大小!),直到到达分隔符。 注意:取决于您对字符串的操作,您甚至可能不需要保留整个内容,这简化了事情。

答案 1 :(得分:2)

如果您事先不知道缓冲区大小,可以查看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;
}

没有中间缓冲区:

#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;
}

答案 2 :(得分:0)

  

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

其他人已经在身体上解决了你的问题。这是一个快速回答,解决了标题中的问题。

标准C通过gets提供gets_s的“更安全”变体。它被ISO/IEC TR 24731-1添加到C标准中。除此之外,TR 24731-1的更安全功能检查目标缓冲区大小,以避免其“不安全”对应物的许多缓冲区溢出问题。

以下是文件:

enter image description here

所以你真的不需要调整任何东西。您只需要为作业使用正确的功能;)