// validate a group info table bool AP_Param::check_group_info(const struct AP_Param::GroupInfo * group_info, uint16_t * total_size, uint8_t group_shift, uint8_t prefix_length) { uint8_t type; int8_t max_idx = -1; for (uint8_t i=0; (type=PGM_UINT8(&group_info[i].type)) != AP_PARAM_NONE; i++) { #ifdef AP_NESTED_GROUPS_ENABLED if (type == AP_PARAM_GROUP) { // a nested group const struct GroupInfo *ginfo = (const struct GroupInfo *)PGM_POINTER(&group_info[i].group_info); if (group_shift + _group_level_shift >= _group_bits) { Debug("double group nesting in %S", group_info[i].name); return false; } if (ginfo == NULL || !check_group_info(ginfo, total_size, group_shift + _group_level_shift, prefix_length + strlen_P(group_info[i].name))) { return false; } continue; } #endif // AP_NESTED_GROUPS_ENABLED uint8_t idx = PGM_UINT8(&group_info[i].idx); if (idx >= (1<<_group_level_shift)) { Debug("idx too large (%u) in %S", idx, group_info[i].name); return false; } if ((int8_t)idx <= max_idx) { Debug("indexes must be in increasing order in %S", group_info[i].name); return false; } max_idx = (int8_t)idx; uint8_t size = type_size((enum ap_var_type)type); if (size == 0) { Debug("invalid type in %S", group_info[i].name); return false; } if (prefix_length + strlen_P(group_info[i].name) > 16) { Debug("suffix is too long in %S", group_info[i].name); return false; } (*total_size) += size + sizeof(struct Param_header); } return true; }
// validate a group info table bool AP_Param::check_group_info(const struct AP_Param::GroupInfo * group_info, uint16_t * total_size, uint8_t group_shift) { uint8_t type; int8_t max_idx = -1; for (uint8_t i=0; (type=PGM_UINT8(&group_info[i].type)) != AP_PARAM_NONE; i++) { #ifdef AP_NESTED_GROUPS_ENABLED if (type == AP_PARAM_GROUP) { // a nested group const struct GroupInfo *ginfo = (const struct GroupInfo *)PGM_POINTER(&group_info[i].group_info); if (group_shift + _group_level_shift >= _group_bits) { // double nesting of groups is not allowed return false; } if (ginfo == NULL || !check_group_info(ginfo, total_size, group_shift + _group_level_shift)) { return false; } continue; } #endif // AP_NESTED_GROUPS_ENABLED uint8_t idx = PGM_UINT8(&group_info[i].idx); if (idx >= (1<<_group_level_shift)) { // passed limit on table size return false; } if ((int8_t)idx <= max_idx) { // the indexes must be in increasing order return false; } max_idx = (int8_t)idx; uint8_t size = type_size((enum ap_var_type)type); if (size == 0) { // not a valid type return false; } (*total_size) += size + sizeof(struct Param_header); } return true; }
// validate the _var_info[] table bool AP_Param::check_var_info(void) { uint16_t total_size = sizeof(struct EEPROM_header); for (uint8_t i=0; i<_num_vars; i++) { uint8_t type = PGM_UINT8(&_var_info[i].type); uint8_t key = PGM_UINT8(&_var_info[i].key); if (type == AP_PARAM_GROUP) { if (i == 0) { // first element can't be a group, for first() call return false; } const struct GroupInfo *group_info = (const struct GroupInfo *)PGM_POINTER(&_var_info[i].group_info); if (group_info == NULL || !check_group_info(group_info, &total_size, 0)) { return false; } } else { uint8_t size = type_size((enum ap_var_type)type); if (size == 0) { // not a valid type - the top level list can't contain // AP_PARAM_NONE return false; } total_size += size + sizeof(struct Param_header); } if (duplicate_key(i, key)) { return false; } } // we no longer check if total_size is larger than _eeprom_size, // as we allow for more variables than could fit, relying on not // saving default values return true; }
// validate the _var_info[] table bool AP_Param::check_var_info(void) { uint16_t total_size = sizeof(struct EEPROM_header); for (uint8_t i=0; i<_num_vars; i++) { uint8_t type = PGM_UINT8(&_var_info[i].type); uint8_t key = PGM_UINT8(&_var_info[i].key); if (type == AP_PARAM_GROUP) { if (i == 0) { // first element can't be a group, for first() call return false; } const struct GroupInfo *group_info = (const struct GroupInfo *)PGM_POINTER(&_var_info[i].group_info); if (group_info == NULL || !check_group_info(group_info, &total_size, 0)) { return false; } } else { uint8_t size = type_size((enum ap_var_type)type); if (size == 0) { // not a valid type - the top level list can't contain // AP_PARAM_NONE return false; } total_size += size + sizeof(struct Param_header); } if (duplicate_key(i, key)) { return false; } } if (total_size > _eeprom_size) { serialDebug("total_size %u exceeds _eeprom_size %u", total_size, _eeprom_size); return false; } return true; }