If the RTC is in use by another process or if the dev interface
is not properly established, calling rtc_xopen will fail.
However, hwclock does not verify the return value of rtc_xopen
before using it.  This causes hwclock to hang indefintely when
it attempts to open a bad file descriptor.  Future calls to
hwclock will then fail, thus making it impossible to read or
set the RTC until the system is rebooted.

Similarly, the returned pointer of ctime and localtime was
being used without checking if the pointer was valid.  One of
these calls was causing a call to hwclock to enter an
uninterruptable sleep when the invalid hwclock access occurred.

The problem can be reproduced by running two instances of the
following shell script:

 #!/bin/sh
 while [ 1 ]; do
   /sbin/hwclock -w -u
   sleep 1;
 done

This patch verifies the RTC file descriptor is valid before it
is used, and it switches all ctime and localtime calls to
ctime_r localtime_r respectively.  Before applying the patch,
running the previously described test resulted in one instance
of the script to hang with hwclock in an uninterruptable sleep
within seconds of starting both scripts.  After the patch, ran
two instances of the scripts for ten minutes without permanently
blocking access to the RTC.

Signed-off-by: Bryan Evenson <[email protected]>
---
 util-linux/hwclock.c |   22 +++++++++++++++-------
 util-linux/rtcwake.c |    2 ++
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index 379eeb2..1aa3b3a 100644
--- a/util-linux/hwclock.c
+++ b/util-linux/hwclock.c
@@ -34,6 +34,8 @@ static time_t read_rtc(const char **pp_rtcname, struct 
timeval *sys_tv, int utc)
        int fd;
 
        fd = rtc_xopen(pp_rtcname, O_RDONLY);
+       if(fd < 0)
+               return 0;
 
        rtc_read_tm(&tm_time, fd);
 
@@ -62,13 +64,14 @@ static void show_clock(const char **pp_rtcname, int utc)
 #endif
        time_t t = read_rtc(pp_rtcname, &sys_tv, utc);
 
+       char cp[64];
 #if ENABLE_LOCALE_SUPPORT
        /* Standard hwclock uses locale-specific output format */
-       char cp[64];
-       struct tm *ptm = localtime(&t);
-       strftime(cp, sizeof(cp), "%c", ptm);
+       struct tm tm_time;
+       localtime_r(&t, &tm_time);
+       strftime(cp, sizeof(cp), "%c", &tm_time);
 #else
-       char *cp = ctime(&t);
+       ctime_r(&t, cp);
        strchrnul(cp, '\n')[0] = '\0';
 #endif
 
@@ -114,6 +117,9 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
        int rtc;
 
        rtc = rtc_xopen(pp_rtcname, O_WRONLY);
+       if(rtc < 0)
+               return;
+
        gettimeofday(&tv, NULL);
        /* Prepare tm_time */
        if (sizeof(time_t) == sizeof(tv.tv_sec)) {
@@ -156,6 +162,8 @@ static void from_sys_clock(const char **pp_rtcname, int utc)
        struct tm tm_time;
        struct timeval tv;
        int rtc = rtc_xopen(pp_rtcname, O_WRONLY);
+       if(rtc < 0)
+               return;
 
        /* Try to catch the moment when whole second is close */
        while (1) {
@@ -242,13 +250,13 @@ static void from_sys_clock(const char **pp_rtcname, int 
utc)
 static void set_system_clock_timezone(int utc)
 {
        struct timeval tv;
-       struct tm *broken;
+       struct tm broken;
        struct timezone tz;
 
        gettimeofday(&tv, NULL);
-       broken = localtime(&tv.tv_sec);
+       localtime_r(&tv.tv_sec, &broken);
        tz.tz_minuteswest = timezone / 60;
-       if (broken->tm_isdst)
+       if (broken.tm_isdst)
                tz.tz_minuteswest -= 60;
        tz.tz_dsttime = 0;
        gettimeofday(&tv, NULL);
diff --git a/util-linux/rtcwake.c b/util-linux/rtcwake.c
index 735a298..40bf2cc 100644
--- a/util-linux/rtcwake.c
+++ b/util-linux/rtcwake.c
@@ -176,6 +176,8 @@ int rtcwake_main(int argc UNUSED_PARAM, char **argv)
 
        /* this RTC must exist and (if we'll sleep) be wakeup-enabled */
        fd = rtc_xopen(&rtcname, O_RDONLY);
+       if(fd < 0)
+               return EXIT_FAILURE;
 
        if (strcmp(suspend, "on") && !may_wakeup(rtcname))
                bb_error_msg_and_die("%s not enabled for wakeup events", 
rtcname);
-- 
1.7.9.5

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to