Commit message: ofp-group: Don't assert-fail decoding bad OF1.5 group mod type or command.

When decoding a group mod, the current code validates the group type and
command after the whole group mod has been decoded.  The OF1.5 decoder,
however, tries to use the type and command earlier, when it might still be
invalid.  This caused an assertion failure (via OVS_NOT_REACHED).  This
commit fixes the problem.

ovs-vswitchd does not enable support for OpenFlow 1.5 by default.

Reported-at: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=9249
Signed-off-by: Ben Pfaff <blp@ovn.org>
Reviewed-by: Yifeng Sun <pkusunyifeng@gmail.com>
CVE: CVE-2018-17204
CWE: CWE-617
Vulnerability description: An issue was discovered in Open vSwitch (OvS) 2.7.x through 2.7.6, affecting parse_group_prop_ntr_selection_method in lib/ofp-util.c. When decoding a group mod, it validates the group type and command after the whole group mod has been decoded. The OF1.5 decoder, however, tries to use the type and command earlier, when it might still be invalid. This causes an assertion failure (via OVS_NOT_REACHED). ovs-vswitchd does not enable support for OpenFlow 1.5 by default.

Project: ovs
File: ofp-util.c

parse_group_prop_ntr_selection_method(struct ofpbuf *payload,
                                      enum ofp11_group_type group_type,
                                      enum ofp15_group_mod_command group_cmd,
                                      struct ofputil_group_props *gp)
{
    struct ntr_group_prop_selection_method *prop = payload->data;
    size_t fields_len, method_len;
    enum ofperr error;

    switch (group_type) {
    case OFPGT11_SELECT:
        break;
    case OFPGT11_ALL:
    case OFPGT11_INDIRECT:
    case OFPGT11_FF:
        OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method property is "
                     "only allowed for select groups");
         return OFPERR_OFPBPC_BAD_VALUE;
     default:
        return OFPERR_OFPGMFC_BAD_TYPE;
     }
 
     switch (group_cmd) {
    case OFPGC15_ADD:
    case OFPGC15_MODIFY:
    case OFPGC15_ADD_OR_MOD:
        break;
    case OFPGC15_DELETE:
    case OFPGC15_INSERT_BUCKET:
    case OFPGC15_REMOVE_BUCKET:
        OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method property is "
                     "only allowed for add and delete group modifications");
         return OFPERR_OFPBPC_BAD_VALUE;
     default:
        return OFPERR_OFPGMFC_BAD_COMMAND;
     }
 
     if (payload->size < sizeof *prop) {
        OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method property "
                    "length %u is not valid", payload->size);
        return OFPERR_OFPBPC_BAD_LEN;
    }

    method_len = strnlen(prop->selection_method, NTR_MAX_SELECTION_METHOD_LEN);

    if (method_len == NTR_MAX_SELECTION_METHOD_LEN) {
        OFPPROP_LOG(&bad_ofmsg_rl, false,
                    "ntr selection method is not null terminated");
        return OFPERR_OFPBPC_BAD_VALUE;
    }

    if (strcmp("hash", prop->selection_method)
        && strcmp("dp_hash", prop->selection_method)) {
        OFPPROP_LOG(&bad_ofmsg_rl, false,
                    "ntr selection method '%s' is not supported",
                    prop->selection_method);
        return OFPERR_OFPBPC_BAD_VALUE;
    }
    /* 'method_len' is now non-zero. */

    strcpy(gp->selection_method, prop->selection_method);
    gp->selection_method_param = ntohll(prop->selection_method_param);

    ofpbuf_pull(payload, sizeof *prop);

    fields_len = ntohs(prop->length) - sizeof *prop;
    if (fields_len && strcmp("hash", gp->selection_method)) {
        OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method %s "
                    "does not support fields", gp->selection_method);
        return OFPERR_OFPBPC_BAD_VALUE;
    }

    error = oxm_pull_field_array(payload->data, fields_len,
                                 &gp->fields);
    if (error) {
        OFPPROP_LOG(&bad_ofmsg_rl, false,
                    "ntr selection method fields are invalid");
        return error;
    }

    return 0;
}