* [PATCH 0/4] Refactor timespec to microsecond conversion
@ 2020-03-02 21:28 Ossama Othman
2020-03-02 21:28 ` [PATCH 1/4] time: Add timespec to microseconds converter Ossama Othman
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Ossama Othman @ 2020-03-02 21:28 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 1263 bytes --]
An integer overflow fix for a timespec to microsecond conversion in
l_path_get_mtime() was previously committed but two overflows could
still occur: (1) the multiplication in the seconds (tv_sec) to
microsecond conversion could still exceed UINT64_MAX, and (2) addition
of the microseconds obtained from the nanoseconds (tv_nsec) member
could also result in a sum that exceeds UINT64_MAX.
This set of patches refactors the timespec to microsecond to a new
l_timespec_to_usecs() function that checks for overflow in both of the
cases mentioned above. The l_path_get_mtime() function now uses
l_timespec_to_usecs() to address the remaining potential integer
overflows. A potential integer overflow in the l_time_now() function
was corrected in a similar manner.
Ossama Othman (4):
time: Add timespec to microseconds converter
unit: Add l_timespec_to_usecs() unit test.
time: Use l_timespec_to_usecs() to avoid overflow.
path: Use l_timespec_to_usecs() to avoid overflow.
ell/ell.sym | 1 +
ell/path.c | 3 +--
ell/time.c | 26 +++++++++++++++++++++++++-
ell/time.h | 3 +++
unit/test-time.c | 34 ++++++++++++++++++++++++++++++++++
5 files changed, 64 insertions(+), 3 deletions(-)
--
2.20.1
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/4] time: Add timespec to microseconds converter
2020-03-02 21:28 [PATCH 0/4] Refactor timespec to microsecond conversion Ossama Othman
@ 2020-03-02 21:28 ` Ossama Othman
2020-03-02 21:34 ` Denis Kenzior
2020-03-02 21:28 ` [PATCH 2/4] unit: Add l_timespec_to_usecs() unit test Ossama Othman
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Ossama Othman @ 2020-03-02 21:28 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 1931 bytes --]
Implement a new function, l_timespec_to_usecs(), that checks for
integer overflow in the multiplication and addition operations that
occur during the conversion of the timespec members to microseconds.
---
ell/ell.sym | 1 +
ell/time.c | 24 ++++++++++++++++++++++++
ell/time.h | 3 +++
3 files changed, 28 insertions(+)
diff --git a/ell/ell.sym b/ell/ell.sym
index 0c83b87..776a94c 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -526,6 +526,7 @@ global:
l_ecdh_generate_key_pair;
l_ecdh_generate_shared_secret;
/* time */
+ l_timespec_to_usecs;
l_time_now;
/* gpio */
l_gpio_chips_with_line_label;
diff --git a/ell/time.c b/ell/time.c
index 6150d03..becf985 100644
--- a/ell/time.c
+++ b/ell/time.c
@@ -30,6 +30,30 @@
#include "time.h"
#include "private.h"
+/**
+ * l_timespec_to_usecs() - convert timespec value to microseconds
+ * @t: pointer to timespec value to be converted to microseconds.
+ *
+ * Convert the timespec value @t to microseconds, being careful to
+ * avoid integer overflows during the conversion.
+ *
+ * Return: Number of microseconds in @t, UINT64_MAX on overflow, and
+ * zero if @t is NULL.
+ */
+LIB_EXPORT uint64_t l_timespec_to_usecs(const struct timespec *t)
+{
+ if (!t)
+ return 0;
+
+ uint64_t usecs = t->tv_sec * L_USEC_PER_SEC;
+
+ /* check overflow */
+ if (usecs / L_USEC_PER_SEC != t->tv_sec)
+ return UINT64_MAX;
+
+ return l_time_offset(usecs, t->tv_nsec / L_NSEC_PER_USEC);
+}
+
/**
* l_time_now:
*
diff --git a/ell/time.h b/ell/time.h
index 6976280..6011b80 100644
--- a/ell/time.h
+++ b/ell/time.h
@@ -38,6 +38,9 @@ extern "C" {
#define L_NSEC_PER_USEC 1000ULL
#define L_TIME_INVALID ((uint64_t) -1)
+struct timespec;
+
+uint64_t l_timespec_to_usecs(const struct timespec *t);
uint64_t l_time_now(void);
static inline bool l_time_after(uint64_t a, uint64_t b)
--
2.20.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/4] unit: Add l_timespec_to_usecs() unit test.
2020-03-02 21:28 [PATCH 0/4] Refactor timespec to microsecond conversion Ossama Othman
2020-03-02 21:28 ` [PATCH 1/4] time: Add timespec to microseconds converter Ossama Othman
@ 2020-03-02 21:28 ` Ossama Othman
2020-03-02 21:40 ` Denis Kenzior
2020-03-02 21:28 ` [PATCH 3/4] time: Use l_timespec_to_usecs() to avoid overflow Ossama Othman
2020-03-02 21:28 ` [PATCH 4/4] path: " Ossama Othman
3 siblings, 1 reply; 10+ messages in thread
From: Ossama Othman @ 2020-03-02 21:28 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 1710 bytes --]
---
unit/test-time.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/unit/test-time.c b/unit/test-time.c
index 1301891..3c8fd0d 100644
--- a/unit/test-time.c
+++ b/unit/test-time.c
@@ -25,6 +25,7 @@
#endif
#include <assert.h>
+#include <limits.h>
#include <ell/ell.h>
@@ -49,12 +50,45 @@ static void test_offset(const void *data)
assert(l_time_offset(max_minus, 1001) == UINT64_MAX);
}
+static void test_timespec_to_usecs(const void *data)
+{
+ static const time_t max_secs =
+ sizeof(time_t) == 4 ? UINT32_MAX : UINT64_MAX;
+ static const long max_nsecs = LONG_MAX;
+
+ static const time_t secs = 2000;
+ static const long nsecs = 1001;
+
+ /* force integer multiplication overflow */
+ static const struct timespec t_max_secs = { .tv_sec = max_secs };
+
+ /* force integer addition overflow */
+ static const struct timespec t_max_nsecs = {
+ .tv_sec = (max_secs / L_USEC_PER_SEC) - 1,
+ .tv_nsec = max_nsecs
+ };
+
+ static const struct timespec t = {
+ .tv_sec = secs,
+ .tv_nsec = nsecs
+ };
+
+ uint64_t usecs = t.tv_sec * L_USEC_PER_SEC +
+ t.tv_nsec / L_NSEC_PER_USEC;
+
+ assert(l_timespec_to_usecs(&t_max_secs) == UINT64_MAX);
+ assert(l_timespec_to_usecs(&t_max_nsecs) == UINT64_MAX);
+ assert(l_timespec_to_usecs(&t) == usecs);
+ assert(l_timespec_to_usecs(NULL) == 0);
+}
+
int main(int argc, char *argv[])
{
l_test_init(&argc, &argv);
l_test_add("Test before/after/diff", test_before_after_diff, NULL);
l_test_add("Test offset", test_offset, NULL);
+ l_test_add("Test timespec to usecs", test_timespec_to_usecs, NULL);
return l_test_run();
}
--
2.20.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] time: Use l_timespec_to_usecs() to avoid overflow.
2020-03-02 21:28 [PATCH 0/4] Refactor timespec to microsecond conversion Ossama Othman
2020-03-02 21:28 ` [PATCH 1/4] time: Add timespec to microseconds converter Ossama Othman
2020-03-02 21:28 ` [PATCH 2/4] unit: Add l_timespec_to_usecs() unit test Ossama Othman
@ 2020-03-02 21:28 ` Ossama Othman
2020-03-02 21:44 ` Denis Kenzior
2020-03-02 21:28 ` [PATCH 4/4] path: " Ossama Othman
3 siblings, 1 reply; 10+ messages in thread
From: Ossama Othman @ 2020-03-02 21:28 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 398 bytes --]
---
ell/time.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ell/time.c b/ell/time.c
index becf985..3bf75e6 100644
--- a/ell/time.c
+++ b/ell/time.c
@@ -67,7 +67,7 @@ LIB_EXPORT uint64_t l_time_now(void)
clock_gettime(CLOCK_BOOTTIME, &now);
- return now.tv_sec * 1000000 + now.tv_nsec / 1000;
+ return l_timespec_to_usecs(&now);
}
/**
--
2.20.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] path: Use l_timespec_to_usecs() to avoid overflow.
2020-03-02 21:28 [PATCH 0/4] Refactor timespec to microsecond conversion Ossama Othman
` (2 preceding siblings ...)
2020-03-02 21:28 ` [PATCH 3/4] time: Use l_timespec_to_usecs() to avoid overflow Ossama Othman
@ 2020-03-02 21:28 ` Ossama Othman
2020-03-02 21:50 ` Denis Kenzior
3 siblings, 1 reply; 10+ messages in thread
From: Ossama Othman @ 2020-03-02 21:28 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 456 bytes --]
---
ell/path.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/ell/path.c b/ell/path.c
index df5a703..e911c01 100644
--- a/ell/path.c
+++ b/ell/path.c
@@ -162,8 +162,7 @@ LIB_EXPORT uint64_t l_path_get_mtime(const char *path)
if (ret < 0)
return L_TIME_INVALID;
- return (uint64_t) sb.st_mtim.tv_sec * 1000000 +
- sb.st_mtim.tv_nsec / 1000;
+ return l_timespec_to_usecs(&sb.st_mtim);
}
/**
--
2.20.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/4] time: Add timespec to microseconds converter
2020-03-02 21:28 ` [PATCH 1/4] time: Add timespec to microseconds converter Ossama Othman
@ 2020-03-02 21:34 ` Denis Kenzior
0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2020-03-02 21:34 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 2779 bytes --]
Hi Ossama,
On 3/2/20 3:28 PM, Ossama Othman wrote:
> Implement a new function, l_timespec_to_usecs(), that checks for
> integer overflow in the multiplication and addition operations that
> occur during the conversion of the timespec members to microseconds.
> ---
> ell/ell.sym | 1 +
> ell/time.c | 24 ++++++++++++++++++++++++
> ell/time.h | 3 +++
> 3 files changed, 28 insertions(+)
ell/time.c: In function ‘l_timespec_to_usecs’:
ell/time.c:48:2: error: ISO C90 forbids mixed declarations and code
[-Werror=declaration-after-statement]
48 | uint64_t usecs = t->tv_sec * L_USEC_PER_SEC;
| ^~~~~~~~
ell/time.c:51:29: error: comparison of integer expressions of different
signedness: ‘long long unsigned int’ and ‘__time_t’ {aka ‘const long
int’} [-Werror=sign-compare]
51 | if (usecs / L_USEC_PER_SEC != t->tv_sec)
| ^~
cc1: all warnings being treated as errors
>
> diff --git a/ell/ell.sym b/ell/ell.sym
> index 0c83b87..776a94c 100644
> --- a/ell/ell.sym
> +++ b/ell/ell.sym
> @@ -526,6 +526,7 @@ global:
> l_ecdh_generate_key_pair;
> l_ecdh_generate_shared_secret;
> /* time */
> + l_timespec_to_usecs;
> l_time_now;
> /* gpio */
> l_gpio_chips_with_line_label;
> diff --git a/ell/time.c b/ell/time.c
> index 6150d03..becf985 100644
> --- a/ell/time.c
> +++ b/ell/time.c
> @@ -30,6 +30,30 @@
> #include "time.h"
> #include "private.h"
>
> +/**
> + * l_timespec_to_usecs() - convert timespec value to microseconds
> + * @t: pointer to timespec value to be converted to microseconds.
> + *
> + * Convert the timespec value @t to microseconds, being careful to
> + * avoid integer overflows during the conversion.
> + *
> + * Return: Number of microseconds in @t, UINT64_MAX on overflow, and
> + * zero if @t is NULL.
> + */
> +LIB_EXPORT uint64_t l_timespec_to_usecs(const struct timespec *t)
> +{
> + if (!t)
> + return 0;
> +
> + uint64_t usecs = t->tv_sec * L_USEC_PER_SEC;
> +
> + /* check overflow */
> + if (usecs / L_USEC_PER_SEC != t->tv_sec)
There has to be a better way than this division...
> + return UINT64_MAX;
> +
> + return l_time_offset(usecs, t->tv_nsec / L_NSEC_PER_USEC);
> +}
> +
> /**
> * l_time_now:
> *
> diff --git a/ell/time.h b/ell/time.h
> index 6976280..6011b80 100644
> --- a/ell/time.h
> +++ b/ell/time.h
> @@ -38,6 +38,9 @@ extern "C" {
> #define L_NSEC_PER_USEC 1000ULL
> #define L_TIME_INVALID ((uint64_t) -1)
>
> +struct timespec;
> +
> +uint64_t l_timespec_to_usecs(const struct timespec *t);
> uint64_t l_time_now(void);
>
> static inline bool l_time_after(uint64_t a, uint64_t b)
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 2/4] unit: Add l_timespec_to_usecs() unit test.
2020-03-02 21:28 ` [PATCH 2/4] unit: Add l_timespec_to_usecs() unit test Ossama Othman
@ 2020-03-02 21:40 ` Denis Kenzior
0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2020-03-02 21:40 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 1970 bytes --]
Hi Ossama,
On 3/2/20 3:28 PM, Ossama Othman wrote:
> ---
> unit/test-time.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/unit/test-time.c b/unit/test-time.c
> index 1301891..3c8fd0d 100644
> --- a/unit/test-time.c
> +++ b/unit/test-time.c
> @@ -25,6 +25,7 @@
> #endif
>
> #include <assert.h>
> +#include <limits.h>
>
> #include <ell/ell.h>
>
> @@ -49,12 +50,45 @@ static void test_offset(const void *data)
> assert(l_time_offset(max_minus, 1001) == UINT64_MAX);
> }
>
> +static void test_timespec_to_usecs(const void *data)
> +{
> + static const time_t max_secs =
> + sizeof(time_t) == 4 ? UINT32_MAX : UINT64_MAX;
> + static const long max_nsecs = LONG_MAX;
The maximum is 999 999 999. man clock_gettime
> +
> + static const time_t secs = 2000;
> + static const long nsecs = 1001;
> +
> + /* force integer multiplication overflow */
> + static const struct timespec t_max_secs = { .tv_sec = max_secs };
> +
> + /* force integer addition overflow */
> + static const struct timespec t_max_nsecs = {
> + .tv_sec = (max_secs / L_USEC_PER_SEC) - 1,
> + .tv_nsec = max_nsecs
> + };
> +
> + static const struct timespec t = {
> + .tv_sec = secs,
> + .tv_nsec = nsecs
> + };
> +
> + uint64_t usecs = t.tv_sec * L_USEC_PER_SEC +
> + t.tv_nsec / L_NSEC_PER_USEC;
> +
> + assert(l_timespec_to_usecs(&t_max_secs) == UINT64_MAX);
> + assert(l_timespec_to_usecs(&t_max_nsecs) == UINT64_MAX);
> + assert(l_timespec_to_usecs(&t) == usecs);
> + assert(l_timespec_to_usecs(NULL) == 0);
> +}
> +
> int main(int argc, char *argv[])
> {
> l_test_init(&argc, &argv);
>
> l_test_add("Test before/after/diff", test_before_after_diff, NULL);
> l_test_add("Test offset", test_offset, NULL);
> + l_test_add("Test timespec to usecs", test_timespec_to_usecs, NULL);
>
> return l_test_run();
> }
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/4] time: Use l_timespec_to_usecs() to avoid overflow.
2020-03-02 21:28 ` [PATCH 3/4] time: Use l_timespec_to_usecs() to avoid overflow Ossama Othman
@ 2020-03-02 21:44 ` Denis Kenzior
0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2020-03-02 21:44 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 672 bytes --]
Hi Ossama,
On 3/2/20 3:28 PM, Ossama Othman wrote:
> ---
> ell/time.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/ell/time.c b/ell/time.c
> index becf985..3bf75e6 100644
> --- a/ell/time.c
> +++ b/ell/time.c
> @@ -67,7 +67,7 @@ LIB_EXPORT uint64_t l_time_now(void)
>
> clock_gettime(CLOCK_BOOTTIME, &now);
>
> - return now.tv_sec * 1000000 + now.tv_nsec / 1000;
> + return l_timespec_to_usecs(&now);
This is time since boot, so I sincerely doubt we want to care about 68+
year uptimes.
It might be worthwhile to use ULL constants though just to be pedantic.
> }
>
> /**
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] path: Use l_timespec_to_usecs() to avoid overflow.
2020-03-02 21:28 ` [PATCH 4/4] path: " Ossama Othman
@ 2020-03-02 21:50 ` Denis Kenzior
2020-03-02 23:13 ` Othman, Ossama
0 siblings, 1 reply; 10+ messages in thread
From: Denis Kenzior @ 2020-03-02 21:50 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 911 bytes --]
Hi Ossama,
On 3/2/20 3:28 PM, Ossama Othman wrote:
> ---
> ell/path.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/ell/path.c b/ell/path.c
> index df5a703..e911c01 100644
> --- a/ell/path.c
> +++ b/ell/path.c
> @@ -162,8 +162,7 @@ LIB_EXPORT uint64_t l_path_get_mtime(const char *path)
> if (ret < 0)
> return L_TIME_INVALID;
>
> - return (uint64_t) sb.st_mtim.tv_sec * 1000000 +
> - sb.st_mtim.tv_nsec / 1000;
> + return l_timespec_to_usecs(&sb.st_mtim);
So while theoretically possible to overflow, this is _highly_ unlikely.
I think we are looking at 35-36 bits of sec info, which is 1-2 thousand
years in the future.
I guess I'm ok if we try and deal with overflow just in case someone is
setting some really large mtime values as long as l_timespec_to_usecs
isn't overly expensive.
> }
>
> /**
>
Regards,
-Denis
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] path: Use l_timespec_to_usecs() to avoid overflow.
2020-03-02 21:50 ` Denis Kenzior
@ 2020-03-02 23:13 ` Othman, Ossama
0 siblings, 0 replies; 10+ messages in thread
From: Othman, Ossama @ 2020-03-02 23:13 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 590 bytes --]
Hi Denis,
On Mon, Mar 2, 2020 at 2:06 PM Denis Kenzior <denkenz@gmail.com> wrote:
> So while theoretically possible to overflow, this is _highly_ unlikely.
> I think we are looking at 35-36 bits of sec info, which is 1-2 thousand
> years in the future.
That's a good point.
> I guess I'm ok if we try and deal with overflow just in case someone is
> setting some really large mtime values as long as l_timespec_to_usecs
> isn't overly expensive.
As you point out that the overflows are highly unlikely to occur, I'm
fine with dropping my patches.
Thanks Denis!
-Ossama
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2020-03-02 23:13 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-02 21:28 [PATCH 0/4] Refactor timespec to microsecond conversion Ossama Othman
2020-03-02 21:28 ` [PATCH 1/4] time: Add timespec to microseconds converter Ossama Othman
2020-03-02 21:34 ` Denis Kenzior
2020-03-02 21:28 ` [PATCH 2/4] unit: Add l_timespec_to_usecs() unit test Ossama Othman
2020-03-02 21:40 ` Denis Kenzior
2020-03-02 21:28 ` [PATCH 3/4] time: Use l_timespec_to_usecs() to avoid overflow Ossama Othman
2020-03-02 21:44 ` Denis Kenzior
2020-03-02 21:28 ` [PATCH 4/4] path: " Ossama Othman
2020-03-02 21:50 ` Denis Kenzior
2020-03-02 23:13 ` Othman, Ossama
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.