diff --git a/library/spdm_responder_lib/libspdm_rsp_chunk_get.c b/library/spdm_responder_lib/libspdm_rsp_chunk_get.c index 0fb140ee0b6..fec6988de5b 100644 --- a/library/spdm_responder_lib/libspdm_rsp_chunk_get.c +++ b/library/spdm_responder_lib/libspdm_rsp_chunk_get.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2024 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -17,6 +17,7 @@ libspdm_return_t libspdm_get_response_chunk_get( { libspdm_chunk_info_t* get_info; uint32_t min_data_transfer_size; + size_t max_chunk_data_transfer_size; const spdm_chunk_get_request_t* spdm_request; spdm_chunk_response_response_t* spdm_response; @@ -103,12 +104,22 @@ libspdm_return_t libspdm_get_response_chunk_get( response_size, response); } - libspdm_zero_mem(response, *response_size); - min_data_transfer_size = LIBSPDM_MIN( spdm_context->connection_info.capability.data_transfer_size, spdm_context->local_context.capability.sender_data_transfer_size); + /* Fail if exceed max chunks */ + max_chunk_data_transfer_size = ((size_t) min_data_transfer_size - sizeof(spdm_chunk_response_response_t)) * 65536 - sizeof(uint32_t); + + if (get_info->large_message_size > max_chunk_data_transfer_size) { + return libspdm_generate_error_response( + spdm_context, + SPDM_ERROR_CODE_RESPONSE_TOO_LARGE, 0, + response_size, response); + } + + libspdm_zero_mem(response, *response_size); + /* Assert the data transfer size is smaller than the response size. * Otherwise there is no reason to chunk this response. */ LIBSPDM_ASSERT(min_data_transfer_size < *response_size); diff --git a/unit_test/test_spdm_responder/chunk_get.c b/unit_test/test_spdm_responder/chunk_get.c index cfc04574195..26017c0b3a4 100644 --- a/unit_test/test_spdm_responder/chunk_get.c +++ b/unit_test/test_spdm_responder/chunk_get.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2022 DMTF. All rights reserved. + * Copyright 2021-2025 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -996,6 +996,101 @@ void libspdm_test_responder_chunk_get_rsp_case13(void** state) } } + +/** + * Test 14: Responder has reponse exceed chunk seq no + **/ +void libspdm_test_responder_chunk_get_rsp_case14(void** state) +{ + libspdm_return_t status; + libspdm_test_context_t* spdm_test_context; + libspdm_context_t* spdm_context; + size_t response_size; + uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE]; + spdm_error_response_t* spdm_response; + spdm_chunk_get_request_t spdm_request; + void* scratch_buffer; + size_t scratch_buffer_size; + + uint8_t chunk_handle; + uint32_t data_transfer_size; + uint32_t total_chunk_size; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 10; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + + spdm_context->connection_info.connection_state = + LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->connection_info.algorithm.base_hash_algo = + m_libspdm_use_hash_algo; + + data_transfer_size = CHUNK_GET_RESPONDER_UNIT_TEST_DATA_TRANSFER_SIZE; + spdm_context->local_context.capability.data_transfer_size = data_transfer_size; + spdm_context->local_context.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP; + + /* large response need a large scratch buffer */ + spdm_context->connection_info.capability.max_spdm_msg_size = data_transfer_size * 65536; + spdm_context->local_context.capability.max_spdm_msg_size = data_transfer_size * 65536; + spdm_test_context->scratch_buffer_size = + libspdm_get_sizeof_required_scratch_buffer(spdm_context); + spdm_test_context->scratch_buffer = (void *)malloc(spdm_test_context->scratch_buffer_size); + libspdm_set_scratch_buffer (spdm_context, + spdm_test_context->scratch_buffer, + spdm_test_context->scratch_buffer_size); + + + libspdm_get_scratch_buffer(spdm_context, &scratch_buffer, &scratch_buffer_size); + + scratch_buffer = (uint8_t*)scratch_buffer + + libspdm_get_scratch_buffer_large_message_offset(spdm_context); + scratch_buffer_size = scratch_buffer_size - + libspdm_get_scratch_buffer_large_message_offset(spdm_context); + libspdm_zero_mem(scratch_buffer, scratch_buffer_size); + + /* a huge chunk size to cause the chunk seq no wrap */ + total_chunk_size = data_transfer_size * 65536; + + LIBSPDM_ASSERT(total_chunk_size <= scratch_buffer_size); + + chunk_handle = (uint8_t) spdm_test_context->case_id; /* Any number is fine */ + spdm_context->chunk_context.get.chunk_in_use = true; + spdm_context->chunk_context.get.chunk_handle = chunk_handle; + spdm_context->chunk_context.get.chunk_seq_no = 0; + spdm_context->chunk_context.get.large_message = scratch_buffer; + spdm_context->chunk_context.get.large_message_size = total_chunk_size; + spdm_context->chunk_context.get.chunk_bytes_transferred = 0; + + libspdm_zero_mem(&spdm_request, sizeof(spdm_request)); + spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12; + spdm_request.header.request_response_code = SPDM_CHUNK_GET; + spdm_request.header.param1 = 0; + spdm_request.header.param2 = chunk_handle; + spdm_request.chunk_seq_no = 0; + + response_size = sizeof(response); + status = libspdm_get_response_chunk_get( + spdm_context, + sizeof(spdm_request), &spdm_request, + &response_size, response); + + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); + assert_int_equal(response_size, sizeof(spdm_error_response_t)); + + spdm_response = (spdm_error_response_t*) response; + + assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12); + assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR); + assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_RESPONSE_TOO_LARGE); + assert_int_equal(spdm_response->header.param2, 0); +} + + int libspdm_responder_chunk_get_rsp_test_main(void) { const struct CMUnitTest spdm_responder_chunk_get_tests[] = { @@ -1025,6 +1120,8 @@ int libspdm_responder_chunk_get_rsp_test_main(void) cmocka_unit_test(libspdm_test_responder_chunk_get_rsp_case12), /* Successful request of last chunk where chunk size is exactly 1 byte */ cmocka_unit_test(libspdm_test_responder_chunk_get_rsp_case13), + /* Responder has reponse exceed chunk seq no */ + cmocka_unit_test(libspdm_test_responder_chunk_get_rsp_case14), }; libspdm_test_context_t test_context = {