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

time.h: fix integer overflow in MsToAbsoluteTimespec() on 32-bit architectures #1042

Merged
merged 6 commits into from
Aug 5, 2022

Conversation

dconeybe
Copy link
Contributor

@dconeybe dconeybe commented Aug 4, 2022

This PR fixes a long-standing bug in MsToAbsoluteTimespec(int milliseconds) which would result in an integer overflow if invoked with a sufficiently-large "milliseconds". The bug manifested on 32-bit architectures because the tv_sec and tv_nsec members of timespec are 4 bytes each (32 bits), where on 64-bit architectures they are 8 bytes each (64 bits), and did not suffer from the overflow.

The problem was that in MsToAbsoluteTimespec(int milliseconds) it would add the given milliseconds, after converting to nanoseconds, to the tv_nsec member, and then call a helper function to normalize the values; however, when being invoked with a milliseconds value of 10000 (10 seconds) this would cause tv_nsec to overflow and wrap around to a negative value. When this malformed timespec was later specified to sem_timedwait() in Semaphore::TimedWait() it would cause the function call to fail immediately with EINVAL.

The fix in this PR is to instead do all of the math with an int64_t and then calculate the tv_sec and tv_nsec values from it. By doing all of the math with a 64-bit integer, no overflow occurs.

This fix will also fix a bunch of Firestore's transaction tests which are currently failing on 32-bit architectures due to this bug when they call Future::Await(10000).

Here is one example of a testapp crash due to this bug on an x86 Android emulator. Here is the implementation of MsToAbsoluteTimespec() with the bug:

inline timespec MsToAbsoluteTimespec(int milliseconds) {
timespec t;
clock_gettime(CLOCK_REALTIME, &t);
t.tv_nsec += milliseconds * internal::kNanosecondsPerMillisecond;
NormalizeTimespec(&t);
return t;
}

In this test, the milliseconds argument was 10000 (10 seconds) and the timespec t had the following values after the following lines:

  • After line 91: tv_sec=1659589211 tv_nsec=799274196
  • After line 92: tv_sec=1659589211 tv_nsec=-2085627692
  • After line 93: tv_sec=1659589209 tv_nsec=-85627692

You can see that tv_nsec is negative, which is invalid.

@dconeybe dconeybe self-assigned this Aug 4, 2022
@dconeybe dconeybe added the tests-requested: quick Trigger a quick set of integration tests. label Aug 4, 2022
@github-actions github-actions bot added tests: in-progress This PR's integration tests are in progress. and removed tests-requested: quick Trigger a quick set of integration tests. labels Aug 4, 2022
@github-actions
Copy link

github-actions bot commented Aug 4, 2022

✅  Integration test succeeded!

Requested by @dconeybe on commit ed0d970
Last updated: Fri Aug 5 15:04 PDT 2022
View integration test log & download artifacts

@github-actions github-actions bot added the tests: failed This PR's integration tests failed. label Aug 4, 2022
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Aug 4, 2022
@github-actions github-actions bot added the tests: succeeded This PR's integration tests succeeded. label Aug 4, 2022
@dconeybe dconeybe removed the tests: failed This PR's integration tests failed. label Aug 4, 2022
@dconeybe dconeybe requested a review from jonsimantov August 4, 2022 14:51
app/src/time.h Outdated
(milliseconds * internal::kNanosecondsPerMillisecond);

t.tv_sec = nanoseconds / internal::kNanosecondsPerSecond;
t.tv_nsec = nanoseconds - (t.tv_sec * internal::kNanosecondsPerSecond);
Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason to not use % ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. Done.

@dconeybe dconeybe added tests-requested: quick Trigger a quick set of integration tests. and removed tests: succeeded This PR's integration tests succeeded. labels Aug 5, 2022
@github-actions github-actions bot added tests: in-progress This PR's integration tests are in progress. tests: succeeded This PR's integration tests succeeded. and removed tests-requested: quick Trigger a quick set of integration tests. labels Aug 5, 2022
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Aug 5, 2022

TEST(TimeTests, MsToAbsoluteTimespecTest) {
const timespec t1 = firebase::internal::MsToAbsoluteTimespec(0);
const timespec t2 = firebase::internal::MsToAbsoluteTimespec(10000);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these value test for previous overflow scenarios?

If so a comment saying that this tests for overlfow on 32 bit systems would be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As long as the test gets run on a 32-bit architecture it will detect the overflow. I'm not sure how our GitHub Actions are set up and if they trigger these tests on 32-bit platforms. I've opened a temporary PR #1043 to see if any of the GitHub Actions fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've also added this inline comment to time_test.cc:

This test verifies the fix for the old integer overflow bug on 32-bit architectures: #1042.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've verified the fix using GitHub Actions in #1043

@dconeybe dconeybe merged commit ed0d970 into main Aug 5, 2022
@dconeybe dconeybe deleted the dconeybe/MsToAbsoluteTimespecFix branch August 5, 2022 18:51
@github-actions github-actions bot added the tests: in-progress This PR's integration tests are in progress. label Aug 5, 2022
@github-actions github-actions bot removed the tests: succeeded This PR's integration tests succeeded. label Aug 5, 2022
@github-actions github-actions bot added the tests: succeeded This PR's integration tests succeeded. label Aug 5, 2022
@firebase-workflow-trigger firebase-workflow-trigger bot removed the tests: in-progress This PR's integration tests are in progress. label Aug 5, 2022
@firebase firebase locked and limited conversation to collaborators Sep 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
tests: succeeded This PR's integration tests succeeded.
4 participants