diff --git a/.gitignore b/.gitignore index 9de0d23..f2d7dc9 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /fish-2.1.0.tar.gz +/fish-2.1.1.tar.gz diff --git a/fish-upstream-CVE-2014-2905-part2.patch b/fish-upstream-CVE-2014-2905-part2.patch deleted file mode 100644 index b1c444f..0000000 --- a/fish-upstream-CVE-2014-2905-part2.patch +++ /dev/null @@ -1,185 +0,0 @@ -From b5cd21c337a8990c0c343ab2c22d3dc123a03d25 Mon Sep 17 00:00:00 2001 -Message-Id: -From: David Adam -Date: Mon, 4 Aug 2014 13:26:14 +0800 -Subject: [PATCH 1/3] Further fixes to universal variable server socket - management - -- Change fishd_path to std::string -- Warn, rather than exiting with an error, if the universal variable - server path is not available, and provide more useful advice. -- Export the new __fishd_runtime_dir variable. ---- - common.cpp | 13 +++++++------ - common.h | 2 +- - env.cpp | 4 ++-- - env_universal.cpp | 22 ++++++++++++++-------- - env_universal.h | 2 +- - fish_pager.cpp | 4 ++-- - fishd.cpp | 9 +++++++-- - 7 files changed, 34 insertions(+), 22 deletions(-) - -diff --git a/common.cpp b/common.cpp -index 3e5a2c8..203eda5 100644 ---- a/common.cpp -+++ b/common.cpp -@@ -2381,10 +2381,11 @@ static int check_runtime_path(const char * path) - } - - /** Return the path of an appropriate runtime data directory */ --const char* common_get_runtime_path(void) -+std::string common_get_runtime_path() - { - const char *dir = getenv("XDG_RUNTIME_DIR"); - const char *uname = getenv("USER"); -+ std::string path; - - if (uname == NULL) - { -@@ -2396,19 +2397,19 @@ const char* common_get_runtime_path(void) - { - // /tmp/fish.user - dir = "/tmp/fish."; -- std::string path; - path.reserve(strlen(dir) + strlen(uname)); - path.append(dir); - path.append(uname); - if (check_runtime_path(path.c_str()) != 0) - { -- debug(0, L"Couldn't create secure runtime path: '%s'", path.c_str()); -- exit(EXIT_FAILURE); -+ debug(0, L"Runtime path not available. Try deleting the directory %s and restarting fish.", path.c_str()); -+ path.clear(); - } -- return strdup(path.c_str()); - } - else - { -- return dir; -+ path.reserve(strlen(dir)); -+ path.append(dir); - } -+ return path; - } -diff --git a/common.h b/common.h -index 4d18aca..b160245 100644 ---- a/common.h -+++ b/common.h -@@ -814,6 +814,6 @@ extern "C" { - } - - /** Return the path of an appropriate runtime data directory */ --const char* common_get_runtime_path(void); -+std::string common_get_runtime_path(); - - #endif -diff --git a/env.cpp b/env.cpp -index 0bda417..703d619 100644 ---- a/env.cpp -+++ b/env.cpp -@@ -620,8 +620,8 @@ void env_init(const struct config_paths_t *paths /* or NULL */) - - const env_var_t user_dir_wstr = env_get_string(L"USER"); - -- const char * fishd_dir = common_get_runtime_path(); -- env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL); -+ std::string fishd_dir = common_get_runtime_path(); -+ env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL | ENV_EXPORT); - - wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast(user_dir_wstr.c_str()); - -diff --git a/env_universal.cpp b/env_universal.cpp -index 1a97443..78e3130 100644 ---- a/env_universal.cpp -+++ b/env_universal.cpp -@@ -242,23 +242,29 @@ static void reconnect() - } - - --void env_universal_init(const char * p, -+void env_universal_init(std::string p, - wchar_t *u, - void (*sf)(), - void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val)) - { -- path=p; -+ path=p.c_str(); - user=u; - start_fishd=sf; - external_callback = cb; - -- env_universal_server.fd = get_socket(); -- env_universal_common_init(&callback); -- env_universal_read_all(); -- s_env_univeral_inited = true; -- if (env_universal_server.fd >= 0) -+ if (p == "") { -+ debug(1, L"Could not connect to universal variable server. You will not be able to share variable values between fish sessions."); -+ } -+ else - { -- env_universal_barrier(); -+ env_universal_server.fd = get_socket(); -+ env_universal_common_init(&callback); -+ env_universal_read_all(); -+ s_env_univeral_inited = true; -+ if (env_universal_server.fd >= 0) -+ { -+ env_universal_barrier(); -+ } - } - } - -diff --git a/env_universal.h b/env_universal.h -index 9e6ab85..f14db29 100644 ---- a/env_universal.h -+++ b/env_universal.h -@@ -17,7 +17,7 @@ extern connection_t env_universal_server; - /** - Initialize the envuni library - */ --void env_universal_init(const char * p, -+void env_universal_init(std::string p, - wchar_t *u, - void (*sf)(), - void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val)); -diff --git a/fish_pager.cpp b/fish_pager.cpp -index 27bc80e..6d05774 100644 ---- a/fish_pager.cpp -+++ b/fish_pager.cpp -@@ -1032,8 +1032,8 @@ static void init(int mangle_descriptors, int out) - exit(1); - } - -- -- env_universal_init("", 0, 0, 0); -+ std::string dir = common_get_runtime_path(); -+ env_universal_init(dir, 0, 0, 0); - input_common_init(&interrupt_handler); - output_set_writer(&pager_buffered_writer); - -diff --git a/fishd.cpp b/fishd.cpp -index dd43647..d725e43 100644 ---- a/fishd.cpp -+++ b/fishd.cpp -@@ -159,10 +159,15 @@ static int quit=0; - */ - static std::string get_socket_filename(void) - { -- const char *dir = common_get_runtime_path(); -+ std::string dir = common_get_runtime_path(); -+ -+ if (dir == "") { -+ debug(0, L"Cannot access desired socket path."); -+ exit(EXIT_FAILURE); -+ } - - std::string name; -- name.reserve(strlen(dir) + strlen(SOCK_FILENAME) + 1); -+ name.reserve(dir.length() + strlen(SOCK_FILENAME) + 1); - name.append(dir); - name.push_back('/'); - name.append(SOCK_FILENAME); --- -1.9.3 - diff --git a/fish-upstream-CVE-2014-2905.patch b/fish-upstream-CVE-2014-2905.patch deleted file mode 100644 index 3f26d84..0000000 --- a/fish-upstream-CVE-2014-2905.patch +++ /dev/null @@ -1,478 +0,0 @@ -From 4cb4fc3ef889788b9755451bc565e27bb803b8ba Mon Sep 17 00:00:00 2001 -Message-Id: <4cb4fc3ef889788b9755451bc565e27bb803b8ba.1407803923.git.luto@amacapital.net> -From: David Adam -Date: Sun, 20 Apr 2014 19:20:07 +0800 -Subject: [PATCH] Fix for CVE-2014-2905 - fishd restart required. - - - Use a secure path for sockets (some code used under license from - tmux). - - Provide the secure path in the environment as $__fish_runtime_dir. - - Link the new path to the old path to ease migration from earlier - versions. - -Closes #1359. - -After installing fish built from or after this commit, you MUST -terminate all running fishd processes (`killall fishd`, `pkill fishd` -or similar). Distributors are encouraged to do this from within their -packaging scripts. fishd will restart automatically, and no data should -be lost. ---- - common.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ - common.h | 2 ++ - doc_src/license.hdr | 20 ++++++++++++++ - env.cpp | 7 ++--- - env_universal.cpp | 41 +++++----------------------- - env_universal.h | 2 +- - env_universal_common.cpp | 10 +++++-- - env_universal_common.h | 9 +++++-- - fish_pager.cpp | 2 +- - fishd.cpp | 56 +++++++++++++++++++++++++++++++++++--- - 10 files changed, 172 insertions(+), 47 deletions(-) - -diff --git a/common.cpp b/common.cpp -index 7a9f7a5..3e5a2c8 100644 ---- a/common.cpp -+++ b/common.cpp -@@ -24,6 +24,7 @@ parts of fish. - #include - #include - #include -+#include - - #ifdef HAVE_SYS_IOCTL_H - #include -@@ -2342,3 +2343,72 @@ char **make_null_terminated_array(const std::vector &lst) - { - return make_null_terminated_array_helper(lst); - } -+ -+/** -+ Check, and create if necessary, a secure runtime path -+ Derived from tmux.c in tmux (http://tmux.sourceforge.net/) -+*/ -+static int check_runtime_path(const char * path) -+{ -+ /* -+ * Copyright (c) 2007 Nicholas Marriott -+ * -+ * Permission to use, copy, modify, and distribute this software for any -+ * purpose with or without fee is hereby granted, provided that the above -+ * copyright notice and this permission notice appear in all copies. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER -+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ */ -+ -+ struct stat statpath; -+ u_int uid = geteuid(); -+ -+ if (mkdir(path, S_IRWXU) != 0 && errno != EEXIST) -+ return errno; -+ if (lstat(path, &statpath) != 0) -+ return errno; -+ if (!S_ISDIR(statpath.st_mode) -+ || statpath.st_uid != uid -+ || (statpath.st_mode & (S_IRWXG|S_IRWXO)) != 0) -+ return EACCES; -+ return 0; -+} -+ -+/** Return the path of an appropriate runtime data directory */ -+const char* common_get_runtime_path(void) -+{ -+ const char *dir = getenv("XDG_RUNTIME_DIR"); -+ const char *uname = getenv("USER"); -+ -+ if (uname == NULL) -+ { -+ const struct passwd *pw = getpwuid(getuid()); -+ uname = pw->pw_name; -+ } -+ -+ if (dir == NULL) -+ { -+ // /tmp/fish.user -+ dir = "/tmp/fish."; -+ std::string path; -+ path.reserve(strlen(dir) + strlen(uname)); -+ path.append(dir); -+ path.append(uname); -+ if (check_runtime_path(path.c_str()) != 0) -+ { -+ debug(0, L"Couldn't create secure runtime path: '%s'", path.c_str()); -+ exit(EXIT_FAILURE); -+ } -+ return strdup(path.c_str()); -+ } -+ else -+ { -+ return dir; -+ } -+} -diff --git a/common.h b/common.h -index 57fe7fa..4d18aca 100644 ---- a/common.h -+++ b/common.h -@@ -813,5 +813,7 @@ extern "C" { - __attribute__((noinline)) void debug_thread_error(void); - } - -+/** Return the path of an appropriate runtime data directory */ -+const char* common_get_runtime_path(void); - - #endif -diff --git a/doc_src/license.hdr b/doc_src/license.hdr -index 64bab10..76981a9 100644 ---- a/doc_src/license.hdr -+++ b/doc_src/license.hdr -@@ -1400,6 +1400,26 @@ POSSIBILITY OF SUCH DAMAGES. - -

- -+

License for code derived from tmux

-+ -+Fish contains code derived from -+tmux, made available under an ISC -+license. -+

-+Copyright (c) 2007 Nicholas Marriott -+

-+Permission to use, copy, modify, and distribute this software for any -+purpose with or without fee is hereby granted, provided that the above -+copyright notice and this permission notice appear in all copies. -+

-+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER -+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -+OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -+ - */ - - \htmlonly \endhtmlonly -diff --git a/env.cpp b/env.cpp -index 13f87b6..0bda417 100644 ---- a/env.cpp -+++ b/env.cpp -@@ -57,7 +57,7 @@ - #include "complete.h" - - /** Command used to start fishd */ --#define FISHD_CMD L"fishd ^ /tmp/fishd.log.%s" -+#define FISHD_CMD L"fishd ^ $__fish_runtime_dir/fishd.log.%s" - - // Version for easier debugging - //#define FISHD_CMD L"fishd" -@@ -618,10 +618,11 @@ void env_init(const struct config_paths_t *paths /* or NULL */) - env_set(L"version", version.c_str(), ENV_GLOBAL); - env_set(L"FISH_VERSION", version.c_str(), ENV_GLOBAL); - -- const env_var_t fishd_dir_wstr = env_get_string(L"FISHD_SOCKET_DIR"); - const env_var_t user_dir_wstr = env_get_string(L"USER"); - -- wchar_t * fishd_dir = fishd_dir_wstr.missing()?NULL:const_cast(fishd_dir_wstr.c_str()); -+ const char * fishd_dir = common_get_runtime_path(); -+ env_set(L"__fish_runtime_dir", str2wcstring(fishd_dir).c_str(), ENV_GLOBAL); -+ - wchar_t * user_dir = user_dir_wstr.missing()?NULL:const_cast(user_dir_wstr.c_str()); - - env_universal_init(fishd_dir , user_dir , -diff --git a/env_universal.cpp b/env_universal.cpp -index c7d060a..1a97443 100644 ---- a/env_universal.cpp -+++ b/env_universal.cpp -@@ -61,7 +61,7 @@ static int get_socket_count = 0; - #define DEFAULT_RETRY_COUNT 15 - #define DEFAULT_RETRY_DELAY 0.2 - --static wchar_t * path; -+static const char * path; - static wchar_t *user; - static void (*start_fishd)(); - static void (*external_callback)(fish_message_type_t type, const wchar_t *name, const wchar_t *val); -@@ -82,48 +82,19 @@ static int try_get_socket_once(void) - { - int s; - -- wchar_t *wdir; -- wchar_t *wuname; -- char *dir = 0; -- -- wdir = path; -- wuname = user; -- - if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - { - wperror(L"socket"); - return -1; - } - -- if (wdir) -- dir = wcs2str(wdir); -- else -- dir = strdup("/tmp"); -- -- std::string uname; -- if (wuname) -- { -- uname = wcs2string(wuname); -- } -- else -- { -- struct passwd *pw = getpwuid(getuid()); -- if (pw && pw->pw_name) -- { -- uname = pw->pw_name; -- } -- } -- - std::string name; -- name.reserve(strlen(dir) + uname.size() + strlen(SOCK_FILENAME) + 2); -- name.append(dir); -- name.append("/"); -+ name.reserve(strlen(path) + strlen(SOCK_FILENAME) + 1); -+ name.append(path); -+ name.push_back('/'); - name.append(SOCK_FILENAME); -- name.append(uname); -- -- free(dir); - -- debug(3, L"Connect to socket %s at fd %2", name.c_str(), s); -+ debug(3, L"Connect to socket %s at fd %d", name.c_str(), s); - - struct sockaddr_un local = {}; - local.sun_family = AF_UNIX; -@@ -271,7 +242,7 @@ static void reconnect() - } - - --void env_universal_init(wchar_t * p, -+void env_universal_init(const char * p, - wchar_t *u, - void (*sf)(), - void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val)) -diff --git a/env_universal.h b/env_universal.h -index 4f38fe7..9e6ab85 100644 ---- a/env_universal.h -+++ b/env_universal.h -@@ -17,7 +17,7 @@ extern connection_t env_universal_server; - /** - Initialize the envuni library - */ --void env_universal_init(wchar_t * p, -+void env_universal_init(const char * p, - wchar_t *u, - void (*sf)(), - void (*cb)(fish_message_type_t type, const wchar_t *name, const wchar_t *val)); -diff --git a/env_universal_common.cpp b/env_universal_common.cpp -index f600e70..2b12cf1 100644 ---- a/env_universal_common.cpp -+++ b/env_universal_common.cpp -@@ -27,7 +27,6 @@ - #include - #include - #include --#include - #include - - #ifdef HAVE_SYS_SELECT_H -@@ -87,6 +86,13 @@ - #define ENV_UNIVERSAL_EOF 0x102 - - /** -+ Maximum length of socket filename -+*/ -+#ifndef UNIX_PATH_MAX -+#define UNIX_PATH_MAX 100 -+#endif -+ -+/** - A variable entry. Stores the value of a variable and whether it - should be exported. Obviously, it needs to be allocated large - enough to fit the value string. -@@ -417,7 +423,7 @@ void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_ - } - - /** -- Read one byte of date form the specified connection -+ Read one byte of date from the specified connection - */ - static int read_byte(connection_t *src) - { -diff --git a/env_universal_common.h b/env_universal_common.h -index 0a13a41..deddfb3 100644 ---- a/env_universal_common.h -+++ b/env_universal_common.h -@@ -33,9 +33,9 @@ - - - /** -- The filename to use for univeral variables. The username is appended -+ The filename to use for univeral variables. - */ --#define SOCK_FILENAME "fishd.socket." -+#define SOCK_FILENAME "fishd.socket" - - /** - The different types of commands that can be sent between client/server -@@ -134,6 +134,11 @@ void try_send_all(connection_t *c); - message_t *create_message(fish_message_type_t type, const wchar_t *key, const wchar_t *val); - - /** -+ Constructs the fish socket filename -+*/ -+std::string env_universal_common_get_socket_filename(void); -+ -+/** - Init the library - */ - void env_universal_common_init(void (*cb)(fish_message_type_t type, const wchar_t *key, const wchar_t *val)); -diff --git a/fish_pager.cpp b/fish_pager.cpp -index 9cde933..27bc80e 100644 ---- a/fish_pager.cpp -+++ b/fish_pager.cpp -@@ -1033,7 +1033,7 @@ static void init(int mangle_descriptors, int out) - } - - -- env_universal_init(0, 0, 0, 0); -+ env_universal_init("", 0, 0, 0); - input_common_init(&interrupt_handler); - output_set_writer(&pager_buffered_writer); - -diff --git a/fishd.cpp b/fishd.cpp -index edb79c2..dd43647 100644 ---- a/fishd.cpp -+++ b/fishd.cpp -@@ -159,6 +159,27 @@ static int quit=0; - */ - static std::string get_socket_filename(void) - { -+ const char *dir = common_get_runtime_path(); -+ -+ std::string name; -+ name.reserve(strlen(dir) + strlen(SOCK_FILENAME) + 1); -+ name.append(dir); -+ name.push_back('/'); -+ name.append(SOCK_FILENAME); -+ -+ if (name.size() >= UNIX_PATH_MAX) -+ { -+ debug(1, L"Filename too long: '%s'", name.c_str()); -+ exit(EXIT_FAILURE); -+ } -+ return name; -+} -+ -+/** -+ Constructs the legacy socket filename -+*/ -+static std::string get_old_socket_filename(void) -+{ - const char *dir = getenv("FISHD_SOCKET_DIR"); - char *uname = getenv("USER"); - -@@ -174,10 +195,9 @@ static std::string get_socket_filename(void) - } - - std::string name; -- name.reserve(strlen(dir)+ strlen(uname)+ strlen(SOCK_FILENAME) + 1); -+ name.reserve(strlen(dir)+ strlen(uname)+ strlen("fishd.socket.") + 1); - name.append(dir); -- name.push_back('/'); -- name.append(SOCK_FILENAME); -+ name.append("/fishd.socket."); - name.append(uname); - - if (name.size() >= UNIX_PATH_MAX) -@@ -541,6 +561,7 @@ repeat: - int exitcode = EXIT_FAILURE; - struct sockaddr_un local; - const std::string sock_name = get_socket_filename(); -+ const std::string old_sock_name = get_old_socket_filename(); - - /* - Start critical section protected by lock -@@ -598,6 +619,19 @@ repeat: - doexit = 1; - } - -+ // Attempt to hardlink the old socket name so that old versions of fish keep working on upgrade -+ // Not critical if it fails -+ if (unlink(old_sock_name.c_str()) != 0 && errno != ENOENT) -+ { -+ debug(0, L"Could not create legacy socket path"); -+ wperror(L"unlink"); -+ } -+ else if (link(sock_name.c_str(), old_sock_name.c_str()) != 0) -+ { -+ debug(0, L"Could not create legacy socket path"); -+ wperror(L"link"); -+ } -+ - unlock: - (void)unlink(lockfile.c_str()); - debug(4, L"Released lockfile: %s", lockfile.c_str()); -@@ -873,6 +907,18 @@ static void init() - } - - /** -+ Clean up behind ourselves -+*/ -+static void cleanup() -+{ -+ if (unlink(get_old_socket_filename().c_str()) != 0) -+ { -+ debug(0, L"Could not remove legacy socket path"); -+ wperror(L"unlink"); -+ } -+} -+ -+/** - Main function for fishd - */ - int main(int argc, char ** argv) -@@ -973,6 +1019,7 @@ int main(int argc, char ** argv) - if (quit) - { - save(); -+ cleanup(); - exit(0); - } - -@@ -982,6 +1029,7 @@ int main(int argc, char ** argv) - if (errno != EINTR) - { - wperror(L"select"); -+ cleanup(); - exit(1); - } - } -@@ -994,6 +1042,7 @@ int main(int argc, char ** argv) - &t)) == -1) - { - wperror(L"accept"); -+ cleanup(); - exit(1); - } - else -@@ -1070,6 +1119,7 @@ int main(int argc, char ** argv) - { - debug(0, L"No more clients. Quitting"); - save(); -+ cleanup(); - break; - } - --- -1.9.3 - diff --git a/fish-upstream-CVE-2014-2906.patch b/fish-upstream-CVE-2014-2906.patch deleted file mode 100644 index ae99537..0000000 --- a/fish-upstream-CVE-2014-2906.patch +++ /dev/null @@ -1,70 +0,0 @@ -From c0989dce2d882c94eb3183e7b94402ba53534abb Mon Sep 17 00:00:00 2001 -Message-Id: -In-Reply-To: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398703637.git.luto@amacapital.net> -References: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398703637.git.luto@amacapital.net> -From: David Adam -Date: Sun, 20 Apr 2014 23:51:20 +0800 -Subject: [PATCH 4/4] use mktemp(1) to generate temporary file names - -Fix for CVE-2014-2906. - -Closes a race condition in funced which would allow execution of -arbitrary code; closes a race condition in psub which would allow -alternation of the data stream. - -Note that `psub -f` does not work (#1040); a fix should be committed -separately for ease of maintenance. ---- - share/functions/funced.fish | 6 +----- - share/functions/psub.fish | 11 +++-------- - 2 files changed, 4 insertions(+), 13 deletions(-) - -diff --git a/share/functions/funced.fish b/share/functions/funced.fish -index 3c2de06..ca2e277 100644 ---- a/share/functions/funced.fish -+++ b/share/functions/funced.fish -@@ -81,11 +81,7 @@ function funced --description 'Edit function definition' - return 0 - end - -- set -q TMPDIR; or set -l TMPDIR /tmp -- set -l tmpname (printf "$TMPDIR/fish_funced_%d_%d.fish" %self (random)) -- while test -f $tmpname -- set tmpname (printf "$TMPDIR/fish_funced_%d_%d.fish" %self (random)) -- end -+ set tmpname (mktemp -t fish_funced.XXXXXXXXXX) - - if functions -q -- $funcname - functions -- $funcname > $tmpname -diff --git a/share/functions/psub.fish b/share/functions/psub.fish -index 42e34c7..7877aa4 100644 ---- a/share/functions/psub.fish -+++ b/share/functions/psub.fish -@@ -45,21 +45,16 @@ function psub --description "Read from stdin into a file and output the filename - return - end - -- # Find unique file name for writing output to -- while true -- set filename /tmp/.psub.(echo %self).(random); -- if not test -e $filename -- break; -- end -- end -- - if test use_fifo = 1 - # Write output to pipe. This needs to be done in the background so - # that the command substitution exits without needing to wait for - # all the commands to exit -+ set dir (mktemp -d /tmp/.psub.XXXXXXXXXX); or return -+ set filename $dir/psub.fifo - mkfifo $filename - cat >$filename & - else -+ set filename (mktemp /tmp/.psub.XXXXXXXXXX) - cat >$filename - end - --- -1.9.0 - diff --git a/fish-upstream-CVE-2014-2914-part2.patch b/fish-upstream-CVE-2014-2914-part2.patch deleted file mode 100644 index 3dae9ab..0000000 --- a/fish-upstream-CVE-2014-2914-part2.patch +++ /dev/null @@ -1,239 +0,0 @@ -commit 397249a8d5a939d044da8ecfbb1654d48ce5a153 -Author: David Adam -Date: Mon Aug 4 13:34:26 2014 +0800 - - Authenticate connections to web_config service - - - Require all requests to use a session path. - - Use a redirect file to avoid exposing the URL on the command line, as - it contains the session path. - - Fix for CVE-2014-2914. - Closes #1438. - -diff --git a/share/tools/web_config/index.html b/share/tools/web_config/index.html -index 22cd470..90df114 100644 ---- a/share/tools/web_config/index.html -+++ b/share/tools/web_config/index.html -@@ -556,7 +556,7 @@ function switch_tab(new_tab) { - if (new_tab == 'tab_colors') { - /* Keep track of whether this is the first element */ - var first = true -- run_get_request('/colors/', function(key_and_values){ -+ run_get_request('colors/', function(key_and_values){ - /* Result is name, description, value */ - var key = key_and_values[0] - var description = key_and_values[1] -@@ -577,7 +577,7 @@ function switch_tab(new_tab) { - sample_prompts.length = 0 - /* Color the first one blue */ - var first = true; -- run_get_request('/sample_prompts/', function(sample_prompt){ -+ run_get_request('sample_prompts/', function(sample_prompt){ - var name = sample_prompt['name'] - sample_prompts[name] = sample_prompt - var color = first ? '66F' : 'AAA' -@@ -594,7 +594,7 @@ function switch_tab(new_tab) { - } else if (new_tab == 'tab_functions') { - /* Keep track of whether this is the first element */ - var first = true -- run_get_request('/functions/', function(contents){ -+ run_get_request('functions/', function(contents){ - var elem = create_master_element(contents, false/* description */, 'AAAAAA', '11pt', select_function_master_element) - if (first) { - /* It's the first element, so select it, so something gets selected */ -@@ -606,7 +606,7 @@ function switch_tab(new_tab) { - $('#master_detail_table').show() - wants_data_table = false - } else if (new_tab == 'tab_variables') { -- run_get_request_with_bulk_handler('/variables/', function(json_contents){ -+ run_get_request_with_bulk_handler('variables/', function(json_contents){ - var rows = new Array() - for (var i = 0; i < json_contents.length; i++) { - var contents = json_contents[i] -@@ -622,7 +622,7 @@ function switch_tab(new_tab) { - } else if (new_tab == 'tab_history') { - // Clear the history map - history_element_map.length = 0 -- run_get_request_with_bulk_handler('/history/', function(json_contents){ -+ run_get_request_with_bulk_handler('history/', function(json_contents){ - start = new Date().getTime() - var rows = new Array() - for (var i = 0; i < json_contents.length; i++) { -@@ -757,7 +757,7 @@ function select_color_master_element(elem) { - function select_function_master_element(elem) { - select_master_element(elem) - -- run_post_request('/get_function/', { -+ run_post_request('get_function/', { - what: current_master_element_name() - }, function(contents){ - /* Replace leading tabs and groups of four spaces at the beginning of a line with two spaces. */ -@@ -773,7 +773,7 @@ function select_sample_prompt_master_element(elem) { - select_master_element(elem) - var name = current_master_element_name() - sample_prompt = sample_prompts[name] -- run_post_request('/get_sample_prompt/', { -+ run_post_request('get_sample_prompt/', { - what: sample_prompt['function'] - }, function(keys_and_values){ - var prompt_func = keys_and_values['function'] -@@ -788,7 +788,7 @@ function select_sample_prompt_master_element(elem) { - function select_current_prompt_master_element(elem) { - $('.prompt_save_button').hide() - select_master_element(elem) -- run_get_request_with_bulk_handler('/current_prompt/', function(keys_and_values){ -+ run_get_request_with_bulk_handler('current_prompt/', function(keys_and_values){ - var prompt_func = keys_and_values['function'] - var prompt_demo = keys_and_values['demo'] - var prompt_font_size = keys_and_values['font_size'] -@@ -801,7 +801,7 @@ function select_current_prompt_master_element(elem) { - function save_current_prompt() { - var name = current_master_element_name() - var sample_prompt = sample_prompts[name] -- run_post_request('/set_prompt/', { -+ run_post_request('set_prompt/', { - what: sample_prompt['function'] - }, function(contents){ - if (contents == "OK") { -@@ -817,7 +817,7 @@ function post_style_to_server() { - if (! style) - return - -- run_post_request('/set_color/', { -+ run_post_request('set_color/', { - what: current_master_element_name(), - color: style.color, - background_color: style.background_color, -@@ -1221,7 +1221,7 @@ function escape_HTML(foo) { - function tell_fish_to_delete_element(idx) { - var row_elem = $('#data_table_row_' + idx) - var txt = history_element_map[idx] -- run_post_request('/delete_history_item/', { -+ run_post_request('delete_history_item/', { - what: txt - }, function(contents){ - if (contents == "OK") { -diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py -index 1b9250b..2a103eb 100755 ---- a/share/tools/web_config/webconfig.py -+++ b/share/tools/web_config/webconfig.py -@@ -17,7 +17,7 @@ else: - from urllib.parse import parse_qs - import webbrowser - import subprocess --import re, socket, os, sys, cgi, select, time, glob -+import re, socket, os, sys, cgi, select, time, glob, random, string - try: - import json - except ImportError: -@@ -485,9 +485,16 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - else: font_size = '18pt' - return font_size - -- - def do_GET(self): - p = self.path -+ -+ authpath = '/' + authkey -+ if p.startswith(authpath): -+ p = p[len(authpath):] -+ else: -+ return self.send_error(403) -+ self.path = p -+ - if p == '/colors/': - output = self.do_get_colors() - elif p == '/functions/': -@@ -519,6 +526,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - - def do_POST(self): - p = self.path -+ -+ authpath = '/' + authkey -+ if p.startswith(authpath): -+ p = p[len(authpath):] -+ else: -+ return self.send_error(403) -+ self.path = p -+ - if IS_PY2: - ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) - else: # Python 3 -@@ -582,7 +597,19 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - def log_request(self, code='-', size='-'): - """ Disable request logging """ - pass -- -+ -+redirect_template_html = """ -+ -+ -+ -+ -+ -+ -+

Start the Fish Web config

-+ -+ -+""" -+ - # find fish - fish_bin_dir = os.environ.get('__fish_bin_dir') - fish_bin_path = None -@@ -618,6 +645,9 @@ initial_wd = os.getcwd() - where = os.path.dirname(sys.argv[0]) - os.chdir(where) - -+# Generate a 16-byte random key as a hexadecimal string -+authkey = hex(random.getrandbits(16*4))[2:] -+ - # Try to find a suitable port - PORT = 8000 - while PORT <= 9000: -@@ -647,9 +677,36 @@ if len(sys.argv) > 1: - initial_tab = '#' + tab - break - --url = 'http://localhost:%d/%s' % (PORT, initial_tab) --print("Web config started at '%s'. Hit enter to stop." % url) --webbrowser.open(url) -+url = 'http://localhost:%d/%s/%s' % (PORT, authkey, initial_tab) -+ -+# Create temporary file to hold redirect to real server -+# This prevents exposing the URL containing the authentication key on the command line -+# (see CVE-2014-2914 or https://github.com/fish-shell/fish-shell/issues/1438) -+if 'XDG_CACHE_HOME' in os.environ: -+ dirname = os.path.expanduser(os.path.expandvars('$XDG_CACHE_HOME/fish/')) -+else: -+ dirname = os.path.expanduser('~/.cache/fish/') -+ -+os.umask(0o0077) -+try: -+ os.makedirs(dirname, 0o0700) -+except OSError as e: -+ if e.errno == 17: -+ pass -+ else: -+ raise e -+ -+randtoken = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(6)) -+filename = dirname + 'web_config-%s.html' % randtoken -+ -+f = open(filename, 'w') -+f.write(redirect_template_html % (url, url)) -+f.close() -+ -+# Open temporary file as URL -+fileurl = 'file://' + filename -+print("Web config started at '%s'. Hit enter to stop." % fileurl) -+webbrowser.open(fileurl) - - # Select on stdin and httpd - stdin_no = sys.stdin.fileno() -@@ -666,3 +723,5 @@ try: - except KeyboardInterrupt: - print("\nShutting down.") - -+# Clean up temporary file -+os.remove(filename) diff --git a/fish-upstream-CVE-2014-2914.patch b/fish-upstream-CVE-2014-2914.patch deleted file mode 100644 index 248bb38..0000000 --- a/fish-upstream-CVE-2014-2914.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 10642a34f17ae45bd93be3ae6021ee920d3da0c2 Mon Sep 17 00:00:00 2001 -Message-Id: <10642a34f17ae45bd93be3ae6021ee920d3da0c2.1398707555.git.luto@amacapital.net> -In-Reply-To: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398707555.git.luto@amacapital.net> -References: <3c5d5b344ee945b99e4bb16a44af6f293601813d.1398707555.git.luto@amacapital.net> -From: Anders Bergh -Date: Tue, 4 Mar 2014 09:59:26 +0100 -Subject: [PATCH 2/4] fish_config: Listen on both IPv6 and IPv4. - -A subclass of TCPServer was created to deny any non-local connections and to -listen using an IPv6 socket. ---- - share/tools/web_config/webconfig.py | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py -index f735a02..1b9250b 100755 ---- a/share/tools/web_config/webconfig.py -+++ b/share/tools/web_config/webconfig.py -@@ -250,6 +250,16 @@ class FishVar: - if self.exported: flags.append('exported') - return [self.name, self.value, ', '.join(flags)] - -+class FishConfigTCPServer(SocketServer.TCPServer): -+ """TCPServer that only accepts connections from localhost (IPv4/IPv6).""" -+ WHITELIST = set(['::1', '::ffff:127.0.0.1', '127.0.0.1']) -+ -+ address_family = socket.AF_INET6 -+ -+ def verify_request(self, request, client_address): -+ return client_address[0] in FishConfigTCPServer.WHITELIST -+ -+ - class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - - def write_to_wfile(self, txt): -@@ -613,7 +623,7 @@ PORT = 8000 - while PORT <= 9000: - try: - Handler = FishConfigHTTPRequestHandler -- httpd = SocketServer.TCPServer(("", PORT), Handler) -+ httpd = FishConfigTCPServer(("::", PORT), Handler) - # Success - break - except socket.error: --- -1.9.0 - diff --git a/fish-webconfig-CVE-2014-2914-followup-1.patch b/fish-webconfig-CVE-2014-2914-followup-1.patch deleted file mode 100644 index 9fab859..0000000 --- a/fish-webconfig-CVE-2014-2914-followup-1.patch +++ /dev/null @@ -1,45 +0,0 @@ -commit 78e2b7cc0897de3eb2a8cdc0f5efe49a34402f9d -Author: Andy Lutomirski -Date: Mon Aug 11 17:50:56 2014 -0700 - - webconfig: Use a constant-time token comparison - - This prevents a linear-time attack to recover the auth token. - -diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py -index 2a103eb..452f771 100755 ---- a/share/tools/web_config/webconfig.py -+++ b/share/tools/web_config/webconfig.py -@@ -471,6 +471,14 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - # Ignore unreadable files, etc - pass - return result -+ -+ def secure_startswith(self, haystack, needle): -+ if len(haystack) < len(needle): -+ return False -+ bits = 0 -+ for x,y in zip(haystack, needle): -+ bits |= ord(x) ^ ord(y) -+ return bits == 0 - - def font_size_for_ansi_prompt(self, prompt_demo_ansi): - width = ansi_prompt_line_width(prompt_demo_ansi) -@@ -489,7 +497,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - p = self.path - - authpath = '/' + authkey -- if p.startswith(authpath): -+ if self.secure_startswith(p, authpath): - p = p[len(authpath):] - else: - return self.send_error(403) -@@ -528,7 +536,7 @@ class FishConfigHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): - p = self.path - - authpath = '/' + authkey -- if p.startswith(authpath): -+ if self.secure_startswith(p, authpath): - p = p[len(authpath):] - else: - return self.send_error(403) diff --git a/fish-webconfig-CVE-2014-2914-followup-2.patch b/fish-webconfig-CVE-2014-2914-followup-2.patch deleted file mode 100644 index a2b3c27..0000000 --- a/fish-webconfig-CVE-2014-2914-followup-2.patch +++ /dev/null @@ -1,19 +0,0 @@ -commit 236a0ce46819ce4b93f73ba112e3bfb0726bade7 -Author: Andy Lutomirski -Date: Mon Aug 11 17:51:27 2014 -0700 - - webconfig: Use 16 byte tokens, as advertized - -diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py -index e129c76..2ceb67e 100755 ---- a/share/tools/web_config/webconfig.py -+++ b/share/tools/web_config/webconfig.py -@@ -654,7 +654,7 @@ where = os.path.dirname(sys.argv[0]) - os.chdir(where) - - # Generate a 16-byte random key as a hexadecimal string --authkey = hex(random.getrandbits(16*4))[2:] -+authkey = hex(random.getrandbits(16*8))[2:] - - # Try to find a suitable port - PORT = 8000 diff --git a/fish-webconfig-CVE-2014-2914-followup-3.patch b/fish-webconfig-CVE-2014-2914-followup-3.patch deleted file mode 100644 index 300f54b..0000000 --- a/fish-webconfig-CVE-2014-2914-followup-3.patch +++ /dev/null @@ -1,21 +0,0 @@ -commit f5d81d3beac2542d675af15bf7f71762c456f30d -Author: Andy Lutomirski -Date: Mon Aug 11 17:52:27 2014 -0700 - - webconfig: Get the auth token from os.urandom - - random.getrandbits shouldn't be used for security. - -diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py -index 2ceb67e..f36f63f 100755 ---- a/share/tools/web_config/webconfig.py -+++ b/share/tools/web_config/webconfig.py -@@ -654,7 +654,7 @@ where = os.path.dirname(sys.argv[0]) - os.chdir(where) - - # Generate a 16-byte random key as a hexadecimal string --authkey = hex(random.getrandbits(16*8))[2:] -+authkey = hex(os.urandom(16))[2:] - - # Try to find a suitable port - PORT = 8000 diff --git a/fish-webconfig-CVE-2014-2914-followup-4.patch b/fish-webconfig-CVE-2014-2914-followup-4.patch deleted file mode 100644 index c0a2603..0000000 --- a/fish-webconfig-CVE-2014-2914-followup-4.patch +++ /dev/null @@ -1,28 +0,0 @@ -commit a7f1e81e6ac23fe4b6fd86023681e2975703078d -Author: Andy Lutomirski -Date: Mon Aug 11 18:18:21 2014 -0700 - - webconfig: Convert authkey to hex correctly - -diff --git a/share/tools/web_config/webconfig.py b/share/tools/web_config/webconfig.py -index 5c7d2b9..43d2ced 100755 ---- a/share/tools/web_config/webconfig.py -+++ b/share/tools/web_config/webconfig.py -@@ -17,7 +17,7 @@ else: - from urllib.parse import parse_qs - import webbrowser - import subprocess --import re, socket, os, sys, cgi, select, time, glob, random, string -+import re, socket, os, sys, cgi, select, time, glob, random, string, binascii - try: - import json - except ImportError: -@@ -654,7 +654,7 @@ where = os.path.dirname(sys.argv[0]) - os.chdir(where) - - # Generate a 16-byte random key as a hexadecimal string --authkey = hex(os.urandom(16))[2:] -+authkey = binascii.b2a_hex(os.urandom(16)) - - # Try to find a suitable port - PORT = 8000 diff --git a/fish.spec b/fish.spec index 38a9662..0bcaf39 100644 --- a/fish.spec +++ b/fish.spec @@ -1,6 +1,6 @@ Name: fish -Version: 2.1.0 -Release: 12%{?dist} +Version: 2.1.1 +Release: 1%{?dist} Summary: A friendly interactive shell Group: System Environment/Shells @@ -10,21 +10,9 @@ Source0: http://fishshell.com/files/%{version}/fish-%{version}.ta Patch0: fish-remove-usr-local.patch Patch1: fish-add-link-cxxflags.patch Patch2: fish-use-usrbinpython.patch -Patch3: fish-upstream-CVE-2014-2914.patch -Patch4: fish-upstream-CVE-2014-2914-part2.patch -Patch5: fish-upstream-CVE-2014-2905.patch -Patch6: fish-upstream-CVE-2014-2905-part2.patch -Patch7: fish-upstream-CVE-2014-2906.patch -Patch8: fish-webconfig-CVE-2014-2914-followup-1.patch -Patch9: fish-webconfig-CVE-2014-2914-followup-2.patch -Patch10: fish-webconfig-CVE-2014-2914-followup-3.patch -Patch11: fish-webconfig-CVE-2014-2914-followup-4.patch BuildRequires: ncurses-devel gettext groff doxygen -# Temporary -- remove once CVE-2014-2905 is fixed in a release -BuildRequires: autoconf - %description fish is a fully-equipped command line shell (like bash or zsh) that is smart and user-friendly. fish supports powerful features like syntax @@ -37,15 +25,6 @@ nothing to learn or configure. %patch0 -p1 %patch1 -p1 %patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 # This is unused. If we fiddle with Python versions, its presence will # be confusing. @@ -98,6 +77,9 @@ fi %changelog +* Mon Sep 29 2014 Andy Lutomirski - 2.1.1-1 +- Update to 2.1.1 + * Sat Aug 16 2014 Fedora Release Engineering - 2.1.0-12 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild diff --git a/sources b/sources index ea4ee7f..005ef3d 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -3a29aebde522b8f52d9975d7423db99e fish-2.1.0.tar.gz +0251e6e5f25d1f326e071425ea1dee22 fish-2.1.1.tar.gz