]> granicus.if.org Git - procps-ng/commitdiff
top: Do not default to the cwd in configs_read().
authorQualys Security Advisory <qsa@qualys.com>
Thu, 1 Jan 1970 00:00:00 +0000 (00:00 +0000)
committerCraig Small <csmall@enc.com.au>
Fri, 18 May 2018 21:32:22 +0000 (07:32 +1000)
If the HOME environment variable is not set, or not absolute, use the
home directory returned by getpwuid(getuid()), if set and absolute
(instead of the cwd "."); otherwise, set p_home to NULL.

To keep the changes to a minimum, we rely on POSIX, which requires that
fopen() fails with ENOENT if the pathname (Rc_name) is an empty string.
This integrates well into the existing code, and makes write_rcfile()
work without a change.

Also, it makes the code in configs_read() easier to follow: only set and
use p_home if safe, and only set Rc_name if safe (in all the other cases
it is the empty string, and the fopen() calls fail). Plus, check for
snprintf() truncation (and if it happens, reset Rc_name to the empty
string).

Important note: top.1 should probably be updated, since it mentions the
fallback to the current working directory.

top/top.c

index bc609aad057686c67108a607f051bcbdeaea8ae3..1b5afeecab7d76c8bd92c5e6f677ca0054256530 100644 (file)
--- a/top/top.c
+++ b/top/top.c
@@ -3810,6 +3810,20 @@ error Hey, fix the above fscanf 'PFLAGSSIZ' dependency !
 } // end: config_file
 
 
+static int snprintf_Rc_name (const char *const format, ...) __attribute__((format(printf,1,2)));
+static int snprintf_Rc_name (const char *const format, ...) {
+   int len;
+   va_list ap;
+   va_start(ap, format);
+   len = vsnprintf(Rc_name, sizeof(Rc_name), format, ap);
+   va_end(ap);
+   if (len <= 0 || (size_t)len >= sizeof(Rc_name)) {
+      Rc_name[0] = '\0';
+      return 0;
+   }
+   return len;
+}
+
         /*
          * Try reading up to 3 rcfiles
          * 1. 'SYS_RCRESTRICT' contains two lines consisting of the secure
@@ -3842,23 +3856,31 @@ static void configs_read (void) {
       fclose(fp);
    }
 
+   Rc_name[0] = '\0'; // "fopen() shall fail if pathname is an empty string."
    // attempt to use the legacy file first, if we cannot access that file, use
    // the new XDG basedir locations (XDG_CONFIG_HOME or HOME/.config) instead.
    p_home = getenv("HOME");
-   if (!p_home || p_home[0] == '\0')
-      p_home = ".";
-   snprintf(Rc_name, sizeof(Rc_name), "%s/.%src", p_home, Myname);
+   if (!p_home || p_home[0] != '/') {
+      const struct passwd *const pwd = getpwuid(getuid());
+      if (!pwd || !(p_home = pwd->pw_dir) || p_home[0] != '/') {
+         p_home = NULL;
+      }
+   }
+   if (p_home) {
+      snprintf_Rc_name("%s/.%src", p_home, Myname);
+   }
 
    if (!(fp = fopen(Rc_name, "r"))) {
       p = getenv("XDG_CONFIG_HOME");
       // ensure the path we get is absolute, fallback otherwise.
       if (!p || p[0] != '/') {
+         if (!p_home) goto system_default;
          p = fmtmk("%s/.config", p_home);
          (void)mkdir(p, 0700);
       }
-      snprintf(Rc_name, sizeof(Rc_name), "%s/procps", p);
+      if (!snprintf_Rc_name("%s/procps", p)) goto system_default;
       (void)mkdir(Rc_name, 0700);
-      snprintf(Rc_name, sizeof(Rc_name), "%s/procps/%src", p, Myname);
+      if (!snprintf_Rc_name("%s/procps/%src", p, Myname)) goto system_default;
       fp = fopen(Rc_name, "r");
    }
 
@@ -3867,6 +3889,7 @@ static void configs_read (void) {
       fclose(fp);
       if (p) goto default_or_error;
    } else {
+system_default:
       fp = fopen(SYS_RCDEFAULTS, "r");
       if (fp) {
          p = config_file(fp, SYS_RCDEFAULTS, &tmp_delay);