From a2ddca0916ef776dbd0c6304ea36b4ca7a35302c Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Tue, 2 Jul 2013 13:38:36 -0500 Subject: Bug #331 - Don't create a /tmp/root directory insecurely When finding the user's home directory to generate a subdirectory in $HOME/.config, we would fall back to /tmp if there were no environment variables for HOME or XDG_CONFIG_HOME. Since libimobiledevice gets used by upower, and since upowerd runs as root, this would cause a /tmp/root directory to be created insecurely, leaving upowerd vulnerable to a symlink attack. Now we fall back to getpwuid_r() to find the user's home directory if it is not provided in environment variables - this is the case when upowerd gets run via systemd, for example. The result is that we'll end up creating /root/.config, a safe directory, since regular users cannot create symlinks in /root. In the future we'll need a way for libimobiledevice to find where to store its pairing data on behalf of the console user, rather than writing it to /root. http://libiphone.lighthouseapp.com/projects/27916-libiphone/tickets/331-insecure-tmp-directory-use --- common/userpref.c | 105 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 29 deletions(-) (limited to 'common/userpref.c') diff --git a/common/userpref.c b/common/userpref.c index d363b0e..ab3a3cf 100644 --- a/common/userpref.c +++ b/common/userpref.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #ifdef HAVE_OPENSSL #include #include @@ -48,6 +51,7 @@ #include "userpref.h" #include "debug.h" +#include "utils.h" #define LIBIMOBILEDEVICE_CONF_DIR "libimobiledevice" #define LIBIMOBILEDEVICE_CONF_FILE "libimobiledevicerc" @@ -65,7 +69,7 @@ #define DIR_SEP_S "/" #endif -static char __config_dir[512] = {0, }; +static char *__config_dir = NULL; #ifdef WIN32 static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, long *items_written) @@ -103,24 +107,60 @@ static char *userpref_utf16_to_utf8(wchar_t *unistr, long len, long *items_read, #endif #ifndef WIN32 -static const char *userpref_get_tmp_dir() +static char *get_home_dir_from_system(void) { - const char *cdir = getenv("TMPDIR"); - if (cdir && cdir[0]) - return cdir; - cdir = getenv("TMP"); - if (cdir && cdir[0]) - return cdir; - cdir = getenv("TEMP"); - if (cdir && cdir[0]) - return cdir; - return "/tmp"; + long bufsize; + char *buf; + int error; + struct passwd pwd; + struct passwd *ppwd; + char *result = NULL; + + bufsize = sysconf (_SC_GETPW_R_SIZE_MAX); + + if (bufsize < 0) + bufsize = 1024; + + buf = NULL; + + do { + free (buf); + buf = malloc (bufsize); + if (!buf) + return NULL; + + errno = 0; + error = getpwuid_r (getuid (), &pwd, buf, bufsize, &ppwd); + + error = (error < 0) ? errno : error; + + if (!ppwd) { + if (error == 0 || error == ENOENT) + break; + else if (bufsize > 32 * 1024) + break; /* Unreasonable size; let's bail out */ + + bufsize *= 2; + } + } while (!ppwd); + + if (ppwd && ppwd->pw_dir) + result = strdup (ppwd->pw_dir); + + free (buf); + + return result; } #endif static const char *userpref_get_config_dir() { - if (__config_dir[0]) return __config_dir; + char *base_config_dir; + int use_dot_config; + + if (__config_dir) + return __config_dir; + #ifdef WIN32 wchar_t path[MAX_PATH+1]; HRESULT hr; @@ -131,38 +171,45 @@ static const char *userpref_get_config_dir() if (hr == S_OK) { b = SHGetPathFromIDListW (pidl, path); if (b) { - char *cdir = userpref_utf16_to_utf8 (path, wcslen(path), NULL, NULL); - strcpy(__config_dir, cdir); - free(cdir); + base_config_dir = userpref_utf16_to_utf8 (path, wcslen(path), NULL, NULL); CoTaskMemFree (pidl); } } + + use_dot_config = 0; #else const char *cdir = getenv("XDG_CONFIG_HOME"); if (!cdir) { cdir = getenv("HOME"); if (!cdir || !cdir[0]) { - const char *tdir = userpref_get_tmp_dir(); - strcpy(__config_dir, tdir); - strcat(__config_dir, DIR_SEP_S); - strcat(__config_dir, "root"); + base_config_dir = get_home_dir_from_system(); + if (!base_config_dir) + return NULL; } else { - strcpy(__config_dir, cdir); + base_config_dir = strdup(cdir); } - strcat(__config_dir, DIR_SEP_S); - strcat(__config_dir, ".config"); + + use_dot_config = 1; } else { - strcpy(__config_dir, cdir); + base_config_dir = strdup(cdir); + use_dot_config = 0; } #endif - strcat(__config_dir, DIR_SEP_S); - strcat(__config_dir, LIBIMOBILEDEVICE_CONF_DIR); - int i = strlen(__config_dir)-1; - while ((i > 0) && (__config_dir[i] == DIR_SEP)) { - __config_dir[i--] = '\0'; + if (use_dot_config) + __config_dir = string_concat(base_config_dir, DIR_SEP_S, ".config", DIR_SEP_S, LIBIMOBILEDEVICE_CONF_DIR); + else + __config_dir = string_concat(base_config_dir, DIR_SEP_S, LIBIMOBILEDEVICE_CONF_DIR); + + if (__config_dir) { + int i = strlen(__config_dir)-1; + while ((i > 0) && (__config_dir[i] == DIR_SEP)) { + __config_dir[i--] = '\0'; + } } + free(base_config_dir); + return __config_dir; } -- cgit v1.1-32-gdbae