process: remove push_in_message_ex
What changed, and why it matters
This commit is a routine code cleanup in Blockstream Jade's QR message handling. It removes a helper function that added an extra memory allocation and copy, and instead lets callers reserve a leading byte directly when allocating the buffer. There is no indication this fixes a security bug; it appears to be an efficiency and consistency improvement.
No security action required; treat as normal maintenance/refactor. Standard code review and regression testing for QR-mode message ingestion are sufficient.
Security signals we found
No security-relevant keywords in commit title or message
No bounds-checking or validation changes
No privilege, authentication, or cryptographic changes
Refactor only: function removal and offset-based buffer pre-allocation
Evidence from the diff
The patch removes jade_process_push_in_message_ex() from main/process.c/process.h. That helper prefixed a one-byte message-source tag by allocating a new buffer, copying data, pushing it, then freeing it. Callers in main/qrmode.c now pre-allocate one extra byte at the start of their CBOR buffers and set it to the source tag before calling jade_process_push_in_message(). bcur_scan_qr() gains an offset parameter so the scanned QR payload can also be allocated with a leading byte already reserved, avoiding the extra copy in scan_qr_post_in_message(). Other callers of bcur_scan_qr() pass offset = 0. The change is a refactor to reduce heap allocations/copies in QR-mode input processing.
Changed components
main/process.cmain/process.hmain/qrmode.cmain/bcur.cmain/bcur.hmain/process/dashboard.cInspect captured patch +37 / −55
diff --git a/main/bcur.c b/main/bcur.c
index 434bfeb..0044fd9 100644
--- a/main/bcur.c
+++ b/main/bcur.c
@@ -658,16 +658,8 @@ static bool collect_any_bcur(qr_data_t* qr_data)
return decoded;
}
-// Scan a QR code that may be a BC-UR code/fragment - ie. single-frame or animated/multi-frame.
-// Returns true if a complete (ie. potentially multi-frame) bc-ur code is scanned, or if a single
-// non-BC-UR frame is scanned successfully.
-// If BC-UR, the complete scanned payload and its BC-UR 'type' are returned.
-// NOTE: output is expected to be a valid CBOR message, although this is not validated.
-// If not BC-UR, the scanned payload is returned with a type of NULL.
-// In either case the caller takes ownership, and must free the output data bytes and any type string.
-// Returns false if scanning fails or is abandoned - in which case there is nothing to free.
-bool bcur_scan_qr(
- const char* prompt_text, char** output_type, uint8_t** output, size_t* output_len, const char* help_url)
+bool bcur_scan_qr(const char* prompt_text, char** output_type, uint8_t** output, size_t* output_len, size_t offset,
+ const char* help_url)
{
// prompt_text is optional
JADE_INIT_OUT_PPTR(output_type);
@@ -698,17 +690,17 @@ bool bcur_scan_qr(
JADE_ASSERT(result_type);
// Copy payload and bc-ur type
- *output = JADE_MALLOC_PREFER_SPIRAM(result_len);
- memcpy(*output, result, result_len);
- *output_len = result_len;
+ *output = JADE_MALLOC_PREFER_SPIRAM(result_len + offset);
+ memcpy(*output + offset, result, result_len);
+ *output_len = result_len + offset;
*output_type = strdup(result_type);
} else {
// Not a bc-ur code - copy straight payload and append a nul-terminator.
// Leave bc-ur type as NULL to indicate data was not a bc-ur payload.
- *output = JADE_MALLOC(qr_data.len + 1);
- memcpy(*output, qr_data.data, qr_data.len);
- (*output)[qr_data.len] = '\0';
- *output_len = qr_data.len;
+ *output = JADE_MALLOC(qr_data.len + offset + 1);
+ memcpy(*output + offset, qr_data.data, qr_data.len);
+ (*output)[qr_data.len + offset] = '\0';
+ *output_len = qr_data.len + offset;
*output_type = NULL;
}
diff --git a/main/bcur.h b/main/bcur.h
index a4e6845..742b0e9 100644
--- a/main/bcur.h
+++ b/main/bcur.h
@@ -43,12 +43,13 @@ bool bcur_build_cbor_crypto_psbt(const struct wally_psbt* psbt, uint8_t** output
// Returns true if a complete (ie. potentially multi-frame) bc-ur code is scanned, or if a single
// non-BC-UR frame is scanned successfully.
// If BC-UR, the complete scanned payload and its BC-UR 'type' are returned.
+// If offset is non-zero, extra bytes are allocated and the result is offset.
// NOTE: output is expected to be a valid CBOR message, although this is not validated.
// If not BC-UR, the scanned payload is returned with a type of NULL.
// In either case the caller takes ownership, and must free the output data bytes and any type string.
// Returns false if scanning fails or is abandoned - in which case there is nothing to free.
-bool bcur_scan_qr(
- const char* prompt_text, char** output_type, uint8_t** output, size_t* output_len, const char* help_url);
+bool bcur_scan_qr(const char* prompt_text, char** output_type, uint8_t** output, size_t* output_len, size_t offset,
+ const char* help_url);
// Encodes the passed payload into a set of one or more BC-UR fragments with the given 'type'.
// These are then rendered as a set of QR codes of the passed version/size.
diff --git a/main/process.c b/main/process.c
index 5ee05e1..1e87d27 100644
--- a/main/process.c
+++ b/main/process.c
@@ -270,20 +270,6 @@ bool jade_process_push_in_message(const uint8_t* data, const size_t size)
return true;
}
-bool jade_process_push_in_message_ex(const uint8_t* data, const size_t size, const jade_msg_source_t source)
-{
- JADE_ASSERT(data);
- JADE_ASSERT(size);
- // Post as message into Jade with msg-source prefix
- const size_t fullsize = size + 1;
- uint8_t* const fullmsg = JADE_MALLOC(fullsize);
- fullmsg[0] = source;
- memcpy(fullmsg + 1, data, size);
- const bool ret = jade_process_push_in_message(fullmsg, fullsize);
- free(fullmsg);
- return ret;
-}
-
void jade_process_push_out_message(const uint8_t* data, const size_t size, const jade_msg_source_t source)
{
#if defined(CONFIG_FREERTOS_UNICORE) && defined(CONFIG_ETH_USE_OPENETH)
diff --git a/main/process.h b/main/process.h
index 35bf8d4..922849c 100644
--- a/main/process.h
+++ b/main/process.h
@@ -84,7 +84,6 @@ void jade_process_free_current_message(jade_process_t* process);
// Push messages to/from a process
bool jade_process_push_in_message(const uint8_t* data, size_t size);
-bool jade_process_push_in_message_ex(const uint8_t* data, size_t size, jade_msg_source_t source);
void jade_process_push_out_message(const uint8_t* data, size_t length, jade_msg_source_t source);
// Send message replies
diff --git a/main/process/dashboard.c b/main/process/dashboard.c
index 6464a72..f68964a 100644
--- a/main/process/dashboard.c
+++ b/main/process/dashboard.c
@@ -1945,7 +1945,7 @@ static void handle_pinserver_scan(void)
char* type;
uint8_t* data = NULL;
size_t data_len = 0;
- if (!bcur_scan_qr(NULL, &type, &data, &data_len, "blkstrm.com/oracle")) {
+ if (!bcur_scan_qr(NULL, &type, &data, &data_len, 0, "blkstrm.com/oracle")) {
// Scan aborted
JADE_ASSERT(!type);
JADE_ASSERT(!data);
diff --git a/main/qrmode.c b/main/qrmode.c
index aa5cb97..971f217 100644
--- a/main/qrmode.c
+++ b/main/qrmode.c
@@ -1290,7 +1290,7 @@ void handle_scan_qr(void)
char* type = NULL;
uint8_t* data = NULL;
size_t data_len = 0;
- if (!bcur_scan_qr(NULL, &type, &data, &data_len, "blkstrm.com/jadescan") || !data) {
+ if (!bcur_scan_qr(NULL, &type, &data, &data_len, 0, "blkstrm.com/jadescan") || !data) {
// Scan aborted
JADE_ASSERT(!type);
JADE_ASSERT(!data);
@@ -1628,9 +1628,9 @@ bool await_qr_back_continue_activity(
// Create and post a 'cancel' message
static bool post_cancel_message(const jade_msg_source_t source)
{
- uint8_t cbor_buf[32];
+ uint8_t cbor_buf[32 + 1];
CborEncoder root_encoder;
- cbor_encoder_init(&root_encoder, cbor_buf, sizeof(cbor_buf), 0);
+ cbor_encoder_init(&root_encoder, cbor_buf + 1, sizeof(cbor_buf) - 1, 0);
CborEncoder root_map_encoder; // id, method
CborError cberr = cbor_encoder_create_map(&root_encoder, &root_map_encoder, 2);
@@ -1640,16 +1640,17 @@ static bool post_cancel_message(const jade_msg_source_t source)
cberr = cbor_encoder_close_container(&root_encoder, &root_map_encoder);
JADE_ASSERT(cberr == CborNoError);
- const size_t cbor_len = cbor_encoder_get_buffer_size(&root_encoder, cbor_buf);
- return jade_process_push_in_message_ex(cbor_buf, cbor_len, source);
+ const size_t cbor_len = cbor_encoder_get_buffer_size(&root_encoder, cbor_buf + 1);
+ cbor_buf[0] = source;
+ return jade_process_push_in_message(cbor_buf, cbor_len + 1);
}
// Locally create and post an 'auth_user' request
static bool post_auth_msg_request(const jade_msg_source_t source, const bool suppress_pin_change_confirmation)
{
- uint8_t cbor_buf[96];
+ uint8_t cbor_buf[96 + 1];
CborEncoder root_encoder;
- cbor_encoder_init(&root_encoder, cbor_buf, sizeof(cbor_buf), 0);
+ cbor_encoder_init(&root_encoder, cbor_buf + 1, sizeof(cbor_buf) - 1, 0);
CborEncoder root_map_encoder; // id, method, params
CborError cberr = cbor_encoder_create_map(&root_encoder, &root_map_encoder, 3);
@@ -1679,8 +1680,9 @@ static bool post_auth_msg_request(const jade_msg_source_t source, const bool sup
cberr = cbor_encoder_close_container(&root_encoder, &root_map_encoder);
JADE_ASSERT(cberr == CborNoError);
- const size_t cbor_len = cbor_encoder_get_buffer_size(&root_encoder, cbor_buf);
- return jade_process_push_in_message_ex(cbor_buf, cbor_len, source);
+ const size_t cbor_len = cbor_encoder_get_buffer_size(&root_encoder, cbor_buf + 1);
+ cbor_buf[0] = source;
+ return jade_process_push_in_message(cbor_buf, cbor_len + 1);
}
// Scan a bcur QR code, and post it into Jade with SOURCE_INTERNAL
@@ -1689,19 +1691,20 @@ static bool scan_qr_post_in_message(const char* label, const char* expected_type
JADE_ASSERT(label);
JADE_ASSERT(expected_type);
- char* output_type = NULL;
- uint8_t* output = NULL;
- size_t output_len = 0;
+ char* type = NULL;
+ uint8_t* data = NULL;
+ size_t data_len = 0;
bool ret = false;
- // NOTE: we take ownership of 'output_type' and 'output'
- if (!bcur_scan_qr(label, &output_type, &output, &output_len, "blkstrm.com/qrpin")) {
+ // NOTE: we take ownership of 'type' and 'data'
+ const uint32_t offset = 1; // Allow for a prefix message source byte
+ if (!bcur_scan_qr(label, &type, &data, &data_len, offset, "blkstrm.com/qrpin")) {
JADE_LOGI("QR scanning failed or abandoned");
return false;
}
// Check if a non-bc-ur code frame was scanned
- if (!output_type) {
+ if (!type) {
JADE_LOGW("Scanning encountered a non-BC-UR QR code, when expecting BC-UR type %s", expected_type);
const char* message[] = { "Unexpected QR payload" };
await_error_activity(message, 1);
@@ -1709,19 +1712,20 @@ static bool scan_qr_post_in_message(const char* label, const char* expected_type
}
// Check the type is as expected
- if (strcasecmp(expected_type, output_type)) {
- JADE_LOGW("Scanning returned unexpected type %s when expecting %s", output_type, expected_type);
+ if (strcasecmp(expected_type, type)) {
+ JADE_LOGW("Scanning returned unexpected type %s when expecting %s", type, expected_type);
const char* message[] = { "Unexpected QR payload type" };
await_error_activity(message, 1);
goto cleanup;
}
// Post as message into Jade with source-qr prefix
- ret = jade_process_push_in_message_ex(output, output_len, SOURCE_INTERNAL);
+ data[0] = SOURCE_INTERNAL;
+ ret = jade_process_push_in_message(data, data_len);
cleanup:
- free(output);
- free(output_type);
+ free(data);
+ free(type);
return ret;
}
Why this scored 11/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.