CVE-2022-3976 (C, published 2022-11-13T14:15Z)
Description: value: A vulnerability has been found in MZ Automation libiec61850 up to 1.4 and classified as critical. This vulnerability affects unknown code of the file src/mms/iso_mms/client/mms_client_files.c of the component MMS File Services. The manipulation of the argument filename leads to path traversal. Upgrading to version 1.5 is able to address this issue. The name of the patch is 10622ba36bb3910c151348f1569f039ecdd8786f. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-213556.
Severity: nan (CVSS v3 base score: 8.8)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/mz-automation/libiec61850
Files changed:
hal/filesystem/linux/file_provider_linux.c
src/mms/inc_private/mms_common_internal.h
src/mms/iso_mms/client/mms_client_files.c
src/mms/iso_mms/common/mms_common_msg.c
src/mms/iso_mms/server/mms_file_service.c
Commit message: - fixed path traversal vulnerability in MMS file services (LIB61850-357)


Vulnerable code:


        MmsFileReadStateMachine* frsm = getFreeFrsm(connection);
        if (frsm != NULL) {
            MmsOutstandingCall obtainFileCall = mmsClient_getMatchingObtainFileRequest(connection, filename);
            if (obtainFileCall) {
                if (DEBUG_MMS_CLIENT)
                    printf("MMS_CLIENT: file open is matching obtain file request for file %s\n", filename);
                obtainFileCall->timeout = Hal_getTimeInMs() + connection->requestTimeout;
            }
            FileHandle fileHandle = mmsMsg_openFile(MmsConnection_getFilestoreBasepath(connection), filename, false);
            if (fileHandle != NULL) {
                frsm->fileHandle = fileHandle;
                frsm->readPosition = filePosition;
                frsm->frsmId = getNextFrsmId(connection);
                frsm->obtainRequest = obtainFileCall;
                mmsMsg_createFileOpenResponse(MmsConnection_getFilestoreBasepath(connection),
                        invokeId, response, filename, frsm);
                mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);

        else
            mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER);
        mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILENAME_SYNTAX_ERROR);



Fixed code:
LIB61850_INTERNAL bool
mmsMsg_isFilenameSave(const char* filename);

        if (mmsMsg_isFilenameSave(filename) == false) {
            /* potential attack */
            if (DEBUG_MMS_CLIENT)
                printf("MMS_CLIENT: client provided unsave filename -> rejected\n");
             mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);
        }
        else {
            MmsFileReadStateMachine* frsm = getFreeFrsm(connection);
            if (frsm != NULL) {
                MmsOutstandingCall obtainFileCall = mmsClient_getMatchingObtainFileRequest(connection, filename);
                if (obtainFileCall) {
                    if (DEBUG_MMS_CLIENT)
                        printf("MMS_CLIENT: file open is matching obtain file request for file %s\n", filename);
                    obtainFileCall->timeout = Hal_getTimeInMs() + connection->requestTimeout;
                }
                FileHandle fileHandle = mmsMsg_openFile(MmsConnection_getFilestoreBasepath(connection), filename, false);

                if (fileHandle != NULL) {

                    frsm->fileHandle = fileHandle;
                    frsm->readPosition = filePosition;
                    frsm->frsmId = getNextFrsmId(connection);
                    frsm->obtainRequest = obtainFileCall;

                    mmsMsg_createFileOpenResponse(MmsConnection_getFilestoreBasepath(connection),
                            invokeId, response, filename, frsm);
                }
                else
                    mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);
                mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_RESOURCE_OTHER);
bool
mmsMsg_isFilenameSave(const char* filename)
{
    if (filename)
    {
        if (strstr(filename, ".."))
            return false;

        if (strstr(filename, "./"))
            return false;

        return true;
    }
    else {
        return false;
    }
}

        mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);
    if (mmsMsg_isFilenameSave(filename) == false)
    {
        if (DEBUG_MMS_SERVER)
            printf("MMS_SERVER: remote provided unsave filename -> rejected\n");

        mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);

        return;
    }

        if (mmsMsg_isFilenameSave(filename) == false) {
            /* potential attack */

            if (DEBUG_MMS_CLIENT)
                printf("MMS_SERVER: remote provided unsave filename -> rejected\n");

             mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);

             return;
        }

        if (mmsMsg_isFilenameSave(destinationFilename) == false) {
            /* potential attack */

            if (DEBUG_MMS_SERVER)
                printf("MMS_SERVER: remote provided unsave filename -> rejected\n");

            goto exit_invalid_parameter;
        }

    if ((directoryName && mmsMsg_isFilenameSave(directoryName) == false) || 
        (continueAfterFileName && mmsMsg_isFilenameSave(continueAfterFileName) == false))
    {
        if (DEBUG_MMS_SERVER)
            printf("MMS_SERVER: remote provided unsave filename -> rejected\n");

       mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);

       return;
    }

        if ((mmsMsg_isFilenameSave(currentFileName) == false) || (mmsMsg_isFilenameSave(newFileName) == false))
        {
            if (DEBUG_MMS_SERVER)
                printf("MMS_SERVER: remote provided unsave filename -> rejected\n");

            mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_FILE_FILE_NON_EXISTENT);

            return;
        }