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

Make ASAN work with tests mocking libc functions and fix several errors caught by UBSAN #732

Merged
merged 9 commits into from
Nov 2, 2023

Conversation

calebsander
Copy link
Contributor

Testing out ASAN revealed that the new tests using LD_PRELOAD with a shared library containing mocks for libc functions cause ASAN to abort at startup. Suppress this check because ASAN seems to have no problems catching memory issues in libnvme, the tests, or the mocks.
Also fix several issues caught by enabling UBSAN in the unit tests:

  • Passing NULL pointers to memcmp() and memset()
  • Dereferencing unaligned pointers
  • Overflow from bit shifts on int values that should be u32s

Copy link
Collaborator

@igaw igaw left a comment

Choose a reason for hiding this comment

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

Nitpick: the subject prefix should be the file name I think.

src/nvme/ioctl.c Outdated Show resolved Hide resolved
src/nvme/ioctl.c Outdated Show resolved Hide resolved
The README currently suggests setting LD_PRELOAD to the libasan path.
However, this seems to be unnecessary (at least on my gcc 9 setup).
The test executables request to link with libasan.so (before libc.so),
so it is automatically loaded.
The recommended suggestion also ends up running ninja with ASAN
instrumentation, which causes it to fail with leaks detected.

Signed-off-by: Caleb Sander <[email protected]>
The undefined behavior sanitizer can catch a bunch of common C bugs.
Add instructions to the README for enabling it via meson.

Signed-off-by: Caleb Sander <[email protected]>
Several tests mock libc functions by setting LD_PRELOAD
to a shared library containing mock implementations of the functions.
Currently this prevents the tests from running with ASAN.
ASAN complains that libasan doesn't come first in LD_PRELOAD and aborts.
But in practice this doesn't seem to be an issue.
Sample ASAN issues added to libnvme, the test cases, and the mocks
are all correctly reported.
So suppress this warning by setting the environment variable
ASAN_OPTIONS=verify_asan_link_order=0.
In case the user does want to inject a specific libasan,
change the tests' use of LD_PRELOAD to append the mock shared library
rather than overwriting LD_PRELOAD entirely.

Signed-off-by: Caleb Sander <[email protected]>
According to the C standard, it is undefined behavior
to pass NULL pointers to standard library functions.
This includes the mem*() family of functions,
even they are passed a length of 0.
So avoid calling these functions when the length is 0.

Signed-off-by: Caleb Sander <[email protected]>
Avoid casting byte-aligned pointers to pointers with higher alignment.
Loading or storing values with higher alignment is undefined behavior,
since some processors don't allow unaligned memory accesses
and compilers may assume pointers of different types don't alias.
Perform an explicit memcpy() in two places, which an optimizing compiler
can easily replace with a single load/store on supported architectures.

While we're touching this code, also use IN6_IS_ADDR_V4MAPPED()
instead of hand-rolling it.

Signed-off-by: Caleb Sander <[email protected]>
Avoid casting byte-aligned pointers to pointers with higher alignment.
Loading or storing values with higher alignment is undefined behavior,
since some processors don't allow unaligned memory accesses
and compilers may assume pointers of different types don't alias.
Perform an explicit memcpy(), which an optimizing compiler
can easily replace with a single load/store on supported architectures.

Signed-off-by: Caleb Sander <[email protected]>
Bit shifts that overflow the resulting type are undefined behavior in C.
C arithmetic promotes to ints all smaller integer types.
There are several places where a 32-bit unsigned value
is constructed by shifting a u8 or u16 to the most significant bits.
Since this overflows a signed 32-bit integer,
explicitly cast to u32 to avoid the UB.
Technically, an int is allowed to only be 16 bits,
so any shift that could set bit 15 or higher is UB.
But platforms where int is s16 are not very common,
so it's likely not worth the effort to fix the code.

Signed-off-by: Caleb Sander <[email protected]>
Bit shifts that overflow the resulting type are undefined behavior in C.
C arithmetic promotes to ints all smaller integer types.
There are several places where a 32-bit unsigned value
is constructed by shifting a u8 or u16 to the most significant bits.
Since this overflows a signed 32-bit integer,
explicitly cast to u32 to avoid the UB.
Technically, an int is allowed to only be 16 bits,
so any shift that could set bit 15 or higher is UB.
But platforms where int is s16 are not very common,
so it's likely not worth the effort to fix the code.

Signed-off-by: Caleb Sander <[email protected]>
Bit shifts that overflow the resulting type are undefined behavior in C.
C arithmetic promotes to ints all smaller integer types.
There are several places where a 32-bit unsigned value
is constructed by shifting a u8 or u16 to the most significant bits.
Since this overflows a signed 32-bit integer,
explicitly cast to u32 to avoid the UB.
Technically, an int is allowed to only be 16 bits,
so any shift that could set bit 15 or higher is UB.
But platforms where int is s16 are not very common,
so it's likely not worth the effort to fix the code.

Signed-off-by: Caleb Sander <[email protected]>
@igaw
Copy link
Collaborator

igaw commented Nov 2, 2023

Just splitted the last two patches, because I think it groups the changes a bit better and thus easier to spot the what's going on.

@igaw igaw merged commit d5962d8 into linux-nvme:master Nov 2, 2023
13 checks passed
@igaw
Copy link
Collaborator

igaw commented Nov 2, 2023

Thanks!

@calebsander calebsander deleted the fix/asan branch November 2, 2023 15:57
matoro added a commit to matoro/gentoo that referenced this pull request Dec 16, 2023
matoro added a commit to matoro/gentoo that referenced this pull request Dec 16, 2023
gentoo-bot pushed a commit to gentoo/gentoo that referenced this pull request Dec 16, 2023
MocioF pushed a commit to MocioF/gentoo that referenced this pull request Dec 17, 2023
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