Time-of-Check, Time-of-Use issues involving access(), faccessat(), stat(), lstat(), fstat(), open(), and fopen()

孤者浪人 提交于 2020-01-25 02:56:05

问题


I don't post here often, so bear with me while I try to decide how to solve this problem.

I'm updating a code base that hasn't been touched for between 10 - 20 years. The code was written without adherence to best practices, and by many authors with sometimes incomplete understandings of security conventions, or perhaps even before those conventions were common practice. The compiler used on this code is c++98 or c++03, but not more recent. The code is also cross platform between Linux and Windows.

All of that said, I need the help of some C++ veterans understanding the proper use of access(), stat() and open() and their perversions as it relates to TOCTOU issues.

Here is an example block of code illustrating the TOCTOU issue:

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

As you can see, the previous developer(s) wanted to make sure the user had access to "file", stat-ed "file", and then opened it without re-access()-ing and without re-stat()-ing "file" after fopen()-ing it. I understand why this is a TOCTOU problem, but I'm not sure of how to fix it.

From what I've researched, open() is preferred over fopen() and fstat() over stat(), but where does lstat() fit in? and if I do a stat, do I even need access() or faccessat()?

And to compound that, this needs to be compatable with a Windows compiler, and I've found articles saying that fopen() is better because it is cross platform while open() is not, making open() potentially unusable; this also seems to be the same for variations of stat() and access(), but I'm not certain.

If you've gotten this far, thank you for reading it all, and I welcome any criticism about the post and help.

来源:https://stackoverflow.com/questions/29526377/time-of-check-time-of-use-issues-involving-access-faccessat-stat-lstat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!