Skip to content

Improve usage of unsafe blocks #18

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

Merged
merged 1 commit into from
Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/abstraction/transient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ impl TransientObjectContext {
self.context.flush_context(key_handle)?;
Err(e)
})?;
let key = match PublicIdUnion::from_public(&key_pub_id) {
let key = match unsafe { PublicIdUnion::from_public(&key_pub_id) } {
// call should be safe given our trust in the TSS library
PublicIdUnion::Rsa(pub_key) => {
let mut key = pub_key.buffer.to_vec();
key.truncate(pub_key.size.try_into().unwrap()); // should not fail on supported targets
Expand Down
27 changes: 20 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,24 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(dead_code)]
///! # Notes on code safety:
///! * the `unsafe` keyword is used to denote methods that could panic, crash or cause undefined
///! behaviour. Whenever this is the case, the properties that need to be checked against
///! parameters before passing them in will be stated in the documentation of the method.
///! * `unsafe` blocks within this crate need to be documented through code comments if they
///! are not covered by the points of trust described here.
///! * the TSS2.0 library that this crate links to is trusted to return consistent values and to
///! not crash or lead to undefined behaviour when presented with valid arguments.
///! * the `Mbox` crate is trusted to perform operations safely on the pointers provided to it, if
///! the pointers are trusted to be valid.
///! * methods not marked `unsafe` are trusted to behave safely, potentially returning appropriate
///! erorr messages when encountering any problems.
///! * whenever `unwrap`, `expect`, `panic` or derivatives of these are used, they need to be
///! thoroughly documented and justified - preferably `unwrap` and `expect` should *never* fail
///! during normal operation.
///! * these rules can be broken in test-only code and in tests.

#[allow(
non_snake_case,
Expand Down Expand Up @@ -412,7 +429,7 @@ impl Context {

if ret.is_success() {
let signature = unsafe { MBox::from_raw(signature) };
Ok((*signature).try_into()?)
Ok(unsafe { Signature::try_from(*signature)? })
Copy link
Member

Choose a reason for hiding this comment

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

Maybe a comment to explain why this is safe would make us better unsafe citizens 👷

Copy link
Member

Choose a reason for hiding this comment

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

Same everywhere we use the unsafe block actually in my opinion. The same way we kind of have to justify when we panic explicitely.

Copy link
Member Author

Choose a reason for hiding this comment

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

Indeed, will add

} else {
error!("Error in loading: {}.", ret);
Err(ret)
Expand Down Expand Up @@ -659,14 +676,10 @@ impl Drop for Context {
let tcti_context = self.tcti_context.take().unwrap(); // should not fail based on how the context is initialised/used

// Close the TCTI context.
unsafe {
tss2_esys::Tss2_TctiLdr_Finalize(
&mut tcti_context.into_raw() as *mut *mut TSS2_TCTI_CONTEXT
)
};
unsafe { tss2_esys::Tss2_TctiLdr_Finalize(&mut tcti_context.into_raw()) };

// Close the context.
unsafe { tss2_esys::Esys_Finalize(&mut esys_context.into_raw() as *mut *mut ESYS_CONTEXT) };
unsafe { tss2_esys::Esys_Finalize(&mut esys_context.into_raw()) };
Copy link
Member

Choose a reason for hiding this comment

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

💌

info!("Context closed.");
}
}
Expand Down
17 changes: 6 additions & 11 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,9 @@ pub enum PublicIdUnion {
}

impl PublicIdUnion {
pub fn from_public(public: &TPM2B_PUBLIC) -> Self {
pub unsafe fn from_public(public: &TPM2B_PUBLIC) -> Self {
match public.publicArea.type_ {
TPM2_ALG_RSA => {
// TODO Issue #2: Should this method be unsafe?
PublicIdUnion::Rsa(Box::from(unsafe { public.publicArea.unique.rsa }))
}
TPM2_ALG_RSA => PublicIdUnion::Rsa(Box::from(public.publicArea.unique.rsa)),
TPM2_ALG_ECC => unimplemented!(),
TPM2_ALG_SYMCIPHER => unimplemented!(),
TPM2_ALG_KEYEDHASH => unimplemented!(),
Expand Down Expand Up @@ -425,15 +422,13 @@ pub struct Signature {
pub signature: Vec<u8>,
}

impl TryFrom<TPMT_SIGNATURE> for Signature {
type Error = Error;

fn try_from(tss_signature: TPMT_SIGNATURE) -> Result<Self> {
impl Signature {
pub unsafe fn try_from(tss_signature: TPMT_SIGNATURE) -> Result<Self> {
Copy link
Member

Choose a reason for hiding this comment

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

I think that is a very good decision to put the unsafe on the method here as we can not trust that the tss_signature argument is always well-composed. The caller of this method needs to make the decision as only him knows where the parameter comes from.

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking: "what if the method is not public?"
But even so, it would maybe be wrong to put it safe anyway.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe a comment would be nice to explain those things? Or that could be part of the documentation of the method itself.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I decided to just leave it to documentation, a comment isn't as visible for users

match tss_signature.sigAlg {
TPM2_ALG_RSASSA => {
let hash_alg = unsafe { tss_signature.signature.rsassa.hash };
let hash_alg = tss_signature.signature.rsassa.hash;
let scheme = AsymSchemeUnion::RSASSA(hash_alg);
let signature_buf = unsafe { tss_signature.signature.rsassa.sig };
let signature_buf = tss_signature.signature.rsassa.sig;
let mut signature = signature_buf.buffer.to_vec();
signature.truncate(signature_buf.size.into());

Expand Down