fru: Introduce get_fru_record_by_option_check()

get_fru_record_by_option() protected the injection of record data into
the record buffer only using assert(). get_fru_record_by_option_check()
instead returns an error if the record data would overflow the record
buffer.

Callers should prefer get_fru_record_by_option_check(), and testing its
result, over get_fru_record_by_option().

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: Ifc1459863cd9f3f7289badb9f1842386d31cbd87
diff --git a/src/fru.c b/src/fru.c
index aeb7d50..39d8576 100644
--- a/src/fru.c
+++ b/src/fru.c
@@ -216,6 +216,17 @@
 			      uint8_t *record_table, size_t *record_size,
 			      uint16_t rsi, uint8_t rt, uint8_t ft)
 {
+	int rc = get_fru_record_by_option_check(table, table_size, record_table,
+						record_size, rsi, rt, ft);
+	(void)rc;
+	assert(rc == PLDM_SUCCESS);
+}
+
+LIBPLDM_ABI_TESTING
+int get_fru_record_by_option_check(const uint8_t *table, size_t table_size,
+				   uint8_t *record_table, size_t *record_size,
+				   uint16_t rsi, uint8_t rt, uint8_t ft)
+{
 	const struct pldm_fru_record_data_format *record_data_src =
 		(const struct pldm_fru_record_data_format *)table;
 	struct pldm_fru_record_data_format *record_data_dest;
@@ -246,6 +257,9 @@
 		      sizeof(struct pldm_fru_record_tlv);
 
 		assert(pos - record_table + len < *record_size);
+		if (pos - record_table + len >= *record_size) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
 		memcpy(pos, record_data_src, len);
 
 		record_data_dest = (struct pldm_fru_record_data_format *)pos;
@@ -257,6 +271,9 @@
 			len = sizeof(*tlv) - 1 + tlv->length;
 			if (tlv->type == ft || ft == 0) {
 				assert(pos - record_table + len < *record_size);
+				if (pos - record_table + len >= *record_size) {
+					return PLDM_ERROR_INVALID_LENGTH;
+				}
 				memcpy(pos, tlv, len);
 				pos += len;
 				count++;
@@ -270,6 +287,8 @@
 	}
 
 	*record_size = pos - record_table;
+
+	return PLDM_SUCCESS;
 }
 
 LIBPLDM_ABI_STABLE