Skip to content

Commit be5e4f0

Browse files
Merge #1779: Add ARG_CHECKs to ensure "array of pointers" elements are non-NULL
8bcda18 test: Add non-NULL checks for "pointer of array" API functions (Sebastian Falbesoner) 5a08c1b Add ARG_CHECKs to ensure "array of pointers" elements are non-NULL (Sebastian Falbesoner) Pull request description: We currently have five public API functions that take an "array of pointers" as input parameter: * `secp256k1_ec_pubkey_combine` (`ins`: array of pointers to public keys to add) * `secp256k1_ec_pubkey_sort` (`pubkeys`: array of pointers to public keys to sort) * `secp256k1_musig_pubkey_agg` (`pubkeys`: array of pointers to public keys to aggregate) * `secp256k1_musig_nonce_agg` (`pubnonces`: array of pointers to public nonces to aggregate) * `secp256k1_musig_partial_sig_agg` (`partial_sigs`: array of pointers to partial signatures to aggregate) Out of these, only `_ec_pubkey_combine` verifies that the individual pointer elements in the array are non-NULL each: https://github.com/bitcoin-core/secp256k1/blob/e7f7083b530a55c83ce9089a7244d2d9d67ac8b2/src/secp256k1.c#L774-L775 This PR adds corresponding `ARG_CHECKS` for the other API functions as well, in order to avoid running into potential UB due to NULL pointer dereference. It seems to me that the tiny run-time overhead is worth it doing this for consistency and to help users in case the arrays are set up incorrectly (I'm thinking e.g. of language binding writers where getting this right might be a bit more involved). Looking into this was motivated by a [review of furszy](#1765 (comment)) (thanks!), who pointed out that the non-NULL checks are missing in at least one API function in the silentpayments module PR as well. Happy to add some `CHECK_ILLEGAL` tests if there is conceptual support for this PR. ACKs for top commit: kevkevinpal: utACK [8bcda18](8bcda18) john-moffett: utACK 8bcda18 real-or-random: utACK 8bcda18 w0xlt: ACK 8bcda18 Tree-SHA512: 24acd6606526e3acb994e3361fde15771aa6706a6f3e7a6ae70b9a9ddb81ac1eedaac2025a027b890cecf98dab20dc378b94edde6c726888c44b9d35b7581ee1
2 parents e7f7083 + 8bcda18 commit be5e4f0

File tree

5 files changed

+54
-0
lines changed

5 files changed

+54
-0
lines changed

src/modules/musig/keyagg_impl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_xonly_pub
177177
}
178178
ARG_CHECK(pubkeys != NULL);
179179
ARG_CHECK(n_pubkeys > 0);
180+
for (i = 0; i < n_pubkeys; i++) {
181+
ARG_CHECK(pubkeys[i] != NULL);
182+
}
180183

181184
ecmult_data.ctx = ctx;
182185
ecmult_data.pks = pubkeys;

src/modules/musig/session_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,10 +521,15 @@ static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1
521521
int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggnonce *aggnonce, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) {
522522
secp256k1_gej aggnonce_ptsj[2];
523523
secp256k1_ge aggnonce_pts[2];
524+
size_t i;
525+
524526
VERIFY_CHECK(ctx != NULL);
525527
ARG_CHECK(aggnonce != NULL);
526528
ARG_CHECK(pubnonces != NULL);
527529
ARG_CHECK(n_pubnonces > 0);
530+
for (i = 0; i < n_pubnonces; i++) {
531+
ARG_CHECK(pubnonces[i] != NULL);
532+
}
528533

529534
if (!secp256k1_musig_sum_pubnonces(ctx, aggnonce_ptsj, pubnonces, n_pubnonces)) {
530535
return 0;
@@ -782,6 +787,9 @@ int secp256k1_musig_partial_sig_agg(const secp256k1_context* ctx, unsigned char
782787
ARG_CHECK(session != NULL);
783788
ARG_CHECK(partial_sigs != NULL);
784789
ARG_CHECK(n_sigs > 0);
790+
for (i = 0; i < n_sigs; i++) {
791+
ARG_CHECK(partial_sigs[i] != NULL);
792+
}
785793

786794
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
787795
return 0;

src/modules/musig/tests_impl.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ static void musig_api_tests(void) {
201201
CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1);
202202
CHECK(secp256k1_musig_pubkey_agg(CTX, NULL, &keyagg_cache, pk_ptr, 2) == 1);
203203
CHECK(secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2) == 1);
204+
/* check that NULL in array of public key pointers is not allowed */
205+
for (i = 0; i < 2; i++) {
206+
const secp256k1_pubkey *original_ptr = pk_ptr[i];
207+
pk_ptr[i] = NULL;
208+
CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, NULL, pk_ptr, 2));
209+
pk_ptr[i] = original_ptr;
210+
}
204211
CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, NULL, 2));
205212
CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0);
206213
CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2));
@@ -350,6 +357,13 @@ static void musig_api_tests(void) {
350357

351358
/** Receive nonces and aggregate **/
352359
CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1);
360+
/* check that NULL in array of public nonce pointers is not allowed */
361+
for (i = 0; i < 2; i++) {
362+
const secp256k1_musig_pubnonce *original_ptr = pubnonce_ptr[i];
363+
pubnonce_ptr[i] = NULL;
364+
CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2));
365+
pubnonce_ptr[i] = original_ptr;
366+
}
353367
CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2));
354368
CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2));
355369
CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0));
@@ -474,6 +488,13 @@ static void musig_api_tests(void) {
474488

475489
/** Signature aggregation and verification */
476490
CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1);
491+
/* check that NULL in array of partial signature pointers is not allowed */
492+
for (i = 0; i < 2; i++) {
493+
const secp256k1_musig_partial_sig *original_ptr = partial_sig_ptr[i];
494+
partial_sig_ptr[i] = NULL;
495+
CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2));
496+
partial_sig_ptr[i] = original_ptr;
497+
}
477498
CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2));
478499
CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2));
479500
CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2));

src/secp256k1.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,13 @@ static int secp256k1_ec_pubkey_sort_cmp(const void* pk1, const void* pk2, void *
325325
}
326326

327327
int secp256k1_ec_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) {
328+
size_t i;
329+
328330
VERIFY_CHECK(ctx != NULL);
329331
ARG_CHECK(pubkeys != NULL);
332+
for (i = 0; i < n_pubkeys; i++) {
333+
ARG_CHECK(pubkeys[i] != NULL);
334+
}
330335

331336
/* Suppress wrong warning (fixed in MSVC 19.33) */
332337
#if defined(_MSC_VER) && (_MSC_VER < 1933)

src/tests.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6052,6 +6052,7 @@ static void run_eckey_edge_case_test(void) {
60526052
secp256k1_pubkey pubkey_negone;
60536053
const secp256k1_pubkey *pubkeys[3];
60546054
size_t len;
6055+
int i;
60556056
/* Group order is too large, reject. */
60566057
CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0);
60576058
SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey));
@@ -6245,6 +6246,14 @@ static void run_eckey_edge_case_test(void) {
62456246
CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1);
62466247
SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey));
62476248
CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0);
6249+
/* check that NULL in array of pubkey pointers is not allowed */
6250+
for (i = 0; i < 3; i++) {
6251+
const secp256k1_pubkey *original_ptr = pubkeys[i];
6252+
secp256k1_pubkey result;
6253+
pubkeys[i] = NULL;
6254+
CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &result, pubkeys, 3));
6255+
pubkeys[i] = original_ptr;
6256+
}
62486257
len = 33;
62496258
CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
62506259
CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1);
@@ -6640,6 +6649,7 @@ static void permute(size_t *arr, size_t n) {
66406649
static void test_sort_api(void) {
66416650
secp256k1_pubkey pks[2];
66426651
const secp256k1_pubkey *pks_ptr[2];
6652+
int i;
66436653

66446654
pks_ptr[0] = &pks[0];
66456655
pks_ptr[1] = &pks[1];
@@ -6648,6 +6658,13 @@ static void test_sort_api(void) {
66486658
testutil_random_pubkey_test(&pks[1]);
66496659

66506660
CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2) == 1);
6661+
/* check that NULL in array of public key pointers is not allowed */
6662+
for (i = 0; i < 2; i++) {
6663+
const secp256k1_pubkey *original_ptr = pks_ptr[i];
6664+
pks_ptr[i] = NULL;
6665+
CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, pks_ptr, 2));
6666+
pks_ptr[i] = original_ptr;
6667+
}
66516668
CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_sort(CTX, NULL, 2));
66526669
CHECK(secp256k1_ec_pubkey_sort(CTX, pks_ptr, 0) == 1);
66536670
/* Test illegal public keys */

0 commit comments

Comments
 (0)