libnsm: bound FPGA diagnostics decode copy by destination size decode_get_fpga_diagnostics_settings_resp copied an on-wire data_size into a caller-provided buffer without verifying it fits the destination, so a crafted response could overflow the small fixed buffer used by the write-protect path (the reported PoC). Add a data_size_max capacity argument and reject an oversized data_size with NSM_SW_ERROR_LENGTH before the memcpy; the six wrappers pass sizeof their destination struct, so no caller signature changes. Regression tests updated. Fixes nvbug https://nvbugspro.nvidia.com/bug/6232725 Signed-off-by: Abhishek Verma <abhisverma@nvidia.com>
diff --git a/libnsm/device-configuration.c b/libnsm/device-configuration.c index 3cfedea..acca8f5 100644 --- a/libnsm/device-configuration.c +++ b/libnsm/device-configuration.c
@@ -1250,11 +1250,9 @@ return NSM_SW_SUCCESS; } -int decode_get_fpga_diagnostics_settings_resp(const struct nsm_msg *msg, - size_t msg_len, uint8_t *cc, - uint16_t *data_size, - uint16_t *reason_code, - uint8_t *data) +int decode_get_fpga_diagnostics_settings_resp( + const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, uint16_t *data_size, + uint16_t *reason_code, uint8_t *data, size_t data_size_max) { if (msg == NULL || cc == NULL || data_size == NULL || reason_code == NULL || data == NULL) { @@ -1281,6 +1279,9 @@ msg_len) { return NSM_SW_ERROR_LENGTH; } + if ((size_t)*data_size > data_size_max) { + return NSM_SW_ERROR_LENGTH; + } memcpy(data, resp->data, *data_size); return NSM_SW_SUCCESS; } @@ -1301,7 +1302,8 @@ { uint16_t data_size = 0; int ret = decode_get_fpga_diagnostics_settings_resp( - msg, msg_len, cc, &data_size, reason_code, (uint8_t *)data); + msg, msg_len, cc, &data_size, reason_code, (uint8_t *)data, + sizeof(struct nsm_fpga_diagnostics_settings_wp)); if (ret != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) return ret; if (data_size < sizeof(struct nsm_fpga_diagnostics_settings_wp)) @@ -1325,7 +1327,8 @@ { uint16_t data_size = 0; int ret = decode_get_fpga_diagnostics_settings_resp( - msg, msg_len, cc, &data_size, reason_code, (uint8_t *)data); + msg, msg_len, cc, &data_size, reason_code, (uint8_t *)data, + sizeof(struct nsm_fpga_diagnostics_settings_wp_jumper)); if (ret != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) return ret; if (data_size < sizeof(struct nsm_fpga_diagnostics_settings_wp_jumper)) @@ -1351,7 +1354,7 @@ uint16_t data_size = 0; int ret = decode_get_fpga_diagnostics_settings_resp( msg, msg_len, cc, &data_size, reason_code, - (uint8_t *)power_supply_status); + (uint8_t *)power_supply_status, sizeof(uint8_t)); if (ret != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) return ret; if (data_size < sizeof(uint8_t)) @@ -1373,7 +1376,8 @@ { uint16_t data_size = 0; int ret = decode_get_fpga_diagnostics_settings_resp( - msg, msg_len, cc, &data_size, reason_code, (uint8_t *)presence); + msg, msg_len, cc, &data_size, reason_code, (uint8_t *)presence, + sizeof(uint8_t)); if (ret != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) return ret; if (data_size < sizeof(uint8_t)) @@ -1395,7 +1399,8 @@ { uint16_t data_size = 0; int ret = decode_get_fpga_diagnostics_settings_resp( - msg, msg_len, cc, &data_size, reason_code, (uint8_t *)power_status); + msg, msg_len, cc, &data_size, reason_code, (uint8_t *)power_status, + sizeof(uint8_t)); if (ret != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) return ret; if (data_size < sizeof(uint8_t)) @@ -1417,7 +1422,7 @@ { uint16_t data_size = 0; int ret = decode_get_fpga_diagnostics_settings_resp( - msg, msg_len, cc, &data_size, reason_code, mode); + msg, msg_len, cc, &data_size, reason_code, mode, sizeof(uint8_t)); if (ret != NSM_SW_SUCCESS || *cc != NSM_SUCCESS) return ret; if (data_size < sizeof(uint8_t))
diff --git a/libnsm/device-configuration.h b/libnsm/device-configuration.h index d0eebac..b096951 100644 --- a/libnsm/device-configuration.h +++ b/libnsm/device-configuration.h
@@ -1311,13 +1311,13 @@ * @param[out] cc - pointer to response message completion code * @param[in] data_size - data size * @param[out] data - pointer to the array of data + * @param[in] data_size_max - maximum size of the data buffer in bytes; the + * decoded data_size must not exceed this * @return nsm_completion_codes */ -int decode_get_fpga_diagnostics_settings_resp(const struct nsm_msg *msg, - size_t msg_len, uint8_t *cc, - uint16_t *data_size, - uint16_t *reason_code, - uint8_t *data); +int decode_get_fpga_diagnostics_settings_resp( + const struct nsm_msg *msg, size_t msg_len, uint8_t *cc, uint16_t *data_size, + uint16_t *reason_code, uint8_t *data, size_t data_size_max); /** @brief Encode a Get FPGA Diagnostics Settings response msg for * Get WP Settings
diff --git a/libnsm/test/libnsm_device_configuration_branch2_test.cpp b/libnsm/test/libnsm_device_configuration_branch2_test.cpp index 84bff72..60d0119 100644 --- a/libnsm/test/libnsm_device_configuration_branch2_test.cpp +++ b/libnsm/test/libnsm_device_configuration_branch2_test.cpp
@@ -104,7 +104,8 @@ uint16_t data_size = 0, reason_code = 0; uint8_t data[64] = {}; auto rc = decode_get_fpga_diagnostics_settings_resp( - msg, buf.size(), nullptr, &data_size, &reason_code, data); + msg, buf.size(), nullptr, &data_size, &reason_code, data, + sizeof(data)); EXPECT_EQ(rc, NSM_SW_ERROR_NULL); } @@ -119,7 +120,7 @@ uint16_t data_size = 0, reason_code = 0; uint8_t data[64] = {}; auto rc = decode_get_fpga_diagnostics_settings_resp( - msg, buf.size(), &cc, &data_size, &reason_code, data); + msg, buf.size(), &cc, &data_size, &reason_code, data, sizeof(data)); EXPECT_EQ(rc, NSM_SW_SUCCESS); EXPECT_EQ(cc, 0xFF); } @@ -137,7 +138,7 @@ uint16_t data_size = 0, reason_code = 0; uint8_t data[64] = {}; auto rc = decode_get_fpga_diagnostics_settings_resp( - msg, buf.size(), &cc, &data_size, &reason_code, data); + msg, buf.size(), &cc, &data_size, &reason_code, data, sizeof(data)); EXPECT_EQ(rc, NSM_SW_ERROR_LENGTH); }
diff --git a/libnsm/test/libnsm_device_configuration_branch4_test.cpp b/libnsm/test/libnsm_device_configuration_branch4_test.cpp index 181b80b..7def13b 100644 --- a/libnsm/test/libnsm_device_configuration_branch4_test.cpp +++ b/libnsm/test/libnsm_device_configuration_branch4_test.cpp
@@ -633,7 +633,7 @@ uint16_t ds = 0, reason = 0; uint8_t data[32] = {}; auto rc = decode_get_fpga_diagnostics_settings_resp( - msg, buf.size(), nullptr, &ds, &reason, data); + msg, buf.size(), nullptr, &ds, &reason, data, sizeof(data)); EXPECT_EQ(rc, NSM_SW_ERROR_NULL); } @@ -644,7 +644,7 @@ uint8_t cc = 0; uint16_t ds = 0, reason = 0; auto rc = decode_get_fpga_diagnostics_settings_resp( - msg, buf.size(), &cc, &ds, &reason, nullptr); + msg, buf.size(), &cc, &ds, &reason, nullptr, 0); EXPECT_EQ(rc, NSM_SW_ERROR_NULL); }
diff --git a/libnsm/test/libnsm_device_configuration_test.cpp b/libnsm/test/libnsm_device_configuration_test.cpp index a653a7e..ce8941b 100644 --- a/libnsm/test/libnsm_device_configuration_test.cpp +++ b/libnsm/test/libnsm_device_configuration_test.cpp
@@ -751,7 +751,8 @@ EXPECT_EQ(rc, NSM_SW_ERROR_NULL); rc = decode_get_fpga_diagnostics_settings_resp( - response, msg_len, &cc, NULL, &reason_code, (uint8_t *)data); + response, msg_len, &cc, NULL, &reason_code, (uint8_t *)data, + sizeof(struct nsm_fpga_diagnostics_settings_wp)); EXPECT_EQ(rc, NSM_SW_ERROR_NULL); rc = decode_get_fpga_diagnostics_settings_wp_resp( @@ -874,7 +875,8 @@ EXPECT_EQ(rc, NSM_SW_ERROR_NULL); rc = decode_get_fpga_diagnostics_settings_resp( - response, msg_len, &cc, NULL, &reason_code, (uint8_t *)data); + response, msg_len, &cc, NULL, &reason_code, (uint8_t *)data, + sizeof(struct nsm_fpga_diagnostics_settings_wp_jumper)); EXPECT_EQ(rc, NSM_SW_ERROR_NULL); rc = decode_get_fpga_diagnostics_settings_wp_jumper_resp( @@ -3779,7 +3781,7 @@ uint16_t rc = 0; uint8_t dst[8] = {0}; EXPECT_EQ(decode_get_fpga_diagnostics_settings_resp( - asMsg(buf), buf.size(), &cc, &ds, &rc, dst), + asMsg(buf), buf.size(), &cc, &ds, &rc, dst, sizeof(dst)), NSM_SW_ERROR_LENGTH); }