仔细检查缓冲区的大小

Double check the size of a buffer

我怀疑我开发的库中可能存在缓冲区溢出,其中有以下 API 可以从外部应用程序调用。我试图找到一个可能的解决方案,但我还没有找到 "right" 那个。 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;
}

我需要提供对 "buffer overflow" 足够安全的代码。出于这个原因,我使用 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 大小是否正确?

谢谢大家!

简单地说 - 你不能...
无法确定您作为指针收到的内存地址的 "length",因为没有实体可以在运行时验证它。这就是您首先要求长度的原因!

在您的情况下,唯一的解决方案是自己分配内存,然后 return 分配给用户,将管理该内存的责任转移给用户:

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

这样,您就可以控制内存分配,从而防止缓冲区溢出