我对我开发的库中存在潜在的缓冲区溢出存在疑问,其中存在可从外部应用程序调用的以下API。我试图找到一个可能的解决方案,但我还没有找到"对"一。 API如下:
char* strftime_ISO8601(uint64_t ns, char* buf, size_t buflen) {
if (buf) {
//The standard format ISO 8601 is 20 bytes + 1 null
char datetime[21];
struct tm tm;
struct timespec ts = //convert nanoseconds into timespec
gmtime_r(&ts.tv_sec, &tm);
strftime(datetime, sizeof(datetime), "+%FT%T", &tm);
snprintf(buf, buflen, "%s.%.9ld", datetime, ts.tv_nsec);
}
return buf;
}
我需要提供足够安全的代码来防止"缓冲区溢出"。出于这个原因,我使用snprintf,其中目标缓冲区的大小作为参数给出,结果字符串以NULL结尾。 我还使用了一些静态分析工具(如RATS)来突出潜在的漏洞。在这种情况下,我有以下通知:
Double check that your buffer is as big as you specify. When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the destination buffer size = n it may not NULL-terminate the string.
snprintf上的
snprintf(buf, buflen, "%s.%.9ld", datetime, ts.tv_nsec);
使用snprintf我确定该字符串将以NULL结尾,但是如何仔细检查输入中给出的缓冲区是否真的是buflen大小?
我的意思是,如果用户调用的API大小不合适,例如
...
char bad[5]
strftime_ISO8601(x, bad, 1024);
....
甚至最糟糕的是使用未初始化的缓冲区,如下所示:
...
char *bad;
strftime_ISO8601(x, bad, 1024);
...
潜在细分错误的一部分,我没有看到上述API中的任何特定漏洞。但是,如何验证API接收的buflen是否是正确的大小?
谢谢大家!
答案 0 :(得分:1)
简单地说 - 你不能...... 没有办法确定"长度"您作为指针接收的内存地址,因为没有可以在运行时验证它的实体。这就是你首先要求长度的原因!
在您的情况下,唯一的解决方案是自己分配内存并将其返回给用户,将管理内存的责任转移给用户:
char* strftime_ISO8601(uint64_t ns) {
//The standard format ISO 8601 is 20 bytes + 1 null
char datetime[21];
char *res = malloc(EXPECTED_SIZE)
struct tm tm;
struct timespec ts = //convert nanoseconds into timespec
gmtime_r(&ts.tv_sec, &tm);
strftime(datetime, sizeof(datetime), "+%FT%T", &tm);
snprintf(res, EXPECTED_SIZE, "%s.%.9ld", datetime, ts.tv_nsec);
return res;
}
这样,您可以控制内存分配,从而可以防止缓冲区溢出