-
Notifications
You must be signed in to change notification settings - Fork 275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fully describe safety requirements #561
Conversation
/// * The capabilities (`All`/`SignOnly`/`VerifyOnly`) of the context *must* match the flags | ||
/// passed to libsecp256k1 when generating the context. | ||
/// * The user must handle the freeing of the context (using the correct functions) by himself. | ||
/// * `raw_ctx` must point to writable memory (cannot be `ffi::secp256k1_context_no_precomp`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lifetime of raw_ctx
pointer must outlive 'buf
.
Non-safety warning: the returned value will not deallocate the pointer, nor destroy the context which may lead to memory leaks. The caller is responsible for these. Note that ManuallyDrop::drop
(or drop_in_place
) will only destroy the context, it will not free memory behind the pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the second point said that, I'll improve it to clarify. Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does but claiming it's safety is wrong and it might not be clear how to drop it properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 382206f:
nit: I'd add the words "in particular," before "cannot be", to clarify that any non-writeable memory is a problem, not just the static context.
src/context.rs
Outdated
/// * The capabilities (`All`/`SignOnly`/`VerifyOnly`) of the context *must* match the flags | ||
/// passed to libsecp256k1 when generating the context. | ||
/// * The user must handle the freeing of the context (using the correct functions) by himself. | ||
/// * `raw_ctx` must point to writable memory (cannot be `ffi::secp256k1_context_no_precomp`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lifetime of raw_ctx
pointer must outlive 'buf
.
Non-safety warning: the returned value will not deallocate the pointer, nor destroy the context which may lead to memory leaks. The caller is responsible for these. Note that ManuallyDrop::drop
(or drop_in_place
) will only destroy the context, it will not free memory behind the pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you trolling me with your cutnpasta? :) (I'm joking, thanks for making sure I don't only fix one instance of the docs)
src/context.rs
Outdated
/// * The capabilities (`All`/`SignOnly`/`VerifyOnly`) of the context *must* match the flags | ||
/// passed to libsecp256k1 when generating the context. | ||
/// * The user must handle the freeing of the context (using the correct functions) by himself. | ||
/// * `raw_ctx` must point to writable memory (cannot be `ffi::secp256k1_context_no_precomp`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lifetime of raw_ctx
pointer must outlive 'buf
.
Non-safety warning: the returned value will not deallocate the pointer, nor destroy the context which may lead to memory leaks. The caller is responsible for these. Note that ManuallyDrop::drop
(or drop_in_place
) will only destroy the context, it will not free memory behind the pointer.
src/context.rs
Outdated
/// | ||
/// This is highly unsafe due to the number of conditions that aren't checked, specifically: | ||
/// | ||
/// * `raw_ctx` needs to be a valid Secp256k1 context pointer that was generated by *exactly* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pointer being generated is kinda vague. Maybe something like this:
raw_ctx
must be a valid pointer (live, aligned...) to the memory that was initialized bysecp256k1_context_preallocated_create
(either called directly, or from this library by one of the context creation methods - all of them call it internally)
One issue with this is this promises we always call that function somehow and there won't be alternative initialization methods that are incompatible with this. I think this is reasonable assumption, right @apoelstra ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that seems like a reasonable assumption for the indefinite future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, thanks.
src/context.rs
Outdated
/// | ||
/// * `raw_ctx` needs to be a valid Secp256k1 context pointer that was generated by *exactly* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same pointer comment here
src/context.rs
Outdated
/// * `raw_ctx` needs to be a valid Secp256k1 context pointer that was generated by *exactly* | ||
/// the same code/version of the libsecp256k1 used here. | ||
/// * The capabilities (`All`/`SignOnly`/`VerifyOnly`) of the context *must* match the flags | ||
/// passed to libsecp256k1 when generating the context. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was written before we started fetching size from context during drop so it mandated exact flags. I think today it should be fine to require that at least the signing flag was supplied.
However to my knowledge secp256k1
asserts validity so it shouldn't lead to UB anyway? OTOH keeping it UB allows us more flexibility. But then wee should explain it's UB for flexibility and "no, we didn't document this incorrectly".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think that, to the extent we can get away with it, we should avoid mentioning flags since they are going to go away with the next major release. (Since upstream merged bitcoin-core/secp256k1#1126 there are basically no more flags.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that the size of context will stay compile-time-known forever? And having a custom mutable context is only needed for signing due to randomization?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both true, yes :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! So in that case we could drop AlignedType
and make ffi::Context
to have the size and alignment same as in C using the same trick I made PR with (just twice). That'd simplify many things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the whole bullet point, commenting here to double check we are happy with that?
src/context.rs
Outdated
/// | ||
/// * `raw_ctx` needs to be a valid Secp256k1 context pointer that was generated by *exactly* | ||
/// the same code/version of the libsecp256k1 used here. | ||
/// * The capabilities (`All`/`SignOnly`/`VerifyOnly`) of the context *must* match the flags |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only verification may be required - same as above.
Also the other part of the issue is we don't provide any guarantees or restriction with regards to pointer we return. E.g. one footgun which I only noticed recently is that the context must not be moved - it's effectively This is not visibly documented in the Rust library and given how common moves are in Rust it may be even bigger footgun than in C. |
I don't understand why contexts can't be moved. They don't have any self-referential pointers even in the C code. |
They don't but the last time I checked the docs moving is forbidden so I assume they may in the future. |
Huh, TIL. I don't know why this warning is there -- presumably to allow for future iterations to use self-referential pointers, I suppose -- but despite the warning, it is safe (with all current versions of the C library) to do moves or copies. The warning also claims that we can't read from the memory, a requirement that makes no sense and can't be enforced in C or Rust or anywhere. So we may want to PR upstream to clarify it. The warning was added in bitcoin-core/secp256k1#566 which has a ton of discussion, including by me and Elichai. If |
Oh crap, I read that wrong, it's concerning Maybe it's time to lift the restriction to resemble stacked borrows instead? :)
This only concerns people working with FFI. It's a non-issue for anyone else. Even if we wanted to make bare context using Rust But still, I'd rather not to either. |
Thanks for the reviews. Will re-spin when I can give this my full concentration. |
ef6836d
to
382206f
Compare
Please re-review carefully. Note also that I've removed the duplication of the docs and instead referred folks to the docs on |
src/context.rs
Outdated
@@ -351,15 +351,22 @@ impl<'buf> Secp256k1<AllPreallocated<'buf>> { | |||
|
|||
/// Creates a context from a raw context. | |||
/// | |||
/// The returned [`core::mem::ManuallyDrop`] context will never deallocate the memory pointed to | |||
/// by `raw_ctx`, nor destroy the context, this may lead to memory leaks. `ManuallyDrop::drop` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 382206f:
nit: this may lead to memory leaks
should be its own sentence.
src/context.rs
Outdated
@@ -351,15 +351,22 @@ impl<'buf> Secp256k1<AllPreallocated<'buf>> { | |||
|
|||
/// Creates a context from a raw context. | |||
/// | |||
/// The returned [`core::mem::ManuallyDrop`] context will never deallocate the memory pointed to | |||
/// by `raw_ctx`, nor destroy the context, this may lead to memory leaks. `ManuallyDrop::drop` | |||
/// (or [`core::ptr::drop_in_place`]) will only destroy the context, the caller is required to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 382206f:
Similarly the caller is required...
should be its own sentence, or we should use a semicolon rather than comma
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used a semicolon (because it makes me feel like an English grammar guru). We now have:
/// The returned [`core::mem::ManuallyDrop`] context will never deallocate the memory pointed to
/// by `raw_ctx` nor destroy the context. This may lead to memory leaks. `ManuallyDrop::drop`
/// (or [`core::ptr::drop_in_place`]) will only destroy the context; the caller is required to
/// free the memory.
382206f
to
0bd9c96
Compare
Force pushed changes to the docs as suggested (and posted above). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK 0bd9c96
Will wait on @Kixunil before merging this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My brain is working at around 30% capacity now so can't say for sure but I don't see anything that's obviously wrong.
/// | ||
/// This is highly unsafe due to a number of conditions that aren't checked, specifically: | ||
/// | ||
/// * `raw_ctx` must be a valid pointer (live, aligned...) to memory that was initialized by |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should mention AlignedType
as the one providing the correct alignment information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just realised I never added anything on AlignedType
as you suggest here.
src/context.rs
Outdated
/// `secp256k1_context_preallocated_create` (either called directly or from this library by | ||
/// one of the context creation methods - all of which call it internally). | ||
/// * The version of `libsecp256k1` used to create `raw_ctx` must be the same as the version | ||
/// used by this library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it about version (leading people to think "version number") or should it be the exact same binary? Maybe compiling with different flags could break it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be the exact same binary ... I agree that "same version" understates the requirement here. But given that there are no "version numbers" for libsecp, at least not until yesterday, I don't think there's any practical way to interpret this dangerously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure I've seen version numbers whether they are "real" doesn't matter that much since people will misinterpret it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, let's change this text to clarify that the version used to create raw_ctx
must be exactly the one linked into this library.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used as suggested and force pushed, no other changes.
0bd9c96
to
312cc1b
Compare
Will need to be rebased on #565 |
312cc1b
to
da49368
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK da49368
da49368
to
3b2e786
Compare
Rebased to see if CI is working. No other changes. |
We are getting unrelated 500 errors from a docker server now. |
Try re-running the failed jobs, it did work in |
Currently we have a wildcard on safety requirements, saying more or less "plus a bunch of other stuff we don't mention". This is not helpful. Attempt to fully describe the safety requirements of creating a context from a raw context (all, signing only, and verification only). Fix: rust-bitcoin#544
3b2e786
to
e705bcf
Compare
Force push a new commit hash just to trigger CI, no changes to the PR. |
1 similar comment
Force push a new commit hash just to trigger CI, no changes to the PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK e705bcf
@Kixunil I'd like your ACK on this before merging it. |
/// * `raw_ctx` needs to be a valid Secp256k1 context pointer. | ||
/// that was generated by *exactly* the same code/version of the libsecp256k1 used here. | ||
/// * The capabilities (All/SignOnly/VerifyOnly) of the context *must* match the flags passed to libsecp256k1 | ||
/// when generating the context. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one still applies but is not mentioned in the new text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't remember why I removed this exactly because it was a long time ago but it seems such an obvious omission that I think me from the past would of had a reason. I'm out of my depth of knowledge here but I thought there was something about the libsecp context not differentiating any more? Are you sure we still want this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From looking at gen_new
I don't see that the libsecp context created is any different for the different All/SignOnly/VerifyOnly tags, or am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, there is now no difference upstream between the capabilities, they're total no-ops. But we haven't updated the Rust API to reflect this yet because it'd be a big breaking change and we wanted to make sure upstream was finished changing first.
So I think this text is ok to drop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet, my brain worked!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need to?
No. Upstream had an actual release :).
Maybe we could start with using All as the default type parameter and change the generic functions to accept any type parameter and deprecate the All, SignOnly and VerifyOnly types. This is not breaking but reflects it in the API.
Another strategy might be to stop exposing context objects in the API at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We still need them for re-randomization, don't we?
Anyway, I prefer the API to be modified a little to not being modified at all because of the amount of work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In #388 (or somewhere) we came to a solution that enables re-randomization without needing explicit context objects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another strategy might be to stop exposing context objects in the API at all.
Would we use a global singleton for the context and leave the secp256k1-sys
API the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tcharding yes, the secp-sys API would remain the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK e705bcf
Assuming dropping of flags gets documented in the future PR.
Currently we have a wildcard on safety requirements, saying more or less "plus a bunch of other stuff we don't mention". This is not helpful.
Attempt to fully describe the safety requirements of creating a context from a raw context (all, signing only, and verification only).
Fix: #544
Note
This is best effort only, will require some thought to review. To do this I read https://doc.rust-lang.org/reference/behavior-considered-undefined.html and then I flicked through
depend/secp256k1/src/secp256k1.c
andutil.h
to look for things that could cause things in the linked to list of UB.