From 2db637f213f7631c988b0f849246d0596da8cb37 Mon Sep 17 00:00:00 2001 From: Aaron Li Date: Tue, 7 Jan 2025 11:09:27 +0800 Subject: [PATCH] Fix chunk_seq_no wrap in chunk send. Fix #2875 Signed-off-by: Aaron Li --- .../libspdm_req_send_receive.c | 20 +++-- unit_test/test_spdm_requester/chunk_send.c | 75 ++++++++++++++++++- 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/library/spdm_requester_lib/libspdm_req_send_receive.c b/library/spdm_requester_lib/libspdm_req_send_receive.c index 8639de04129..20b9447026a 100644 --- a/library/spdm_requester_lib/libspdm_req_send_receive.c +++ b/library/spdm_requester_lib/libspdm_req_send_receive.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 **/ @@ -316,6 +316,7 @@ libspdm_return_t libspdm_handle_large_request( size_t copy_size; libspdm_chunk_info_t *send_info; uint32_t min_data_transfer_size; + size_t max_chunk_data_transfer_size; spdm_error_response_t *spdm_error; if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) { @@ -330,6 +331,19 @@ libspdm_return_t libspdm_handle_large_request( return LIBSPDM_STATUS_ERROR_PEER; } + /* Fail if exceed max chunks */ + min_data_transfer_size = LIBSPDM_MIN( + spdm_context->connection_info.capability.data_transfer_size, + spdm_context->local_context.capability.sender_data_transfer_size); + + max_chunk_data_transfer_size = + ((size_t) min_data_transfer_size - sizeof(spdm_chunk_send_request_t)) * 65536 - + sizeof(uint32_t); + + if (request_size > max_chunk_data_transfer_size) { + return LIBSPDM_STATUS_BUFFER_TOO_SMALL; + } + /* now we can get sender buffer */ transport_header_size = spdm_context->local_context.capability.transport_header_size; @@ -359,10 +373,6 @@ libspdm_return_t libspdm_handle_large_request( request = NULL; /* Invalidate to prevent accidental use. */ request_size = 0; - min_data_transfer_size = LIBSPDM_MIN( - spdm_context->connection_info.capability.data_transfer_size, - spdm_context->local_context.capability.sender_data_transfer_size); - do { LIBSPDM_ASSERT(send_info->large_message_capacity >= transport_header_size); spdm_request = (spdm_chunk_send_request_t *)((uint8_t *)message + transport_header_size); diff --git a/unit_test/test_spdm_requester/chunk_send.c b/unit_test/test_spdm_requester/chunk_send.c index b66e411754f..45f3e70736b 100644 --- a/unit_test/test_spdm_requester/chunk_send.c +++ b/unit_test/test_spdm_requester/chunk_send.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 **/ @@ -105,6 +105,10 @@ libspdm_return_t libspdm_requester_chunk_send_test_send_message( LIBSPDM_ASSERT(chunk_send->header.request_response_code == SPDM_CHUNK_SEND); return LIBSPDM_STATUS_SUCCESS; } + if (spdm_test_context->case_id == 13) { + /* Should never reach here since the test case is meant to fail before send */ + LIBSPDM_ASSERT(0); + } return LIBSPDM_STATUS_SEND_FAIL; } @@ -323,6 +327,10 @@ libspdm_return_t libspdm_requester_chunk_send_test_receive_message( return LIBSPDM_STATUS_SUCCESS; } + if (spdm_test_context->case_id == 13) { + /* Should never reach here since the test case is meant to fail before send */ + LIBSPDM_ASSERT(0); + } return LIBSPDM_STATUS_RECEIVE_FAIL; } @@ -380,6 +388,56 @@ libspdm_return_t libspdm_test_requester_chunk_send_generic_test_case( return status; } +libspdm_return_t libspdm_test_requester_chunk_send_vendor_specific_test_case( + void** state, uint32_t case_id) +{ + /* Use vendor specific request to generate a large request. */ + libspdm_return_t status; + libspdm_test_context_t* spdm_test_context; + libspdm_context_t* spdm_context; + + uint16_t standard_id = 6; + uint8_t vendor_id_len = 2; + uint8_t vendor_id[SPDM_MAX_VENDOR_ID_LENGTH] = {0xAA, 0xAA}; + uint16_t data_len = 65535; + uint8_t data[65535] = {0}; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = case_id; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + /* Large request need a large scratch buffer. */ + spdm_context->connection_info.capability.max_spdm_msg_size = 0x12000; + spdm_context->local_context.capability.max_spdm_msg_size = 0x12000; + spdm_context->connection_info.connection_state = + LIBSPDM_CONNECTION_STATE_NEGOTIATED; + spdm_context->connection_info.capability.flags |= + (SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP + | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP); + spdm_context->connection_info.capability.data_transfer_size + = sizeof(spdm_chunk_send_request_t) + 1; + spdm_context->local_context.capability.sender_data_transfer_size + = CHUNK_SEND_REQUESTER_UNIT_TEST_DATA_TRANSFER_SIZE; + spdm_context->local_context.is_requester = true; + + 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_reset_message_a(spdm_context); + + status = libspdm_vendor_send_request_receive_response(spdm_context, NULL, + standard_id, vendor_id_len, vendor_id, + data_len, data, + &standard_id, &vendor_id_len, vendor_id, + &data_len, data); + return status; +} + void libspdm_test_requester_chunk_send_case1(void** state) { libspdm_return_t status; @@ -472,6 +530,19 @@ void libspdm_test_requester_chunk_send_case12(void** state) assert_int_equal(status, LIBSPDM_STATUS_ERROR_PEER); } + +/** + * Test 13: Request size shall not exceed max supported transfer size. + * Expected behavior: returns a status of LIBSPDM_STATUS_SEND_FAIL, + **/ +void libspdm_test_requester_chunk_send_case13(void** state) +{ + libspdm_return_t status; + + status = libspdm_test_requester_chunk_send_vendor_specific_test_case(state, 13); + assert_int_equal(status, LIBSPDM_STATUS_SEND_FAIL); +} + int libspdm_requester_chunk_send_test_main(void) { /* Test the CHUNK_SEND handlers in various requester handlers */ @@ -500,6 +571,8 @@ int libspdm_requester_chunk_send_test_main(void) cmocka_unit_test(libspdm_test_requester_chunk_send_case11), /* ErrorCode == LargeResponse shall not be allowed in ResponseToLargeRequest */ cmocka_unit_test(libspdm_test_requester_chunk_send_case12), + /* Request size exceed max chunks */ + cmocka_unit_test(libspdm_test_requester_chunk_send_case13), }; libspdm_test_context_t test_context = {