Skip to content

Conversation

apoelstra
Copy link
Member

Fixes the signature of secp256k1_ec_pubkey_sort to use *mut rather than *const.

Separately, our call to secp256k1_ec_pubkey_sort, while correctly starting from a &mut [PublicKey], briefly constructed a &[ffi::PublicKey] slice before obtaining a *mut pointer from this. This was unsound for completely unnecessary reasons, and only compiled because we have an impl of the CPtr trait for &[T], which provides a as_mut_c_ptr() method which basically cannot be safely used.

Removing that &[T] impl revealed another case where it was (unnecessarily) being used: in EllSwift::shared_secret, where we use it to obtain a *mut pointer from a &[u8], which we pass across the FFI boundary which simply drops it.

In rust-bitcoin#794 I accidentally changed a *mut to *const. This is incorrect and
unsound.
We take an optional `data` argument to `shared_secret`, but the upstream
function we call never uses it. However, this argument *does* use the
CPtr impl on &[T] in order to obtain a pointer to pass across the FFI
boundary. This impl is very dangerous, and its use here is sound only
because the resulting pointer is never used.

See
rust-bitcoin#627 (comment)
In sort_pubkeys() we convert a slice of PublicKeys to a slice of
ffi::PublicKeys. This is OK, because we have repr(transparent) allowing
us to do this. But we do so in an unnecessarily-complicated way, which
winds up going through the CPtr implementation on &[u8], and which I
think may technically be unsound.

Simplify it and avoid using this impl. The next commit will remove it
entirely.
@apoelstra
Copy link
Member Author

I am equivocating on whether I should backport the last commit to secp256k1-sys 0.9.x, 0.10.x and 0.11.x. Doing so would be a breaking change (and would break rust-secp256k1, necessitating a minor release of those) and technically speaking there is no unsoundness here so it is not urgent to do so.

But on the other hand, <&[T]>::as_c_mut_ptr is really dangerous, never needed to be exposed except that we made a mistake, and we managed to cut ourselves with it and nearly released an unsound version of the library with it. Which we caught entirely by accident -- I incorrectly changed a ffi signature near the UB, which Kix noticed and complained about, and in my investigation I found it.

@apoelstra
Copy link
Member Author

For anyone struggling to follow my story here -- checkout master remove the impl CPtr for &[T] block in secp256k1-sys/src/lib.rs, and see what breaks.

Copy link
Member Author

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On debae90 successfully ran local tests

Copy link
Member

@tcharding tcharding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK debae90

@tcharding
Copy link
Member

This is a bit over my head. I went to read the Rustnomicon and decided I don't want to do that ATM, one day ...

@apoelstra apoelstra merged commit 9d5fcba into rust-bitcoin:master Jul 2, 2025
28 checks passed
@apoelstra apoelstra deleted the 2025-06_cptr_madness branch July 2, 2025 04:32
chain-forgexcr45 added a commit to chain-forgexcr45/rust-secp256k1 that referenced this pull request Sep 28, 2025
…mpl for `&[T]` and associated weirdness

debae9017592c4659bb0d64294d1cdadbf8e652f secp256k1-sys: remove CPtr impl for &[T] (Andrew Poelstra)
2cef56192f8107ab4ee2c8f5e1131708769b82fc key.rs: clean up some pointer mangling in sort_pubkeys() (Andrew Poelstra)
44bcb893053d96bf5f082c6acd45e89226128300 ellswift: remove unused `data` argument from `shared_secret` (Andrew Poelstra)
2139aff0d705142ffb40883023bf47d4978dae70 secp256k1-sys: fix type signature in secp256k1_ec_pubkey_sort (Andrew Poelstra)

Pull request description:

  Fixes the signature of secp256k1_ec_pubkey_sort to use `*mut` rather than `*const`.
  
  Separately, our call to `secp256k1_ec_pubkey_sort`, while correctly starting from a `&mut [PublicKey]`, briefly constructed a `&[ffi::PublicKey]` slice before obtaining a `*mut` pointer from this. This was unsound for completely unnecessary reasons, and only compiled because we have an impl of the `CPtr` trait for `&[T]`, which provides a `as_mut_c_ptr()` method which basically cannot be safely used.
  
  Removing that `&[T]` impl revealed another case where it was (unnecessarily) being used: in `EllSwift::shared_secret`, where we use it to obtain a `*mut` pointer from a `&[u8]`, which we pass across the FFI boundary which simply drops it.


ACKs for top commit:
  tcharding:
    ACK debae9017592c4659bb0d64294d1cdadbf8e652f


Tree-SHA512: 2245883cbd0695dcf495a075d530155c6f496cf7fe78c2560b567888dc5fb5f3160970c8bbd44abd67e240bccf41555fc71fd3f74daac11d446fc2b4783028ed
william2332-limf added a commit to william2332-limf/rust-secp256k1 that referenced this pull request Oct 2, 2025
…mpl for `&[T]` and associated weirdness

debae9017592c4659bb0d64294d1cdadbf8e652f secp256k1-sys: remove CPtr impl for &[T] (Andrew Poelstra)
2cef56192f8107ab4ee2c8f5e1131708769b82fc key.rs: clean up some pointer mangling in sort_pubkeys() (Andrew Poelstra)
44bcb893053d96bf5f082c6acd45e89226128300 ellswift: remove unused `data` argument from `shared_secret` (Andrew Poelstra)
2139aff0d705142ffb40883023bf47d4978dae70 secp256k1-sys: fix type signature in secp256k1_ec_pubkey_sort (Andrew Poelstra)

Pull request description:

  Fixes the signature of secp256k1_ec_pubkey_sort to use `*mut` rather than `*const`.
  
  Separately, our call to `secp256k1_ec_pubkey_sort`, while correctly starting from a `&mut [PublicKey]`, briefly constructed a `&[ffi::PublicKey]` slice before obtaining a `*mut` pointer from this. This was unsound for completely unnecessary reasons, and only compiled because we have an impl of the `CPtr` trait for `&[T]`, which provides a `as_mut_c_ptr()` method which basically cannot be safely used.
  
  Removing that `&[T]` impl revealed another case where it was (unnecessarily) being used: in `EllSwift::shared_secret`, where we use it to obtain a `*mut` pointer from a `&[u8]`, which we pass across the FFI boundary which simply drops it.


ACKs for top commit:
  tcharding:
    ACK debae9017592c4659bb0d64294d1cdadbf8e652f


Tree-SHA512: 2245883cbd0695dcf495a075d530155c6f496cf7fe78c2560b567888dc5fb5f3160970c8bbd44abd67e240bccf41555fc71fd3f74daac11d446fc2b4783028ed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants