-
Notifications
You must be signed in to change notification settings - Fork 155
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
Make the Tx
object zeroize itself on drop
#2925
base: main
Are you sure you want to change the base?
Conversation
This is an experimental change to improve hygeine of memory in the consensus enclave (but also in the clients) This makes a bunch of objects derive `Zeroize` in transaction-core, and makes the `Tx` object zeroize itself on drop. For examples of why this is a good change, consider that, in the `mc-connection` ThickClient crate, after we serialize a Tx to protobuf and encrypt it for the enclave, we zeroize the plaintext. However, before this change, we do not zeroize the `Tx` object (since it would not have been possible), so another copy of the data that we zeroized continues to exist in memory. After this change, the `Tx` will zeroize itself automatically as well. The main reason not to do this would be if it hurts the performance of the consensus nodes, but I consider this unlikely, because, the untrusted side never actually sees `Tx` objects so SCP should not be meaningfully impacted by this, only the transaction validation handles the decrypted `Tx`. And the elliptic curve operations done to validate a Tx should be many orders of magnitude more expensive than a zeroizing operation. So I expect no measurable performance difference as a result of this change. See github issue #2717
@@ -310,7 +310,7 @@ pub fn initialize_ledger( | |||
); | |||
|
|||
let key_images = tx.key_images(); | |||
(tx.prefix.outputs, key_images) | |||
(tx.prefix.outputs.clone(), key_images) |
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 needed because rustc says we cannot move out of Tx
anymore since it is a Drop
type now
transaction/core/src/tx.rs
Outdated
@@ -103,7 +103,8 @@ impl fmt::Debug for TxHash { | |||
} | |||
|
|||
/// A CryptoNote-style transaction. | |||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Message, Digestible)] | |||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Message, Digestible, Zeroize)] | |||
#[zeroize(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.
this is the main change
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.
looks good sans the other instance that needs to clone
error[E0509]: cannot move out of type `Tx`, which implements the `Drop` trait
--> consensus/enclave/mock/src/lib.rs:287:28
|
287 | outputs.extend(tx.prefix.outputs.into_iter());
| ^^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `tx.prefix.outputs` has type `Vec<TxOut>`, which does not implement the `Copy` trait
For more information about this error, try `rustc --explain E0509`.
transaction/core/src/tx.rs
Outdated
@@ -103,7 +103,8 @@ impl fmt::Debug for TxHash { | |||
} | |||
|
|||
/// A CryptoNote-style transaction. | |||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Message, Digestible)] | |||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Message, Digestible, Zeroize)] | |||
#[zeroize(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.
❓ These docs are hard to parse.
Zeroing memory is hard
...
This crate has custom derive support for the Zeroize trait, gated under the zeroize crate’s zeroize_derive Cargo feature, which automatically calls zeroize() on all members of a struct or tuple struct.
The automatically calls gave me the impression this was during drop. In their defense they have examples after with comments saying ZeorizeOnDrop
happens on drop.
Anyway should the ZeroizeOnDrop
be added to more types in addition to the plain Zeroize
?
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.
Yes, looks like we want both. That's what the Zeroize tests do: https://github.com/RustCrypto/utils/blob/master/zeroize/tests/zeroize_derive.rs
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.
Anyway should the ZeroizeOnDrop be added to more types in addition to the plain Zeroize?
I am not sure right now
I tried to make a list of things that should maybe be zeroized in #2717
I figured starting with Tx
was a reasonable place to start, and I wrote a bunch of rationale in the code comments.
It is causing wierd rust compilation issues to make the type Drop when it wasn't previously, so I'd rather not do this to a lot of types in this PR. And the other thing is, zeroizing operations may have nontrivial overhead, so we either have to measure the impact carefully or have a very good reason why it shouldn't impact network performance (ideally both).
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 there any to stand this hypothesis up in one of the test networks?
In this draft PR, I developed a benchmark which clones and drops a Tx with the It looks that it takes about .14 milliseconds, which is a lot slower than I would have hoped for. |
See also this issue: RustCrypto/utils#743 |
@cbeck88 Is this still live, or can we close it? |
I plan to test this properly once we have slam working properly |
Idk, i mean, if slam looks the same before and after this change then i feel like it should be okay to go in, but feel free to tell me otherwise |
@cbeck88 Ping on this now that we've got slam going... |
Yea lets try to slam it I also opened a PR in zeroize crate, if they take that should also give us a good way to optimize this |
This is an experimental change to improve hygeine of memory in the consensus enclave (but also in the clients)
This makes a bunch of objects derive
Zeroize
in transaction-core, and makes theTx
object zeroize itself on drop.For examples of why this is a good change, consider that, in the
mc-connection
ThickClient crate, after we serialize a Tx to protobuf and encrypt it for the enclave, we zeroize the plaintext. However, before this change, we do not zeroize theTx
object (since it would not have been possible), so another copy of the data that we zeroized continues to exist in memory. After this change, theTx
will zeroize itself automatically as well.The main reason not to do this would be if it hurts the performance of the consensus nodes, but I consider this unlikely, because, the untrusted side never actually sees
Tx
objects so SCP should not be meaningfully impacted by this, only the transaction validation handles the decryptedTx
. And the elliptic curve operations done to validate a Tx should be many orders of magnitude more expensive than a zeroizing operation. So I expect no measurable performance difference in the consensus network as a result of this change.For similar reasons I don't expect any client to have a measurable perf impact either.
See github issue #2717