Hello, I was having a bit of a problem with the new monotonic_call() stuff
on some old systems (again, a Kindle 2 w/ a fairly old glibc & kernel duo),
so, inspired from what's done in OpenSSH, I tweaked it to do runtime checks
w/ clock_gettime (and not the syscall, which really didn't play nice for
some reason).

It might not be terribly pretty, but it fixed it for me ;).

[Sorry for the whitespace noise]

----

diff -r 9a48d8bcfeed configure.ac
--- a/configure.ac      Sun Jul 27 23:11:52 2014 +0800
+++ b/configure.ac      Sun Jul 27 23:38:47 2014 +0200
@@ -636,6 +636,9 @@
 
 AC_SEARCH_LIBS(basename, gen, AC_DEFINE(HAVE_BASENAME))
 
+AC_SEARCH_LIBS([clock_gettime], [rt],
+       [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Have clock_gettime])])
+
 # Solaris needs ptmx
 if test -z "$no_ptmx_check" ; then
        if test x"$cross_compiling" = x"no" ; then
diff -r 9a48d8bcfeed dbutil.c
--- a/dbutil.c  Sun Jul 27 23:11:52 2014 +0800
+++ b/dbutil.c  Sun Jul 27 23:38:47 2014 +0200
@@ -1,19 +1,19 @@
 /*
  * Dropbear - a SSH2 server
- * 
+ *
  * Copyright (c) 2002,2003 Matt Johnston
  * All rights reserved.
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -50,12 +50,6 @@
 
 #include "config.h"
 
-#ifdef __linux__
-#define _GNU_SOURCE
-/* To call clock_gettime() directly */
-#include <sys/syscall.h>
-#endif /* __linux */
-
 #ifdef HAVE_MACH_MACH_TIME_H
 #include <mach/mach_time.h>
 #include <mach/mach.h>
@@ -69,9 +63,9 @@
 
 #define MAX_FMT 100
 
-static void generic_dropbear_exit(int exitcode, const char* format, 
+static void generic_dropbear_exit(int exitcode, const char* format,
                va_list param) ATTRIB_NORETURN;
-static void generic_dropbear_log(int priority, const char* format, 
+static void generic_dropbear_log(int priority, const char* format,
                va_list param);
 
 void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
ATTRIB_NORETURN
@@ -111,7 +105,7 @@
        va_end(param);
 }
 
-static void generic_dropbear_exit(int exitcode, const char* format, 
+static void generic_dropbear_exit(int exitcode, const char* format,
                va_list param) {
 
        char fmtbuf[300];
@@ -127,7 +121,7 @@
        dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr);
 }
 
-static void generic_dropbear_log(int UNUSED(priority), const char* format, 
+static void generic_dropbear_log(int UNUSED(priority), const char* format,
                va_list param) {
 
        char printbuf[1024];
@@ -236,7 +230,7 @@
 
 }
 
-/* Listen on address:port. 
+/* Listen on address:port.
  * Special cases are address of "" listening on everything,
  * and address of NULL listening on localhost only.
  * Returns the number of sockets bound on success, or -1 on failure. On
@@ -253,7 +247,7 @@
        int sock;
 
        TRACE(("enter dropbear_listen"))
-       
+
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
        hints.ai_socktype = SOCK_STREAM;
@@ -316,7 +310,7 @@
 #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
                if (res->ai_family == AF_INET6) {
                        int on = 1;
-                       if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 
+                       if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
                                                &on, sizeof(on)) == -1) {
                                dropbear_log(LOG_WARNING, "Couldn't set 
IPV6_V6ONLY");
                        }
@@ -415,7 +409,7 @@
                        int len;
                        len = 100 + strlen(gai_strerror(err));
                        *errstring = (char*)m_malloc(len);
-                       snprintf(*errstring, len, "Error resolving '%s' port 
'%s'. %s", 
+                       snprintf(*errstring, len, "Error resolving '%s' port 
'%s'. %s",
                                        remotehost, remoteport, 
gai_strerror(err));
                }
                TRACE(("Error resolving: %s", gai_strerror(err)))
@@ -614,39 +608,39 @@
 {
        struct sockaddr_storage addr;
        socklen_t addrlen;
-       
+
        if (local_host || local_port) {
                addrlen = sizeof(addr);
                if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
                        dropbear_exit("Failed socket address: %s", 
strerror(errno));
                }
-               getaddrstring(&addr, local_host, local_port, host_lookup);      
        
+               getaddrstring(&addr, local_host, local_port, host_lookup);
        }
        if (remote_host || remote_port) {
                addrlen = sizeof(addr);
                if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) {
                        dropbear_exit("Failed socket address: %s", 
strerror(errno));
                }
-               getaddrstring(&addr, remote_host, remote_port, host_lookup);    
        
+               getaddrstring(&addr, remote_host, remote_port, host_lookup);
        }
 }
 
 /* Return a string representation of the socket address passed. The return
  * value is allocated with malloc() */
-void getaddrstring(struct sockaddr_storage* addr, 
+void getaddrstring(struct sockaddr_storage* addr,
                        char **ret_host, char **ret_port,
                        int host_lookup) {
 
        char host[NI_MAXHOST+1], serv[NI_MAXSERV+1];
        unsigned int len;
        int ret;
-       
+
        int flags = NI_NUMERICSERV | NI_NUMERICHOST;
 
 #ifndef DO_HOST_LOOKUP
        host_lookup = 0;
 #endif
-       
+
        if (host_lookup) {
                flags = NI_NUMERICSERV;
        }
@@ -667,7 +661,7 @@
 #endif
 #endif
 
-       ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1, 
+       ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1,
                        serv, sizeof(serv)-1, flags);
 
        if (ret != 0) {
@@ -727,7 +721,7 @@
        char * ret;
        int len, pos;
        int i;
-       
+
        len = strlen(text);
        ret = m_malloc(len+1);
 
@@ -742,7 +736,7 @@
        ret[pos] = 0x0;
        return ret;
 }
-                       
+
 
 /* reads the contents of filename into the buffer buf, from the current
  * position, either to the end of the file, or the buffer being full.
@@ -759,7 +753,7 @@
        if (fd < 0) {
                goto out;
        }
-       
+
        do {
                maxlen = buf->size - buf->pos;
                len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
@@ -819,7 +813,7 @@
                return DROPBEAR_SUCCESS;
        }
 
-}      
+}
 #endif
 
 /* make sure that the socket closes */
@@ -839,7 +833,7 @@
                dropbear_exit("Error closing fd %d, %s", fd, strerror(errno));
        }
 }
-       
+
 void * m_malloc(size_t size) {
 
        void* ret;
@@ -947,19 +941,34 @@
 
 time_t monotonic_now() {
 
-#if defined(__linux__) && defined(SYS_clock_gettime)
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
        /* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32. Probably cheaper. 
*/
 #ifndef CLOCK_MONOTONIC_COARSE
 #define CLOCK_MONOTONIC_COARSE 6
 #endif
        static clockid_t clock_source = CLOCK_MONOTONIC_COARSE;
        struct timespec ts;
+       static int gettime_coarse_failed = 0;
+       static int gettime_failed = 0;
 
-       if (syscall(SYS_clock_gettime, clock_source, &ts) == EINVAL) {
-               clock_source = CLOCK_MONOTONIC;
-               syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts);
+       /* Try the cheaper CLOCK_MONOTONIC_COARSE first, keeping track of 
failure
to avoid spamming invalid calls... */
+       if (!gettime_coarse_failed) {
+               if (clock_gettime(clock_source, &ts) == 0)
+                       return ts.tv_sec;
+               else {
+                       gettime_coarse_failed = 1;
+                       clock_source = CLOCK_MONOTONIC;
+               }
        }
-       return ts.tv_sec;
+       /* Then try CLOCK_MONOTONIC, keeping track of it too... */
+       if (!gettime_failed) {
+               if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+                       return ts.tv_sec;
+               else
+                       gettime_failed = 1;
+       }
+       /* Fallback to time() (CLOCK_MONOTONIC being defined doesn't ensure 
it'll
actually be supported at runtime...) */
+       return time(NULL);
 #elif defined(HAVE_MACH_ABSOLUTE_TIME)
        /* OS X, see 
https://developer.apple.com/library/mac/qa/qa1398/_index.html */
        static mach_timebase_info_data_t timebase_info;
@@ -968,7 +977,7 @@
        }
        return mach_absolute_time() * timebase_info.numer / timebase_info.denom
                / 1e9;
-#else 
+#else
        /* Fallback for everything else - this will sometimes go backwards */
        return time(NULL);
 #endif


Reply via email to