Print this page
5375 utmpd(1M) core dumps when WTMPX_UPDATE_FREQ is zero

@@ -17,11 +17,11 @@
  * information: Portions Copyright [yyyy] [name of copyright owner]
  *
  * CDDL HEADER END
  */
 /*
- * Copyright 2014 Shruti V Sampat <shrutisampat@gmail.com>
+ * Copyright 2014, 2015 Shruti V Sampat <shrutisampat@gmail.com>
  */
 
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.

@@ -76,10 +76,11 @@
 #include        <string.h>
 #include        <poll.h>
 #include        <deflt.h>
 #include        <procfs.h>
 #include        <sys/resource.h>
+#include        <limits.h>
 
 #define dprintf(x)      if (Debug) (void) printf x
 
 /*
  * Memory allocation keyed off MAX_FDS

@@ -174,10 +175,13 @@
 static void nonfatal();         /* Prints error message */
 static void print_tables();     /* Prints out internal tables for Debug */
 static int proc_is_alive(pid_t pid);    /* Check if a process is alive */
 static void warn_utmp(void);
 
+/* Validate defaults from file and assign */
+static int validate_default(char *defp, int *flag);
+
 /*
  * main()  - Main does basic setup and calls wait_for_pids() to do the work
  */
 
 int

@@ -185,10 +189,11 @@
 {
         char *defp;
         struct rlimit rlim;
         int i;
         time_t curtime, now;
+        char msg[256];
 
         prog_name = argv[0];                    /* Save invocation name */
 
         if (getuid() != 0)  {
                 (void) fprintf(stderr,

@@ -208,32 +213,44 @@
                         exit(2);
                 }
         }
 
         /*
-         * Read defaults file for poll timeout
+         * Read defaults file for poll timeout, WTMPX update frequency
+         * and maximum number of processes to monitor.
          */
         if (defopen(UTMP_DEFAULT) == 0) {
-                if ((defp = defread("SCAN_PERIOD=")) != NULL) {
-                        Poll_timeout = atol(defp);
-                        dprintf(("Poll timeout set to %d\n", Poll_timeout));
+                if ((defp = defread("SCAN_PERIOD=")) != NULL)
+                        if (validate_default(defp, &Poll_timeout) == -1) {
+                                (void) snprintf(msg, sizeof (msg), "SCAN_PERIOD"
+                                    " should be a positive integer, found %s",
+                                    defp);
+                                nonfatal(msg);
                 }
+                dprintf(("Poll timeout set to %d\n", Poll_timeout));
 
-                if ((defp = defread("WTMPX_UPDATE_FREQ=")) != NULL) {
-                        WTMPX_ufreq = atol(defp);
-                        dprintf(("WTMPX update frequency set to %d\n",
-                            WTMPX_ufreq));
+                if ((defp = defread("WTMPX_UPDATE_FREQ=")) != NULL)
+                        if (validate_default(defp, &WTMPX_ufreq) == -1) {
+                                (void) snprintf(msg, sizeof (msg),
+                                    "WTMPX_UPDATE_FREQ should be a positive "
+                                    "integer, found %s", defp);
+                                nonfatal(msg);
                 }
+                dprintf(("WTMPX update frequency set to %d\n", WTMPX_ufreq));
 
                 /*
                  * Paranoia - if polling on large number of FDs is expensive /
                  * buggy the number can be set lower in the field.
                  */
-                if ((defp = defread("MAX_FDS=")) != NULL) {
-                        Max_fds = atol(defp);
-                        dprintf(("Max_fds set to %d\n", Max_fds));
+                if ((defp = defread("MAX_FDS=")) != NULL)
+                        if (validate_default(defp, &Max_fds) == -1) {
+                                (void) snprintf(msg, sizeof (msg), "MAX_FDS "
+                                    "should be a positive integer, found %s",
+                                    defp);
+                                nonfatal(msg);
                 }
+                dprintf(("Max fds set to %d\n", Max_fds));
                 (void) defopen((char *)NULL);
         }
 
         if (Debug == 0) {
                 /*

@@ -279,11 +296,11 @@
                 fatal("getrlimit returned failure");
 
         (void) enable_extended_FILE_stdio(-1, -1);
 
         if ((WTMPXfd = open(WTMPX_FILE, O_RDONLY)) < 0)
-                nonfatal("WARNING: unable to open " WTMPX_FILE "for update.");
+                nonfatal("WARNING: unable to open " WTMPX_FILE " for update.");
 
         /*
          * Loop here scanning the utmpx file and waiting for processes
          * to terminate.  Most of the activity is directed out of wait_for_pids.
          * If wait_for_pids fails we reload the table and try again.

@@ -680,12 +697,11 @@
  * add_pid      - add a pid to the fd table and the pidtable.
  *                these tables are sorted tables for quick lookups.
  *
  */
 static void
-add_pid(pid)
-        pid_t pid;
+add_pid(pid_t pid)
 {
         int fd = 0;
         int i = 0, move_amt;
         int j;
         static int first_time = 1;

@@ -767,17 +783,20 @@
 
 /*
  * rem_pid      - Remove an entry from the table and check to see if its
  *                not in the utmpx file.
  *                If i != -1 don't look up the pid, use i as index
+ *
+ * pid          - Pid of process to clean or 0 if we don't know it
+ *
+ * i            - Index into table or -1 if we need to look it up
+ *
+ * clean_it     - Clean the entry, or just remove from table?
  */
 
 static void
-rem_pid(pid, i, clean_it)
-        pid_t pid;      /* Pid of process to clean or 0 if we don't know it */
-        int i;          /* Index into table or -1 if we need to look it up */
-        int clean_it;   /* Clean the entry, or just remove from table? */
+rem_pid(pid_t pid, int i, int clean_it)
 {
         int move_amt;
 
         dprintf(("  rem_pid: pid = %d i = %d", (int)pid, i));
 

@@ -821,13 +840,11 @@
  * find_pid     - Returns an index into the pidtable of the specifed pid,
  *                else -1 if not found
  */
 
 static int
-find_pid(pid, i)
-        pid_t pid;
-        int *i;
+find_pid(pid_t pid, int *i)
 {
         struct pidentry pe;
         struct pidentry *p;
 
         pe.pl_pid = pid;

@@ -845,12 +862,11 @@
 /*
  * Pidcmp - Used by besearch for sorting and finding  process IDs.
  */
 
 static int
-pidcmp(a, b)
-        struct pidentry *a, *b;
+pidcmp(struct pidentry *a, struct pidentry *b)
 {
         if (b == NULL || a == NULL)
                 return (0);
         return (a->pl_pid - b->pl_pid);
 }

@@ -859,12 +875,11 @@
 /*
  * proc_to_fd   - Take a process ID and return an open file descriptor to the
  *                /proc file for the specified process.
  */
 static int
-proc_to_fd(pid)
-        pid_t pid;
+proc_to_fd(pid_t pid)
 {
         char procname[64];
         int fd, dfd;
 
         (void) sprintf(procname, "/proc/%d/psinfo", (int)pid);

@@ -909,12 +924,11 @@
 /*
  * Clean_entry  - Cleans the specified entry - where i is an index
  *                into the pid_table.
  */
 static void
-clean_entry(i)
-        int i;
+clean_entry(int i)
 {
         struct utmpx *u;
 
         if (pidcnt == 0)
                 return;

@@ -923,11 +937,11 @@
 
         /*
          * Double check if the process is dead.
          */
         if (proc_is_alive(pidtable[i].pl_pid)) {
-                dprintf(("      Bad attempt to clean %d\n", \
+                dprintf(("      Bad attempt to clean %d\n",
                         (int)pidtable[i].pl_pid));
                 return;
         }
 
         /*

@@ -949,12 +963,11 @@
 /*
  * clean_utmpx_ent      - Clean a utmpx entry
  */
 
 static void
-clean_utmpx_ent(u)
-        struct utmpx *u;
+clean_utmpx_ent(struct utmpx *u)
 {
         dprintf(("      clean_utmpx_ent: %d\n", (int)u->ut_pid));
         u->ut_type = DEAD_PROCESS;
         (void) time(&u->ut_xtime);
         (void) pututxline(u);

@@ -1031,12 +1044,11 @@
  *                        not a zombie.  Returns 1 if process is alive
  *                        and zero if it is dead or a zombie.
  */
 
 static int
-proc_is_alive(pid)
-        pid_t pid;
+proc_is_alive(pid_t pid)
 {
         char psinfoname[64];
         int fd;
         psinfo_t psinfo;
 

@@ -1080,6 +1092,32 @@
         if (lstat(UTMP_FILE, &s) == 0 &&
             s.st_size % sizeof (struct utmp) == 0) {
                 nonfatal("WARNING: /var/adm/utmp exists!\nSee "
                     "utmp(4) for more information");
         }
+}
+
+/*
+ * validate_default - validate and assign defaults.
+ */
+
+static int
+validate_default(char *defp, int *flag)
+{
+        long lval;
+        char *endptr;
+
+        errno = 0;
+        lval = strtol(defp, &endptr, 10);
+
+        if (errno != 0 || lval > INT_MAX || lval <= 0)
+                return (-1);
+
+        while (isspace(*endptr) != 0)
+                endptr++;
+
+        if (*endptr != '\0')
+                return (-1);
+
+        *flag = lval;
+        return (0);
 }