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/CHANGELOG.md b/CHANGELOG.md
index 9f0b16e..6cdaa84 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
### Added
1. bios_table: Introduce pldm_bios_table_append_pad_checksum_check()
+2. fru: Introduce get_fru_record_by_option_check()
### Changed
diff --git a/include/libpldm/fru.h b/include/libpldm/fru.h
index ce93e55..d046805 100644
--- a/include/libpldm/fru.h
+++ b/include/libpldm/fru.h
@@ -464,6 +464,22 @@
void get_fru_record_by_option(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);
+
+/** @brief Get FRU Record Table By Option or return an error
+ * @param[in] table - The source fru record table
+ * @param[in] table_size - Size of the source fru record table
+ * @param[out] record_table - Fru table fetched based on the input option
+ * @param[in/out] record_size - Size of the table fetched by fru record option
+ * @param[in] rsi - FRU record set identifier
+ * @param[in] rt - FRU record type
+ * @param[in] ft - FRU field type
+ *
+ * @return PLDM_SUCCESS if no error occurs. PLDM_ERROR_INVALID_LENGTH if record_size lacks capacity
+ * to encode the relevant records.
+ */
+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);
/* SetFruRecordTable */
/** @brief Decode SetFruRecordTable request data
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