Skip to content
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

ext_config: Fixes config only operations. #123

Merged
merged 1 commit into from
Dec 2, 2023

Conversation

larrydewey
Copy link
Contributor

Previously we were passing the u64 value of the pointer to the vector of bytes the extended report certificates were being loaded from. However, when handling the case of an extended configuration only, because the pointer value of an empty vector is not 0, this was causing an error in the kernel when attempting to access the "pointer" being provided. By modifying the underlying type of bytes to Option<Vec<u8>>, it allows the default value to be set to None, and conditionally update the extended config certs_address field when certificate bytes are present.

@larrydewey larrydewey added the bug Something isn't working label Nov 16, 2023
@larrydewey larrydewey self-assigned this Nov 16, 2023
@auto-assign auto-assign bot requested a review from ryansavino November 16, 2023 16:12
Copy link
Member

@DGonzalezVillal DGonzalezVillal left a comment

Choose a reason for hiding this comment

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

Clever, so when passing the value as none instead of a ptr, then the firmware knows it's supposed to be empty?

@tylerfanelli
Copy link
Member

If the certificate input is empty, wouldn't the ext_config certs_len be set to 0? Why would the buffer be read in that case?

Copy link
Member

@tylerfanelli tylerfanelli left a comment

Choose a reason for hiding this comment

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

See above comment.

@larrydewey
Copy link
Contributor Author

If the certificate input is empty, wouldn't the ext_config certs_len be set to 0? Why would the buffer be read in that case?

It isn't that it is being read from the user's input, but that we created the bytes vector to ensure the data lived long enough before being dropped. In this case, because the vector was originally vec![] the pointer was actually 0x1, which caused an issue with the kernel. By setting the value to None by default, and wrapping the condition with an if let Some(), we can check if the bytes array has been populated after converting the Rust CertTable to the C-CertTable structure.

@tylerfanelli
Copy link
Member

tylerfanelli commented Nov 16, 2023

If the certificate input is empty, wouldn't the ext_config certs_len be set to 0? Why would the buffer be read in that case?

It isn't that it is being read from the user's input, but that we created the bytes vector to ensure the data lived long enough before being dropped. In this case, because the vector was originally vec![] the pointer was actually 0x1, which caused an issue with the kernel. By setting the value to None by default, and wrapping the condition with an if let Some(), we can check if the bytes array has been populated after converting the Rust CertTable to the C-CertTable structure.

I'm still not seeing how the kernel gets tripped up here unless a read takes place. If the vec![] is of size 0 (i.e. there are no certs) then the buffer would never be read.

Previously we were passing the u64 value of the
pointer to the vector of bytes the extended
report certificates were being loaded from.
However, when handling the case of an extended
configuration only, because the pointer value
of an empty vector is not 0, this was causing
an error in the kernel when attempting to access
the "pointer" being provided. By modifying the
underlying type of `bytes` to `Option<Vec<u8>>`,
it allows the default value to be set to `None`,
and conditionally update the extended config
`certs_address` field when certificate bytes are
present.

Also updated the TryFrom<ExtConfig> for
SnpExtSetConfig to use the reference instead of
a copy. This prevents the underlying config
object from being dropped after the if-let block.

Signed-off-by: Larry Dewey <[email protected]>
Copy link
Member

@DGonzalezVillal DGonzalezVillal left a comment

Choose a reason for hiding this comment

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

lgtm

@larrydewey
Copy link
Contributor Author

larrydewey commented Dec 1, 2023

If the certificate input is empty, wouldn't the ext_config certs_len be set to 0? Why would the buffer be read in that case?

It isn't that it is being read from the user's input, but that we created the bytes vector to ensure the data lived long enough before being dropped. In this case, because the vector was originally vec![] the pointer was actually 0x1, which caused an issue with the kernel. By setting the value to None by default, and wrapping the condition with an if let Some(), we can check if the bytes array has been populated after converting the Rust CertTable to the C-CertTable structure.

I'm still not seeing how the kernel gets tripped up here unless a read takes place. If the vec![] is of size 0 (i.e. there are no certs) then the buffer would never be read.

The Kernel gets tripped up because input.certs_address is not 0x0, it is 0x1, which means it enters the conditional block from the link you provided above. When this happens, !input.certs_len becomes true, and returns -EINVAL. In the situation where we want to set the REPORTED_TCB via config_only, we don't want this to cause the kernel to puke an -EINVAL.

Updating the pointer to the certs_address only when the certificate bytes are present fixes this problem.

Further, there is a use after free issue which is happening because of the if-let block. I recently learned that when using if-let, the value in Some(value) is a copy, and drops out of scope at the end of the if-let block. Using Some(ref value), we are specifying we want to refer to the original value instead of copying it.

I have tested setting and resetting the REPORTED_TCB on a machine with these patches, and it is working as expected now.

@tylerfanelli
Copy link
Member

I see, so when we are only setting the extended config, we have an empty certs buffer (i.e. certs_address != 0 and certs_len == 0), and thus it fails. What we want to do is pass certs_address == 0 (which is basically what we are doing with a None value being passed).

Copy link
Member

@tylerfanelli tylerfanelli left a comment

Choose a reason for hiding this comment

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

LGTM.

@larrydewey larrydewey merged commit abd442f into virtee:main Dec 2, 2023
18 checks passed
@larrydewey larrydewey deleted the tcb_bug branch December 2, 2023 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants