gpt4 book ai didi

c - 此 C 代码片段背后的安全考虑

转载 作者:行者123 更新时间:2023-11-30 20:48:23 24 4
gpt4 key购买 nike

我在 git 上找到了这段代码并想使用它,但有人评论了其中的安全错误。我好像没认出来:

int32_t read_arrbuff(FILE *f, uint32_t *arrmap) {
int32_t i = 0, n_map;
fread(&n_map, sizeof(n_map), 1, f);
if (n_map > 256)
return -1;
while (n_map--) {
fread(&arrmap[i++], sizeof(uint32_t), 1, f);
}
return n_map;
}

最佳答案

单独来看,问题包括:

  • 您不会检查 f 是否不为 NULL。
  • 您没有检查 arrmap 是否不为 NULL。
  • 您不会检查第一个 fread() 是否成功。
  • 您没有完全验证读取的值;负值或零值会让事情变得很糟糕。
  • 您不会检查第二个 fread() 是否成功。
  • 无论任何操作成功还是失败,您始终返回 -1

其中哪些是安全问题?在某些层面上,是所有的。在某些情况下,您可以假设 farrmap 是合法的而不进行检查。不检查读取是否成功,尤其是第一次,是一个严重的问题。 n_map 的负值将是一个严重的问题。当每次读取失败时声称成功将是一个问题。

循环完成后,n_map 设置为 -1(在后递减之前为零)。因此,失败或成功时返回 -1。那没有帮助。它几乎肯定会返回从文件中读取的 n_map 值,以便调用者可以知道数组中有多少个值。

通常最好不要将诸如 256 之类的大小限制硬编码到程序中。该接口(interface)应包含数组大小,并且您应检查传递的数组大小。

使用原始界面,您可以使用:

#include "stderr.h"
#include <stdio.h>
#include <inttypes.h>

extern int32_t read_arrbuff(FILE *f, uint32_t *arrmap);

int32_t read_arrbuff(FILE *f, uint32_t *arrmap)
{
int32_t n_map;
if (fread(&n_map, sizeof(n_map), 1, f) != 1)
err_syserr("failed to read data (count)\n");
if (n_map > 256 || n_map <= 0)
return -1;
for (int32_t i = 0; i < n_map; i++)
{
if (fread(&arrmap[i], sizeof(uint32_t), 1, f) != 1)
err_syserr("failed to read data (value %" PRId32 ")\n", i);
}
return n_map;
}

int main(int argc, char **argv)
{
err_setarg0(argv[0]);
if (argc != 1)
err_usage("");

char file[] = "data";

/* Create data file */
FILE *fp = fopen(file, "wb");
if (fp == NULL)
err_syserr("failed to open file '%s' for writing\n", file);
int32_t nmap = 32;
if (fwrite(&nmap, sizeof(nmap), 1, fp) != 1)
err_syserr("failed to write to file '%s'\n", file);
for (int32_t i = 0; i < nmap; i++)
{
if (fwrite(&i, sizeof(i), 1, fp) != 1)
err_syserr("failed to write to file '%s'\n", file);
}
fclose(fp);

/* Read data file */
fp = fopen(file, "rb");
if (fp == NULL)
err_syserr("failed to open file '%s' for reading\n", file);

uint32_t amap[256];
int32_t rc = read_arrbuff(fp, amap);
printf("rc = %" PRId32 "\n", rc);

for (int32_t i = 0; i < rc; i++)
printf("%3" PRId32 " = %3" PRId32 "\n", i, amap[i]);

fclose(fp);

return 0;
}

您可以争论 err_syserr() 强制的单方面退出是否合适。 (err_*() 函数的声明和源代码位于 stderr.hstderr.c 中,可从 GitHub 获取。 .)

从函数参数中获取最大数组大小的替代版本是:

#include "stderr.h"
#include <assert.h>
#include <stdio.h>
#include <inttypes.h>

extern int32_t read_arrbuff(FILE *f, int32_t a_size, uint32_t arrmap[a_size]);

int32_t read_arrbuff(FILE *f, int32_t a_size, uint32_t arrmap[a_size])
{
int32_t n_map;
assert(f != NULL && arrmap != NULL && a_size > 0 && a_size <= 256);
if (fread(&n_map, sizeof(n_map), 1, f) != 1)
{
err_sysrem("failed to read data (count)\n");
return -1;
}
if (n_map > a_size || n_map <= 0)
{
err_sysrem("count %" PRId32 " is out of range 1..%" PRId32 "\n",
n_map, a_size);
return -1;
}
for (int32_t i = 0; i < n_map; i++)
{
if (fread(&arrmap[i], sizeof(uint32_t), 1, f) != 1)
{
err_syserr("failed to read data (value %" PRId32 " of %" PRId32 ")\n",
i, n_map);
}
}
return n_map;
}

int main(int argc, char **argv)
{
err_setarg0(argv[0]);
if (argc != 1)
err_usage("");

char file[] = "data";

/* Create data file */
FILE *fp = fopen(file, "wb");
if (fp == NULL)
err_syserr("failed to open file '%s' for writing\n", file);
int32_t nmap = 32;
if (fwrite(&nmap, sizeof(nmap), 1, fp) != 1)
err_syserr("failed to write to file '%s'\n", file);
for (int32_t i = 0; i < nmap; i++)
{
if (fwrite(&i, sizeof(i), 1, fp) != 1)
err_syserr("failed to write to file '%s'\n", file);
}
fclose(fp);

/* Read data file */
fp = fopen(file, "rb");
if (fp == NULL)
err_syserr("failed to open file '%s' for reading\n", file);

enum { AMAP_SIZE = 256 };
uint32_t amap[AMAP_SIZE];
int32_t rc = read_arrbuff(fp, AMAP_SIZE, amap);
printf("rc = %" PRId32 "\n", rc);

for (int32_t i = 0; i < rc; i++)
printf("%3" PRId32 " = %3" PRId32 "\n", i, amap[i]);

fclose(fp);

return 0;
}

此版本报告特定错误并返回错误。它在入口时做出半适当的断言(256 的限制不一定适当,但与原始代码一致)。

输出并不令人兴奋(两者相同):

rc = 32
0 = 0
1 = 1
2 = 2
3 = 3
4 = 4
5 = 5
6 = 6
7 = 7
8 = 8
9 = 9
10 = 10
11 = 11
12 = 12
13 = 13
14 = 14
15 = 15
16 = 16
17 = 17
18 = 18
19 = 19
20 = 20
21 = 21
22 = 22
23 = 23
24 = 24
25 = 25
26 = 26
27 = 27
28 = 28
29 = 29
30 = 30
31 = 31

关于c - 此 C 代码片段背后的安全考虑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41525994/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com