]> granicus.if.org Git - sudo/commitdiff
Use btime in /proc/stat to determine system start time instead of
authorTodd C. Miller <Todd.Miller@sudo.ws>
Wed, 4 Apr 2018 17:28:53 +0000 (11:28 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Wed, 4 Apr 2018 17:28:53 +0000 (11:28 -0600)
/proc/uptime.  Fixes the process start time test when run from a
container where /proc/uptime is the uptime of the container but the
process start time is relative to the host system boot time.
Bug #829

plugins/sudoers/regress/starttime/check_starttime.c

index 4bcdde89192ac6531689710d20b084f5e38a539b..15dd1f7bf3e412e0ec16712c30238868a8781c11 100644 (file)
 #include <config.h>
 
 #include <sys/types.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <time.h>
 #include <unistd.h>
 
 #include "sudo_fatal.h"
 #include "check.h"
 
+#ifndef TIME_T_MAX
+# if SIZEOF_TIME_T == 8
+#  define TIME_T_MAX    LLONG_MAX
+# else
+#  define TIME_T_MAX    INT_MAX
+# endif
+#endif
+
 __dso_public int main(int argc, char *argv[]);
 
 #ifdef __linux__
 static int
 get_now(struct timespec *now)
 {
-    int ret = -1;
+    const char *errstr;
     char buf[1024];
+    time_t seconds;
+    int ret = -1;
     FILE *fp;
 
     /* Linux process start time is relative to boot time. */
-    fp = fopen("/proc/uptime", "r");
+    fp = fopen("/proc/stat", "r");
     if (fp != NULL) {
-       if (fgets(buf, sizeof(buf), fp) != NULL) {
-           char *ep;
-           double uptime = strtod(buf, &ep);
-           if (*ep == ' ') {
-               now->tv_sec = (time_t)uptime;
-               now->tv_nsec = (uptime - (time_t)uptime) * 1000000000;
-               ret = 0;
-           }
+       while (fgets(buf, sizeof(buf), fp) != NULL) {
+           if (strncmp(buf, "btime ", 6) != 0)
+               continue;
+           buf[strcspn(buf, "\n")] = '\0';
+
+           /* Boot time is in seconds since the epoch. */
+           seconds = strtonum(buf + 6, 0, TIME_T_MAX, &errstr);
+           if (errstr != NULL)
+               return -1;
+
+           /* Instead of the real time, "now" is relative to boot time. */
+           if (sudo_gettime_real(now) == -1)
+               return -1;
+           now->tv_sec -= seconds;
+           ret = 0;
+           break;
        }
        fclose(fp);
     }