Skip to content

Commit 4b6df5e

Browse files
contexts: Forbid cloning/destroying secp256k1_context_static
1 parent b1579cf commit 4b6df5e

File tree

5 files changed

+88
-24
lines changed

5 files changed

+88
-24
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
#### Changed
11+
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
12+
1013
## [0.2.0] - 2022-12-12
1114

1215
#### Added

include/secp256k1.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -291,8 +291,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
291291
* called at most once for every call of this function. If you need to avoid dynamic
292292
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
293293
*
294+
* Cloning secp256k1_context_static is not possible, and should not be emulated by
295+
* the caller (e.g., using memcpy). Create a new context instead.
296+
*
294297
* Returns: a newly created context object.
295-
* Args: ctx: an existing context to copy
298+
* Args: ctx: an existing context to copy (not secp256k1_context_static)
296299
*/
297300
SECP256K1_API secp256k1_context* secp256k1_context_clone(
298301
const secp256k1_context* ctx
@@ -310,6 +313,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
310313
*
311314
* Args: ctx: an existing context to destroy, constructed using
312315
* secp256k1_context_create or secp256k1_context_clone
316+
* (i.e., not secp256k1_context_static).
313317
*/
314318
SECP256K1_API void secp256k1_context_destroy(
315319
secp256k1_context* ctx

include/secp256k1_preallocated.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,11 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
8888
* the lifetime of this context object, see the description of
8989
* secp256k1_context_preallocated_create for details.
9090
*
91+
* Cloning secp256k1_context_static is not possible, and should not be emulated by
92+
* the caller (e.g., using memcpy). Create a new context instead.
93+
*
9194
* Returns: a newly created context object.
92-
* Args: ctx: an existing context to copy.
95+
* Args: ctx: an existing context to copy (not secp256k1_context_static).
9396
* In: prealloc: a pointer to a rewritable contiguous block of memory of
9497
* size at least secp256k1_context_preallocated_size(flags)
9598
* bytes, as detailed above.
@@ -117,7 +120,8 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
117120
*
118121
* Args: ctx: an existing context to destroy, constructed using
119122
* secp256k1_context_preallocated_create or
120-
* secp256k1_context_preallocated_clone.
123+
* secp256k1_context_preallocated_clone
124+
* (i.e., not secp256k1_context_static).
121125
*/
122126
SECP256K1_API void secp256k1_context_preallocated_destroy(
123127
secp256k1_context* ctx

src/secp256k1.c

+20-8
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ size_t secp256k1_context_preallocated_size(unsigned int flags) {
109109
}
110110

111111
size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) {
112-
size_t ret = sizeof(secp256k1_context);
113112
VERIFY_CHECK(ctx != NULL);
114-
return ret;
113+
ARG_CHECK(secp256k1_context_is_proper(ctx));
114+
return sizeof(secp256k1_context);
115115
}
116116

117117
secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) {
@@ -152,6 +152,7 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context*
152152
secp256k1_context* ret;
153153
VERIFY_CHECK(ctx != NULL);
154154
ARG_CHECK(prealloc != NULL);
155+
ARG_CHECK(secp256k1_context_is_proper(ctx));
155156

156157
ret = (secp256k1_context*)prealloc;
157158
*ret = *ctx;
@@ -163,24 +164,35 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
163164
size_t prealloc_size;
164165

165166
VERIFY_CHECK(ctx != NULL);
167+
ARG_CHECK(secp256k1_context_is_proper(ctx));
168+
166169
prealloc_size = secp256k1_context_preallocated_clone_size(ctx);
167170
ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size);
168171
ret = secp256k1_context_preallocated_clone(ctx, ret);
169172
return ret;
170173
}
171174

172175
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
173-
ARG_CHECK_VOID(ctx != secp256k1_context_static);
174-
if (ctx != NULL) {
175-
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
176+
ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
177+
178+
/* Defined as noop */
179+
if (ctx == NULL) {
180+
return;
176181
}
182+
183+
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
177184
}
178185

179186
void secp256k1_context_destroy(secp256k1_context* ctx) {
180-
if (ctx != NULL) {
181-
secp256k1_context_preallocated_destroy(ctx);
182-
free(ctx);
187+
ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
188+
189+
/* Defined as noop */
190+
if (ctx == NULL) {
191+
return;
183192
}
193+
194+
secp256k1_context_preallocated_destroy(ctx);
195+
free(ctx);
184196
}
185197

186198
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {

src/tests.c

+54-13
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ static int COUNT = 64;
3232
static secp256k1_context *CTX = NULL;
3333
static secp256k1_context *STATIC_CTX = NULL;
3434

35+
static int all_bytes_equal(const void* s, unsigned char value, size_t n) {
36+
const unsigned char *p = s;
37+
size_t i;
38+
39+
for (i = 0; i < n; i++) {
40+
if (p[i] != value) {
41+
return 0;
42+
}
43+
}
44+
return 1;
45+
}
46+
3547
static void counting_illegal_callback_fn(const char* str, void* data) {
3648
/* Dummy callback function that just counts. */
3749
int32_t *p;
@@ -229,20 +241,47 @@ static void run_ec_illegal_argument_tests(void) {
229241
secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
230242
}
231243

232-
static void run_static_context_tests(void) {
233-
int32_t dummy = 0;
234-
244+
static void run_static_context_tests(int use_prealloc) {
235245
/* Check that deprecated secp256k1_context_no_precomp is an alias to secp256k1_context_static. */
236246
CHECK(secp256k1_context_no_precomp == secp256k1_context_static);
237247

238-
/* check if sizes for cloning are consistent */
239-
CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) >= sizeof(secp256k1_context));
248+
{
249+
int ecount = 0;
250+
secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
251+
/* Destroying or cloning secp256k1_context_static is not supported. */
252+
if (use_prealloc) {
253+
CHECK(secp256k1_context_preallocated_clone_size(STATIC_CTX) == 0);
254+
CHECK(ecount == 1);
255+
{
256+
secp256k1_context *my_static_ctx = malloc(sizeof(*STATIC_CTX));
257+
CHECK(my_static_ctx != NULL);
258+
memset(my_static_ctx, 0x2a, sizeof(*my_static_ctx));
259+
CHECK(secp256k1_context_preallocated_clone(STATIC_CTX, my_static_ctx) == NULL);
260+
CHECK(all_bytes_equal(my_static_ctx, 0x2a, sizeof(*my_static_ctx)));
261+
CHECK(ecount == 2);
262+
free(my_static_ctx);
263+
}
264+
secp256k1_context_preallocated_destroy(STATIC_CTX);
265+
CHECK(ecount == 3);
266+
} else {
267+
CHECK(secp256k1_context_clone(STATIC_CTX) == NULL);
268+
CHECK(ecount == 1);
269+
secp256k1_context_destroy(STATIC_CTX);
270+
CHECK(ecount == 2);
271+
}
272+
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
273+
}
240274

241-
/* Verify that setting and resetting illegal callback works */
242-
secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy);
243-
CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn);
244-
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
245-
CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
275+
{
276+
/* Verify that setting and resetting illegal callback works */
277+
int32_t dummy = 0;
278+
secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy);
279+
CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn);
280+
CHECK(STATIC_CTX->illegal_callback.data == &dummy);
281+
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
282+
CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
283+
CHECK(STATIC_CTX->illegal_callback.data == NULL);
284+
}
246285
}
247286

248287
static void run_proper_context_tests(int use_prealloc) {
@@ -300,8 +339,10 @@ static void run_proper_context_tests(int use_prealloc) {
300339
/* Verify that setting and resetting illegal callback works */
301340
secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy);
302341
CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn);
342+
CHECK(my_ctx->illegal_callback.data == &dummy);
303343
secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL);
304344
CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn);
345+
CHECK(my_ctx->illegal_callback.data == NULL);
305346

306347
/*** attempt to use them ***/
307348
random_scalar_order_test(&msg);
@@ -327,6 +368,7 @@ static void run_proper_context_tests(int use_prealloc) {
327368
} else {
328369
secp256k1_context_destroy(my_ctx);
329370
}
371+
330372
/* Defined as no-op. */
331373
secp256k1_context_destroy(NULL);
332374
secp256k1_context_preallocated_destroy(NULL);
@@ -7389,9 +7431,8 @@ int main(int argc, char **argv) {
73897431
run_selftest_tests();
73907432

73917433
/* context tests */
7392-
run_proper_context_tests(0);
7393-
run_proper_context_tests(1);
7394-
run_static_context_tests();
7434+
run_proper_context_tests(0); run_proper_context_tests(1);
7435+
run_static_context_tests(0); run_static_context_tests(1);
73957436
run_deprecated_context_flags_test();
73967437

73977438
/* scratch tests */

0 commit comments

Comments
 (0)