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

Add ASAN and UBSAN stages to CI, fix various errors [AP-1386] #1403

Merged
merged 3 commits into from
Mar 3, 2024

Conversation

woodfell
Copy link
Contributor

@woodfell woodfell commented Feb 15, 2024

Description

@swift-nav/devinfra

Add bazel config to build with ASAN, UBSAN, TSAN, or MSAN

Add CI stages to run tests with ASAN and UBSAN. The other sanitizers aren't important to run regularly given the nature of code in this repository, but they exist for consistency with other projects and to enable manually running those sanitizer if required

A couple of fixes to problems in code which were discovered by the sanitizer. No breaking changes though

API compatibility

No

API compatibility plan

No

JIRA Reference

https://swift-nav.atlassian.net/browse/AP-1386

@@ -29,7 +29,7 @@ struct SbpHeaderParams {
uint16_t sender_id;
uint16_t msg_type;
uint8_t payload_len;
msg_obs_t payload;
uint8_t payload[SBP_MAX_PAYLOAD_LEN];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For messages with variable length arrays the legacy API generates a struct with a zero length array at the end. Something like:

struct sbp_obs_t {
  struct sbp_common_header_t header;
  struct sbp_packed_obs_t obs[0];
};

The size of this struct doesn't include the variable length array. So in this instance sizeof(SbpHeaderParams::payload) == 5 (the size of the header only) but when the handler is invoked a few lines down the payload length will be anything up to 255. This causes a buffer overflow.

@@ -28,6 +28,13 @@
#include <libsbp/legacy/cpp/payload_handler.h>
#include <libsbp/legacy/cpp/legacy_state.h>

template<typename T, typename U = std::remove_reference_t<T>>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changes in this template required because fields in the wire encoded byte stream rarely have the correct alignment. Eg, a 2 byte integer has an alignment of 2 (on typical systems), but the starting address of the field in the byte stream might not be properly aligned.

x86 tends to cope with this properly which is why this hasn't caused problems so far, but it is a problem detectable by one of the sanitizers. This solution adds a little helper function to memcpy a few bytes from the bytestream in to a stack variable which is guaranteed to be properly aligned, then return to the caller.

This method reduces the amount of code changes required, although it does lead to a rather annoying use of decltype a few lines down. Since this is in legacy code and will be deleted soon it seems a reasonable solution.

@@ -376,7 +376,7 @@ void comparison_tests(const (((t.struct_name))) &lesser,
template <typename T,
std::enable_if_t<std::is_integral<T>::value, bool> = true>
void make_lesser_greater(T &lesser, T &greater) {
if (greater == std::numeric_limits<T>::max()) {
if (lesser > std::numeric_limits<T>::min()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For variable length arrays this can cause a buffer overflow.

The modern API deals with variable length arrays by generating a maximally sized array plus a companion field which indicates how many elements are valid. For example, a message containing a variable length array of uint8_t:

struct sbp_msg_sample_t {
  uint32_t some_other_field;
  uint8_t bytes[SBP_MSG_SAMPLE_BYTES_MAX];
  size_t n_bytes;
};

This function make_lesser_greater is used by the test cases for comparison functions. The generator will use this function by:

  • Given some sample data from the test specs create 2 instances of the test message containing identical data
  • For each field in the message spec call make_lesser_greater to purposefully introduce a different between the 2 instances
  • Run a series of comparisons on both instances and validate the results

One of the tests compares the altered message instance to itself. This is meant to ensure that even with the altered field the message will compare equal to something which was altered in the same way.

The function make_lesser_greater prefers to increment a field value and only decrements it if the field is already at the maximum value for the type. In the case of the companion field for variable length arrays (n_bytes in the strawman code above) this can lead the comparison field to believe there are more elements in the variable length array than there actually are. ASAN will pick up on this describing it as a buffer overflow.

The simple solution is to alter make_lesser_greater to prefer decrementing a field value and only incrementing it if the field is at the minimum value for the type. This could lead to exactly the same problem if the test spec provides 0 elements for the variable length array, however the changes to cope with this are too intrusive to write on this PR, they can be handled separately

@woodfell woodfell marked this pull request as ready for review February 15, 2024 22:57
@woodfell woodfell requested review from jungleraptor and a team as code owners February 15, 2024 22:57
@woodfell woodfell changed the title Add ASAN and UBSAN stages to CI, fix various errors Add ASAN and UBSAN stages to CI, fix various errors [AP-1386] Feb 15, 2024
Copy link

sonarcloud bot commented Feb 16, 2024

Quality Gate Passed Quality Gate passed for 'libsbp-c'

Issues
0 New issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

Copy link
Contributor

@reimerix reimerix left a comment

Choose a reason for hiding this comment

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

Awesome, thanks for adding this!

@woodfell woodfell merged commit 9415861 into master Mar 3, 2024
23 checks passed
@woodfell woodfell deleted the woodfell/add_asan_ubsan branch March 3, 2024 22:21
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.

3 participants