我不经常在这里发帖,所以当我试着决定如何解决这个问题时请耐心等待。
我正在更新一个10到20年没有被触及的代码库。编写的代码不遵循最佳实践,许多作者有时对安全约定的理解不完整,或者甚至在这些约定之前都是常见的做法。此代码上使用的编译器是c ++ 98或c ++ 03,但不是更新的。该代码也是Linux和Windows之间的跨平台。
所有这些都说,我需要一些C ++老手的帮助,了解正确使用access(),stat()和open()及其与TOCTOU问题相关的变态。
以下是说明TOCTOU问题的示例代码块:
#ifdef WIN32
struct _stat buf;
#else
struct stat buf;
#endif //WIN32
FILE *fp;
char data[2560];
// Make sure file exists and is readable
#ifdef WIN32
if (_access(file.c_str(), R_OK) == -1) {
#else
if (access(file.c_str(), R_OK) == -1) {
#endif //WIN32
/* This is a fix from a previous
Stack-based Buffer Overflow
issue. I tried to keep the original
code as close to possible while
dealing with the potential security
issue, as I can't be certain of how
my change might effect the system. */
std::string checkStr("File ");
checkStr += file.c_str();
checkStr += " Not Found or Not Readable";
if(checkStr.length() >= 2560)
throw checkStr.c_str();
char message[2560];
sprintf(message, "File '%s' Not Found or Not Readable", file.c_str());
//DISPLAY_MSG_ERROR( this, message, "GetFileContents", "System" );
throw message;
}
// Get the file status information
#ifdef WIN32
if (_stat(file.c_str(), &buf) != 0) {
#else
if (stat(file.c_str(), &buf) != 0) {
#endif //WIN32
/* Same story here. */
std::string checkStr("File ");
checkStr += file.c_str();
checkStr += " No Status Available";
if(checkStr.length() >= 2560)
throw checkStr.c_str();
char message[2560];
sprintf(message, "File '%s' No Status Available", file.c_str());
//DISPLAY_MSG_ERROR( this, message, "GetFileContents", "System" );
throw message;
}
// Open the file for reading
fp = fopen(file.c_str(), "r");
if (fp == NULL) {
char message[2560];
sprintf(message, "File '%s' Cound Not be Opened", file.c_str());
//DISPLAY_MSG_ERROR( this, message, "GetFileContents", "System" );
throw message;
}
// Read the file
MvString s, ss;
while (fgets(data, sizeof(data), fp) != (char *)0) {
s = data;
s.trimBoth();
if (s.compare( 0, 5, "GROUP" ) == 0) {
//size_t t = s.find_last_of( ":" );
size_t t = s.find( ":" );
if (t != string::npos) {
ss = s.substr( t+1 ).c_str();
ss.trimBoth();
ss = ss.substr( 1, ss.length() - 3 ).c_str();
group_list.push_back( ss );
}
}
}
// Close the file
fclose(fp);
}
正如您所看到的,之前的开发人员希望确保用户可以访问“文件”,统计“文件”,然后打开它而无需重新访问() - 没有重新访问stat() - fopen()之后的“文件”。我理解为什么这是一个TOCTOU问题,但我不知道如何解决它。
根据我的研究,open()优于fopen()和fstat()优于stat(),但lstat()适合哪里?如果我做一个统计,我甚至需要access()或faccessat()?
复杂的是,这需要与Windows编译器兼容,并且我发现文章说fopen()更好,因为它是跨平台而open()不是,使open()可能无法使用;对于stat()和access()的变体,这似乎也是一样的,但我不确定。
如果你已经走到这一步,感谢你阅读本文,我欢迎任何有关帖子和帮助的批评。