CVE-2023-27772 (C, published 2023-04-13T18:15Z)
Description: value: libiec61850 v1.5.1 was discovered to contain a segmentation violation via the function ControlObjectClient_setOrigin() at /client/client_control.c.
Severity: nan (CVSS v3 base score: 7.5)
Weakness: CWE-754 \u2014 Improper Check for Unusual or Exceptional Conditions
The product does not check or incorrectly checks for unusual or exceptional conditions that are not expected to occur frequently during day to day operation of the product.
Repository: https://github.com/mz-automation/libiec61850
Files changed:
examples/iec61850_client_example_control/client_example_control.c
Commit message: - added missing checks in iec61850_client_example_control (#442)


Vulnerable code:
    if (error == IED_ERROR_OK) {

        MmsValue* ctlVal = MmsValue_newBoolean(true);
        ControlObjectClient_setOrigin(control, NULL, 3);
        if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
            printf("simpleIOGenericIO/GGIO1.SPCSO1 operated successfully\n");
        }
        else {
            printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO1\n");
        }
        MmsValue_delete(ctlVal);
        ControlObjectClient_destroy(control);
        /* Check if status value has changed */
        MmsValue* stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO1.stVal", IEC61850_FC_ST);
        if (error == IED_ERROR_OK) {
            bool state = MmsValue_getBoolean(stVal);
            MmsValue_delete(stVal);
            printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state);
            printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO1 failed!\n");

        if (ControlObjectClient_select(control)) {
            ctlVal = MmsValue_newBoolean(true);
            if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                printf("simpleIOGenericIO/GGIO1.SPCSO2 operated successfully\n");
                printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO2!\n");
            MmsValue_delete(ctlVal);
            printf("failed to select simpleIOGenericIO/GGIO1.SPCSO2!\n");
        ControlObjectClient_destroy(control);


        ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
        ctlVal = MmsValue_newBoolean(true);
        if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
            printf("simpleIOGenericIO/GGIO1.SPCSO3 operated successfully\n");
        }
        else {
            printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO3\n");
        }
        MmsValue_delete(ctlVal);
        /* Wait for command termination message */
        Thread_sleep(1000);
        ControlObjectClient_destroy(control);
        /* Check if status value has changed */
       stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", IEC61850_FC_ST);
        if (error == IED_ERROR_OK) {
            bool state = MmsValue_getBoolean(stVal);
            printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state);
            MmsValue_delete(stVal);
            printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n");
        ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
        ctlVal = MmsValue_newBoolean(true);
        if (ControlObjectClient_selectWithValue(control, ctlVal)) {
            if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                printf("simpleIOGenericIO/GGIO1.SPCSO4 operated successfully\n");
                printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO4!\n");
            printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n");
        MmsValue_delete(ctlVal);

        /* Wait for command termination message */
        Thread_sleep(1000);

        ControlObjectClient_destroy(control);


        ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);

        ctlVal = MmsValue_newBoolean(true);
        if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
            printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n");
        }
        else {
            printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n");
        }
        MmsValue_delete(ctlVal);
        /* Wait for command termination message */
        Thread_sleep(1000);
        ControlObjectClient_destroy(control);

Fixed code:
    if (error == IED_ERROR_OK)
    {
        MmsValue* ctlVal = NULL;
        MmsValue* stVal = NULL;
        if (control)
        {
            ctlVal = MmsValue_newBoolean(true);
            ControlObjectClient_setOrigin(control, NULL, 3);
            if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                printf("simpleIOGenericIO/GGIO1.SPCSO1 operated successfully\n");
            }
            else {
                printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO1\n");
            }

            MmsValue_delete(ctlVal);
            ControlObjectClient_destroy(control);
            /* Check if status value has changed */
            stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO1.stVal", IEC61850_FC_ST);
            if (error == IED_ERROR_OK) {
                bool state = MmsValue_getBoolean(stVal);
                MmsValue_delete(stVal);
                printf("New status of simpleIOGenericIO/GGIO1.SPCSO1.stVal: %i\n", state);
            }
            else {
                printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO1 failed!\n");
            }
            printf("Control object simpleIOGenericIO/GGIO1.SPCSO1 not found in server\n");
        if (control)
        {
            if (ControlObjectClient_select(control)) {
                ctlVal = MmsValue_newBoolean(true);
                if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                    printf("simpleIOGenericIO/GGIO1.SPCSO2 operated successfully\n");
                }
                else {
                    printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO2!\n");
                }

                MmsValue_delete(ctlVal);
                printf("failed to select simpleIOGenericIO/GGIO1.SPCSO2!\n");
            ControlObjectClient_destroy(control);
            printf("Control object simpleIOGenericIO/GGIO1.SPCSO2 not found in server\n");
        if (control)
        {
            ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
            ctlVal = MmsValue_newBoolean(true);
            if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                printf("simpleIOGenericIO/GGIO1.SPCSO3 operated successfully\n");
            }
            else {
                printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO3\n");
            }
            MmsValue_delete(ctlVal);
            /* Wait for command termination message */
            Thread_sleep(1000);
            ControlObjectClient_destroy(control);
            /* Check if status value has changed */
            stVal = IedConnection_readObject(con, &error, "simpleIOGenericIO/GGIO1.SPCSO3.stVal", IEC61850_FC_ST);
            if (error == IED_ERROR_OK) {
                bool state = MmsValue_getBoolean(stVal);
                printf("New status of simpleIOGenericIO/GGIO1.SPCSO3.stVal: %i\n", state);
                MmsValue_delete(stVal);
            }
            else {
                printf("Reading status for simpleIOGenericIO/GGIO1.SPCSO3 failed!\n");
            }
            printf("Control object simpleIOGenericIO/GGIO1.SPCSO3 not found in server\n");
        if (control)
        {
            ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
            ctlVal = MmsValue_newBoolean(true);
            if (ControlObjectClient_selectWithValue(control, ctlVal)) {

                if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                    printf("simpleIOGenericIO/GGIO1.SPCSO4 operated successfully\n");
                }
                else {
                    printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO4!\n");
                }
                printf("failed to select simpleIOGenericIO/GGIO1.SPCSO4!\n");
            MmsValue_delete(ctlVal);

            /* Wait for command termination message */
            Thread_sleep(1000);

            ControlObjectClient_destroy(control);
            printf("Control object simpleIOGenericIO/GGIO1.SPCSO4 not found in server\n");
        if (control)
        {
            ControlObjectClient_setCommandTerminationHandler(control, commandTerminationHandler, NULL);
            ctlVal = MmsValue_newBoolean(true);
            if (ControlObjectClient_operate(control, ctlVal, 0 /* operate now */)) {
                printf("simpleIOGenericIO/GGIO1.SPCSO9 operated successfully\n");
            }
            else {
                printf("failed to operate simpleIOGenericIO/GGIO1.SPCSO9\n");
            }
            MmsValue_delete(ctlVal);
            /* Wait for command termination message */
            Thread_sleep(1000);
            ControlObjectClient_destroy(control);
        }
        else {
            printf("Control object simpleIOGenericIO/GGIO1.SPCSO9 not found in server\n");
        }