From 7c92bff18396470fd963c548ae197b376792cf58 Mon Sep 17 00:00:00 2001 From: Qualys Security Advisory Date: Thu, 1 Jan 1970 00:00:00 +0000 Subject: [PATCH] 0097-top: Do not default to the cwd in configs_read(). 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 | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/top/top.c b/top/top.c index 71000fe6..e13feb62 100644 --- a/top/top.c +++ b/top/top.c @@ -3346,6 +3346,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 @@ -3378,23 +3392,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"); } @@ -3403,6 +3425,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);