From 5fa758767e517779fc5398b6b4faedc4e36d3de5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Veronika=20Hanul=C3=ADkov=C3=A1?= <vhanulik@redhat.com>
Date: Fri, 12 Jul 2024 14:03:59 +0200
Subject: [PATCH] muscle: Report invalid SW when reading object

Thanks Matteo Marini for report
https://github.com/OpenSC/OpenSC/security/advisories/GHSA-p3mx-7472-h3j8

fuzz_pkcs11/20, fuzz_pkcs15init/10

CVE: CVE-2024-45616
Upstream-Status: Backport [https://github.com/OpenSC/OpenSC/commit/5fa758767e517779fc5398b6b4faedc4e36d3de5]

Signed-off-by: Zhang Peng <peng.zhang1.cn@windriver.com>
---
 src/libopensc/muscle.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/src/libopensc/muscle.c b/src/libopensc/muscle.c
index a749657df..b30173ec6 100644
--- a/src/libopensc/muscle.c
+++ b/src/libopensc/muscle.c
@@ -92,33 +92,34 @@ int msc_partial_read_object(sc_card_t *card, msc_id objectId, int offset, u8 *da
 	apdu.resp = data; 
 	r = sc_transmit_apdu(card, &apdu);
 	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-	if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
+	if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && dataLength <= apdu.resplen)
 		return dataLength;
-	if(apdu.sw1 == 0x9C) {
-		if(apdu.sw2 == 0x07) {
+	if (apdu.sw1 == 0x9C) {
+		if (apdu.sw2 == 0x07) {
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
-		} else if(apdu.sw2 == 0x06) {
+		} else if (apdu.sw2 == 0x06) {
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
-		} else if(apdu.sw2 == 0x0F) {
+		} else if (apdu.sw2 == 0x0F) {
 			/* GUESSED */
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
 		}
 	}
 	sc_log(card->ctx, 
 		"got strange SWs: 0x%02X 0x%02X\n", apdu.sw1, apdu.sw2);
-	return dataLength;
-	
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
 }
 
 int msc_read_object(sc_card_t *card, msc_id objectId, int offset, u8 *data, size_t dataLength)
 {
-	int r;
+	int r = 0;
 	size_t i;
 	size_t max_read_unit = MSC_MAX_READ;
 
-	for(i = 0; i < dataLength; i += max_read_unit) {
+	for(i = 0; i < dataLength; i += r) {
 		r = msc_partial_read_object(card, objectId, offset + i, data + i, MIN(dataLength - i, max_read_unit));
 		LOG_TEST_RET(card->ctx, r, "Error in partial object read");
+		if (r == 0)
+			break;
 	}
 	return dataLength;
 }
--
2.34.1
