mirror of
https://github.com/bettse/seader.git
synced 2026-10-22 12:52:30 +00:00
fix: enhance scratchpad safety and optimize memory handling
- Strengthened scratchpad bounds validation and ensured pointer range checks. - Improved memory management with fallback allocation and robust cleanup. - Adjusted SEADER_UART_RX_BUF_SIZE to 300 for better headroom. - Added safeguards against frame/header underflows in scratchpad handling. - Ensured proper alignment for UART worker and zero-copy transmission paths.
This commit is contained in:
5 files changed
+92
-18
No files matched your search
@@ -158,16 +158,35 @@ void seader_ccid_XfrBlockToSlot(
|
||||
uint8_t slot,
|
||||
uint8_t* data,
|
||||
size_t len) {
|
||||
bool in_scratchpad = (data >= seader_uart->tx_buf && data < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE);
|
||||
uint8_t header_len = 2 + 10;
|
||||
if(len > ((size_t)SEADER_UART_RX_BUF_SIZE - header_len)) {
|
||||
FURI_LOG_E(TAG, "CCID frame too long: %d", (int)(header_len + len));
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t tx_start = (uintptr_t)seader_uart->tx_buf;
|
||||
uintptr_t tx_end = tx_start + SEADER_UART_RX_BUF_SIZE;
|
||||
uintptr_t data_addr = (uintptr_t)data;
|
||||
bool in_scratchpad = false;
|
||||
if(data_addr >= tx_start + header_len && data_addr <= tx_end) {
|
||||
size_t available = (size_t)(tx_end - data_addr);
|
||||
in_scratchpad = len <= available;
|
||||
}
|
||||
uint8_t* frame;
|
||||
|
||||
if(in_scratchpad) {
|
||||
frame = data - header_len;
|
||||
seader_uart->tx_len = header_len + len;
|
||||
// Shift frame to start of tx_buf for UART worker
|
||||
if(frame != seader_uart->tx_buf) {
|
||||
memmove(seader_uart->tx_buf, frame, seader_uart->tx_len);
|
||||
frame = seader_uart->tx_buf;
|
||||
}
|
||||
} else {
|
||||
frame = seader_uart->tx_buf;
|
||||
memset(frame, 0, header_len);
|
||||
memcpy(frame + header_len, data, len);
|
||||
seader_uart->tx_len = header_len + len;
|
||||
}
|
||||
|
||||
frame[0] = SYNC;
|
||||
@@ -183,7 +202,6 @@ void seader_ccid_XfrBlockToSlot(
|
||||
frame[2 + 8] = 0;
|
||||
frame[2 + 9] = 0;
|
||||
|
||||
seader_uart->tx_len = header_len + len;
|
||||
seader_uart->tx_len = seader_add_lrc(frame, seader_uart->tx_len);
|
||||
|
||||
/*
|
||||
|
||||
@@ -185,16 +185,28 @@ bool seader_send_apdu(
|
||||
bool extended = seader_uart->T == 1;
|
||||
uint8_t header_len = extended ? 7 : 5;
|
||||
|
||||
if(header_len + payloadLen > SEADER_UART_RX_BUF_SIZE) {
|
||||
// Must account for MAX_FRAME_HEADERS headroom in scratchpad mode
|
||||
if(MAX_FRAME_HEADERS + header_len + payloadLen > SEADER_UART_RX_BUF_SIZE) {
|
||||
FURI_LOG_E(TAG, "Cannot send message, too long: %d", header_len + payloadLen);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t length = header_len + payloadLen;
|
||||
uint8_t* apdu;
|
||||
bool must_free = false;
|
||||
uintptr_t tx_start = (uintptr_t)seader_uart->tx_buf;
|
||||
uintptr_t tx_end = tx_start + SEADER_UART_RX_BUF_SIZE;
|
||||
uintptr_t payload_addr = (uintptr_t)payload;
|
||||
bool scratchpad_payload = false;
|
||||
|
||||
if(in_scratchpad) {
|
||||
apdu = payload - header_len;
|
||||
// in_scratchpad is only valid when the full payload range is inside tx_buf.
|
||||
if(in_scratchpad && payload_addr >= tx_start + header_len && payload_addr <= tx_end) {
|
||||
size_t available = (size_t)(tx_end - payload_addr);
|
||||
scratchpad_payload = payloadLen <= available;
|
||||
}
|
||||
|
||||
if(scratchpad_payload) {
|
||||
apdu = (uint8_t*)(payload_addr - header_len);
|
||||
} else {
|
||||
apdu = malloc(length);
|
||||
if(!apdu) {
|
||||
@@ -202,6 +214,7 @@ bool seader_send_apdu(
|
||||
return false;
|
||||
}
|
||||
memcpy(apdu + header_len, payload, payloadLen);
|
||||
must_free = true;
|
||||
}
|
||||
|
||||
apdu[0] = CLA;
|
||||
@@ -225,7 +238,7 @@ bool seader_send_apdu(
|
||||
seader_ccid_XfrBlock(seader_uart, apdu, length);
|
||||
}
|
||||
|
||||
if(!in_scratchpad) {
|
||||
if(must_free) {
|
||||
free(apdu);
|
||||
}
|
||||
|
||||
@@ -257,9 +270,41 @@ void seader_send_payload(
|
||||
|
||||
uint8_t* scratchpad = seader_uart->tx_buf + MAX_FRAME_HEADERS;
|
||||
size_t scratchpad_size = SEADER_UART_RX_BUF_SIZE - MAX_FRAME_HEADERS;
|
||||
size_t max_der_len = UINT8_MAX - ASN1_PREFIX;
|
||||
uint8_t* payload_buf = scratchpad;
|
||||
bool payload_in_scratchpad = true;
|
||||
|
||||
asn_enc_rval_t er =
|
||||
der_encode_to_buffer(&asn_DEF_Payload, payload, scratchpad + ASN1_PREFIX, scratchpad_size - ASN1_PREFIX);
|
||||
der_encode_to_buffer(
|
||||
&asn_DEF_Payload, payload, scratchpad + ASN1_PREFIX, scratchpad_size - ASN1_PREFIX);
|
||||
|
||||
if(er.encoded < 0 || ((size_t)er.encoded + ASN1_PREFIX) > UINT8_MAX) {
|
||||
payload_buf = malloc(ASN1_PREFIX + max_der_len);
|
||||
if(!payload_buf) {
|
||||
FURI_LOG_E(TAG, "Failed to allocate DER fallback buffer");
|
||||
return;
|
||||
}
|
||||
payload_in_scratchpad = false;
|
||||
|
||||
er = der_encode_to_buffer(&asn_DEF_Payload, payload, payload_buf + ASN1_PREFIX, max_der_len);
|
||||
}
|
||||
|
||||
if(er.encoded < 0) {
|
||||
FURI_LOG_E(TAG, "Failed to encode payload");
|
||||
if(!payload_in_scratchpad) {
|
||||
free(payload_buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
size_t apdu_payload_len = ASN1_PREFIX + (size_t)er.encoded;
|
||||
if(apdu_payload_len > UINT8_MAX) {
|
||||
FURI_LOG_E(TAG, "Encoded payload too large for APDU: %d", (int)apdu_payload_len);
|
||||
if(!payload_in_scratchpad) {
|
||||
free(payload_buf);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ASN1_DEBUG
|
||||
if(er.encoded > -1) {
|
||||
@@ -277,14 +322,26 @@ void seader_send_payload(
|
||||
#endif
|
||||
//0xa0, 0xda, 0x02, 0x63, 0x00, 0x00, 0x0a,
|
||||
//0x44, 0x0a, 0x44, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x96, 0x00
|
||||
scratchpad[0] = from;
|
||||
scratchpad[1] = to;
|
||||
scratchpad[2] = replyTo;
|
||||
scratchpad[3] = 0x00;
|
||||
scratchpad[4] = 0x00;
|
||||
scratchpad[5] = 0x00;
|
||||
payload_buf[0] = from;
|
||||
payload_buf[1] = to;
|
||||
payload_buf[2] = replyTo;
|
||||
payload_buf[3] = 0x00;
|
||||
payload_buf[4] = 0x00;
|
||||
payload_buf[5] = 0x00;
|
||||
|
||||
seader_send_apdu(seader, 0xA0, 0xDA, 0x02, 0x63, scratchpad, 6 + er.encoded, true);
|
||||
seader_send_apdu(
|
||||
seader,
|
||||
0xA0,
|
||||
0xDA,
|
||||
0x02,
|
||||
0x63,
|
||||
payload_buf,
|
||||
(uint8_t)apdu_payload_len,
|
||||
payload_in_scratchpad);
|
||||
|
||||
if(!payload_in_scratchpad) {
|
||||
free(payload_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void seader_send_process_config_card(Seader* seader) {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
#include <furi_hal.h>
|
||||
|
||||
// https://ww1.microchip.com/downloads/en/DeviceDoc/00001561C.pdf
|
||||
#define SEADER_UART_RX_BUF_SIZE (261)
|
||||
#define SEADER_UART_RX_BUF_SIZE (300)
|
||||
|
||||
typedef struct {
|
||||
uint8_t uart_ch;
|
||||
|
||||
@@ -125,7 +125,8 @@ void seader_send_t1_scratchpad(SeaderUartBridge* seader_uart, uint8_t PCB, uint8
|
||||
void seader_send_t1(SeaderUartBridge* seader_uart, uint8_t* apdu, size_t len) {
|
||||
uint8_t ifsc = seader_uart->IFSC;
|
||||
|
||||
bool in_scratchpad = (apdu >= seader_uart->tx_buf && apdu < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE);
|
||||
bool in_scratchpad = (apdu >= seader_uart->tx_buf + 3 &&
|
||||
apdu < seader_uart->tx_buf + SEADER_UART_RX_BUF_SIZE);
|
||||
|
||||
if(len > ifsc) {
|
||||
if(seader_t_1_tx_buffer == NULL) {
|
||||
|
||||
Reference in new issue
Block a user