Add reactive tampering functionality to mock dispatcher
What changed, and why it matters
This commit only adds a new testing feature to the unit-test mock dispatcher. It lets test authors simulate a malicious client that tampers with protocol responses. It does not change the actual Ledger Bitcoin app code, does not introduce a real vulnerability, and is not a security fix. It is purely test infrastructure.
No action required. This is a legitimate test-infrastructure enhancement. Continue normal review.
Security signals we found
No production code changed
Change is confined to unit-tests/libs/mock_dispatcher.c and unit-tests/libs/mock_dispatcher.h
Added hook is explicitly documented as a test-only simulation of malicious client behavior
No vulnerability is fixed or introduced in the shipped app
Evidence from the diff
The diff adds a callback-based tamper hook to mock_dispatcher_t in the unit-test library. The hook is invoked in mock_process_interruption() after a response is built and before it is delivered to the caller, allowing tests to mutate response_buf/response_len or simulate a communication failure. New API: mock_dispatcher_set_tamper_hook(). No production firmware code is modified.
Changed components
unit-tests/libs/mock_dispatcher.cunit-tests/libs/mock_dispatcher.hInspect captured patch +50 / −0
diff --git a/unit-tests/libs/mock_dispatcher.c b/unit-tests/libs/mock_dispatcher.c
index ce7cd2b..7874274 100644
--- a/unit-tests/libs/mock_dispatcher.c
+++ b/unit-tests/libs/mock_dispatcher.c
@@ -403,6 +403,19 @@ static int mock_process_interruption(dispatcher_context_t *dc) {
return -1;
}
+ /* Call tamper hook if set */
+ if (m->tamper_hook != NULL) {
+ int tamper_rc = m->tamper_hook(m->response_buf,
+ &m->response_len,
+ cmd,
+ m->tamper_call_count,
+ m->tamper_user_data);
+ m->tamper_call_count++;
+ if (tamper_rc < 0) {
+ return -1;
+ }
+ }
+
/* Set read_buffer to point at the response */
dc->read_buffer = buffer_create(m->response_buf, m->response_len);
return 0;
diff --git a/unit-tests/libs/mock_dispatcher.h b/unit-tests/libs/mock_dispatcher.h
index b0e4315..f2b61b5 100644
--- a/unit-tests/libs/mock_dispatcher.h
+++ b/unit-tests/libs/mock_dispatcher.h
@@ -62,6 +62,25 @@ typedef struct {
size_t head; /* next to dequeue */
} mock_queue_t;
+/**
+ * Tamper hook signature.
+ * Called after a response is built but before it's delivered to the caller.
+ * Can modify response_buf/response_len to simulate malicious client behavior.
+ * Return 0 to deliver the (possibly modified) response normally.
+ * Return -1 to simulate a communication failure (process_interruption returns -1).
+ *
+ * @param response_buf The response buffer (writable).
+ * @param response_len Pointer to the response length (readable/writable).
+ * @param cmd The client command that produced this response.
+ * @param call_count How many times this hook has been called (0-indexed).
+ * @param user_data Opaque pointer set by the test.
+ */
+typedef int (*mock_tamper_hook_t)(uint8_t *response_buf,
+ size_t *response_len,
+ uint8_t cmd,
+ int call_count,
+ void *user_data);
+
/* ---- Main mock state ---- */
typedef struct {
dispatcher_context_t dc; /* MUST be first member (container_of pattern) */
@@ -96,6 +115,11 @@ typedef struct {
size_t len;
} yielded[MOCK_MAX_YIELDED];
size_t n_yielded;
+
+ /* Tamper hook (NULL = no tampering, behave honestly) */
+ mock_tamper_hook_t tamper_hook;
+ void *tamper_user_data;
+ int tamper_call_count;
} mock_dispatcher_t;
/* ---- Public API ---- */
@@ -112,6 +136,19 @@ void mock_dispatcher_init(mock_dispatcher_t *mock);
*/
void mock_dispatcher_add_preimage(mock_dispatcher_t *mock, const uint8_t *data, size_t len);
+/**
+ * Set a tamper hook to simulate malicious client behavior.
+ * The hook is called after each response is built, before delivery.
+ * Pass NULL to disable tampering.
+ */
+static inline void mock_dispatcher_set_tamper_hook(mock_dispatcher_t *mock,
+ mock_tamper_hook_t hook,
+ void *user_data) {
+ mock->tamper_hook = hook;
+ mock->tamper_user_data = user_data;
+ mock->tamper_call_count = 0;
+}
+
/**
* Build a Merkle tree from a list of elements and register it.
* Also registers each leaf preimage (0x00 || element) as a known preimage.
Why this scored 15/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.