[RTEMS Project] #4338: rtems_clock_set(): Cannot set future dates later than approximately 2105

RTEMS trac trac at rtems.org
Fri Mar 12 13:52:51 UTC 2021


#4338: rtems_clock_set(): Cannot set future dates later than approximately 2105
-------------------------+-------------------------------------------------
  Reporter:  Frank       |      Owner:  Sebastian Huber
  Kuehndel               |
      Type:  defect      |     Status:  assigned
  Priority:  normal      |  Milestone:  6.1
 Component:  rtems       |    Version:  6
  Severity:  normal      |   Keywords:  rtems_clock_set, 2514,
                         |  _TOD_To_seconds
Blocked By:              |   Blocking:
-------------------------+-------------------------------------------------
 == Short Problem Description ==

 [https://docs.rtems.org/branches/master/c-user/clock/directives.html
 #rtems-clock-set RTEMS Classic API Guide] says:

 > RTEMS can represent time points of this clock in nanoseconds ranging
 from 1988-01-01T00:00:00.000000000Z to 2514-05-31T01:53:03.999999999Z.

 * Yet, years larger than roughly 2105 to 2110 cannot be set
   (or at least the date should be wrong but this never
   occured in my tests).

 > The possible RETURN VALUES are RTEMS_SUCCESSFUL, RTEMS_INVALID_ADDRESS,
 RTEMS_INVALID_CLOCK

 * Yet, rtems_clock_set() can return status RTEMS_INVALID_NUMBER, too.
   (Only for such dates in the far future.)

 == How To Replicate? ==

 Call rtems_clock_set() with this time_of-day:
 {
   year = 2514,
   month = 5,
   day = 31,
   hour = 1,
   minute = 53,
   second = 3,
   ticks = 995
 }
 The return value will be RTEMS_INVALID_NUMBER.

 == Bugs in _TOD_To_seconds() ==

 cpukit/rtems/src/clockset.c: rtems_clock_set() calls

 * cpukit/rtems/src/clocktodvalidate.c: _TOD_Validate() and
 * cpukit/rtems/src/clocktodtoseconds.c: _TOD_To_seconds() and
 * cpukit/score/src/coretodset.c: _TOD_Set()

 First issue:

 _TOD_To_seconds() converts the time_of_day structure into seconds using a
 variable `time` of type `uint32_t`. This simply overflows when in comes
 close to year 2110.

 Debugger output at the end of _TOD_To_seconds():

 {{{
 (gdb) print the_tod->year
 $16 = 2104
 (gdb) print time
 $17 = 4233686400
 }}}

 with a higher year:

 {{{
 (gdb) print the_tod->year
 $28 = 2514
 (gdb) print *the_tod
 $31 = {
   year = 2514,
   month = 5,
   day = 31,
   hour = 1,
   minute = 53,
   second = 3,
   ticks = 995
 }
 (gdb) print time
 $29 = 192272
 }}}

 Second issue:

 _TOD_To_seconds() can (most likely) not handle the leap year issues of the
 years 2200, 2300, 2400, 2500 because it has dedicated code for the 2100
 case only:

 {{{
   /* The year 2100 is not a leap year */
   if ( time
       >= (TOD_SECONDS_AT_2100_03_01_00_00 -
 TOD_SECONDS_1970_THROUGH_1988)) {
     time -= TOD_SECONDS_PER_DAY;
   }
 }}}


 == _TOD_Check_time_of_day_and_run_hooks() causes STATUS_INVALID_NUMBER ==

 cpukit/score/src/coretodset.c: _TOD_Set() calls

 * cpukit/score/src/coretodset.c:
   _TOD_Check_time_of_day_and_run_hooks()

 in this code snippet (note `return status`):

 {{{
   status = _TOD_Check_time_of_day_and_run_hooks( tod );
   if ( status != STATUS_SUCCESSFUL ) {
     _TOD_Release( lock_context );
     return status;
   }
 }}}

 _TOD_Check_time_of_day_and_run_hooks( tod ) can return status
 STATUS_INVALID_NUMBER which is not documented for rtems_clock_set(). The
 small time in seconds value 192272 from the integer overrun discussed
 above triggers the middle `if` clause:

 {{{
 static Status_Control _TOD_Check_time_of_day_and_run_hooks(
   const struct timespec *tod
 )
 {
   if ( !_Watchdog_Is_valid_timespec( tod ) ) {
     return STATUS_INVALID_NUMBER;
   }

   if ( tod->tv_sec < TOD_SECONDS_1970_THROUGH_1988 ) {
     return STATUS_INVALID_NUMBER;
   }

   if ( _Watchdog_Is_far_future_timespec( tod ) ) {
     return STATUS_INVALID_NUMBER;
   }

   return _TOD_Hook_Run( TOD_ACTION_SET_CLOCK, tod );
 }
 }}}

 == Final Notes ==

 * I found #2665 and #2548 but I do not say these are relevant here.
 * `#define WATCHDOG_MAX_SECONDS 0x3ffffffff` in
 cpukit/include/rtems/score/watchdogimpl.h covers 17179869183 seconds which
 are some 544 years
 * _TOD_Check_time_of_day_and_run_hooks() seems to be only used by
 _TOD_Set() but _TOD_Set() has three users.
 * I did not check whether the invers conversation (rtems_clock_get_tod())
 works for dates which are centuries in the future.

--
Ticket URL: <http://devel.rtems.org/ticket/4338>
RTEMS Project <http://www.rtems.org/>
RTEMS Project


More information about the bugs mailing list