Subject: Gnutls elisp code doesn't properly check for file existence

From: "" <[email-masked]>
Date: Mon, 11 Nov 2013 19:20:08 -0500

The function gnutls-negotiate uses the (potentially)
magic-file-enabled predicate file-exists-p to check for the
"existence" of files in the gnutls-trustfiles list before passing the
raw file paths on as-is to the gnutls c-code.

The elements of the problem are as follows

1. The predicate file-exists-p potentially references
   magic-file-handler(s) so that we really are only testing for the
   existence of the magic-modified file path. At the same time the
   c-code is unaware of magic-file-handlers and assumes the raw path is a
   standard OS-accessible path without any magic modification.

   In particular, I have encountered this inconsistency with the
   cygwin-mount magic file handler, but the same problem will occur with
   *any* magic file handler that causes a non-OS recognizable path to
   test as existing with file-exists-p.

2. When the gnutls c-code is passed a file path that the OS can't find,
   it crashes the gnutls calling function without any human-readable or
   understandable error message. The error code passed back is "-64"
   whic presumably must mean something like "file not found"

3. Gnutls.el implicitly supports cygwin since a cygwin-style trustfile
   is included in gnutls-trustfiles and labeled as such. This presumably
   works fine in a cygwin-compiled version of emacs but if one uses a
   generic windows-native version of Emacs with cygwin-mount as the
   magic file handler then problems (1) & (2) cause gnutls to crash
   every time.

Luckily, there is a near trivial patch that does the following:

i]  If the function 'expand-file-name' has an associated magic file
    handler, the function expand-file-name is called to convert it "to
    absolute, and canonicalize it" (quoted from the function
    definition).

ii] The test for file-exists-p is then wrapped in a 'let' construct
	with file-name-handler-alist set to nil. This effectively shuts
	off magic file handling and ensures that file-exists-p now checks
	for true OS existence of the now potentially expanded path.

iii]The function gnutls-trustfiles is now assured that it will be
    passed an OS-valid path.

--- gnutls.el	2013-03-17 13:52:40.000000000 -0400
+++ gnutls.el.new	2013-10-23 12:47:36.503554500 -0400
@@ -174,7 +174,8 @@
   (let* ((type (or type 'gnutls-x509pki))
          (trustfiles (or trustfiles
                          (delq nil
-                               (mapcar (lambda (f) (and f (file-exists-p f) f))
+                               (mapcar (lambda (f) 
+								   		   (and f 
+										     (if (find-file-name-handler f
												    'expand-file-name)
+								   		      		(setq f (expand-file-name f)))
+											  (let (file-name-handler-alist)
+                                              	   (file-exists-p f)) f))
                                        (if (functionp gnutls-trustfiles)
                                            (funcall gnutls-trustfiles)
                                          gnutls-trustfiles)))))

The patch could of course be extended to 'catch' any error and display
an error message like "Error: gntuls trustfile xxxxx not found" rather
than crashing if somehow there is still a file access issue.

I generate the error using the following:
(require 'cygwin-mount)
(require 'gnutls)
(open-gnutls-stream "tls" "tls-buffer" "imap.gmail.com" "imaps")

The emacs debugger, gives the following results:

Debugger entered--Lisp error: (gnutls-error #<process tls> -64)
  signal(gnutls-error (#<process tls> -64))
  gnutls-negotiate(:process #<process tls> :type gnutls-x509pki
  :hostname "imap.gmail.com")
  open-gnutls-stream("tls" "tls-buffer" "imap.gmail.com" "imaps")
  eval-region(19 83 t #[257 "\300\242b\210\301\207" [(83)
  (open-gnutls-stream "tls" "tls-buffer" "imap.gmail.com" "imaps")] 2
  "\n\n(fn IGNORE)"])  ; Reading at buffer position 83
  eval-defun-2()
  eval-defun(nil)
  call-interactively(eval-defun nil nil)
  command-execute(eval-defun)

--------------------------------------------------------------------------

In GNU Emacs 24.3.1 (i386-mingw-nt6.1.7601)
 of 2013-03-17 on MARVIN
Windowing system distributor `Microsoft Corp.', version 6.1.7601
Configured using:
 `configure --with-gcc (4.7) --cflags
 -ID:/devel/emacs/libs/libXpm-3.5.8/include
 -ID:/devel/emacs/libs/libXpm-3.5.8/src
 -ID:/devel/emacs/libs/libpng-dev_1.4.3-1/include
 -ID:/devel/emacs/libs/zlib-dev_1.2.5-2/include
 -ID:/devel/emacs/libs/giflib-4.1.4-1/include
 -ID:/devel/emacs/libs/jpeg-6b-4/include
 -ID:/devel/emacs/libs/tiff-3.8.2-1/include
 -ID:/devel/emacs/libs/gnutls-3.0.9/include
 -ID:/devel/emacs/libs/libiconv-1.13.1-1-dev/include
 -ID:/devel/emacs/libs/libxml2-2.7.8/include/libxml2'

Important settings:
  value of $LANG: ENU
  locale-coding-system: cp1252
  default enable-multibyte-characters: t

Major mode: Text

Minor modes in effect:
  shell-dirtrack-mode: t
  display-time-mode: t
  tooltip-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  auto-fill-function: do-auto-fill
  transient-mark-mode: t
  abbrev-mode: t

Recent input:
<backspace> <backspace> <backspace> <backspace> <backspace> <tab> r <tab> <return>

Recent messages:
Quit
Deleting...done
(No files need saving)
Marking holidays...done
Marking holidays...done
Undo!
Mark saved where search started [2 times]
Making completion list... [3 times]
delete-backward-char: Text is read-only [2 times]
Making completion list...

Load-path shadows:
None found.

Features:
(shadow sort emacsbug echistory chistory solar cal-dst cal-julian
cal-hebrew holidays hol-loaddefs cal-move cal-tex jjk-calendar cal-menu
calendar cal-loaddefs dired-aux browse-url url-util url-parse url-vars
ruler-mode hl-line hexl eldoc mule-util tramp-cmds noutline outline
easy-mmode tramp-cache tramp-sh tramp tramp-compat tramp-loaddefs shell
pcomplete find-func ebuff-menu pp misearch multi-isearch nxml-uchnm
rng-xsd xsd-regexp rng-cmpct rng-nxml rng-valid rng-loc rng-uri
rng-parse nxml-parse rng-match rng-dt rng-util rng-pttrn nxml-ns
nxml-mode nxml-outln nxml-rap nxml-util nxml-glyph nxml-enc xmltok
network-stream starttls tls message idna format-spec mml mml-sec
mm-decode mm-bodies mm-encode gmm-utils mailheader vm-imap bbdb-gui
help-mode flyspell ispell cl-macs gv vm-reply easymenu jjk-vm dired
vm-mime-display-internal-application vm-ps-print bbdb-vm vm-autoload
bbdb-snarf mail-extr rfc822 bbdb-autoloads bbdb-hooks mail-parse rfc2231
bbdb-com mailabbrev cl vcard vm-vcard vm-pine smtpmail bbdb timezone
sendmail rfc2047 rfc2045 ietf-drums mail-utils vm-rfaddons vm-menu
vm-window vm-toolbar vm-folder vm-mime vm-undo vm-virtual
vm-summary-faces vm-summary vm-mouse vm-page vm-motion vm-minibuf
vm-message vm-misc vm-macro vm-autoloads vm-vars vm-version vm
jjk-comments jjk-load ps-print ps-def lpr jjk-print ibm-keymaps
jjk-frames jjk-hooks jjk-keymaps ehelp electric uniquify warnings
arc-mode archive-mode jjk-lib epa-file epa derived epg epg-config advice
help-fns cl-lib advice-preload auth-source eieio byte-opt bytecomp
byte-compile cconv gnus-util mm-util mail-prsvr password-cache
cygwin-mount ange-ftp comint ansi-color ring server time time-date
tooltip ediff-hook vc-hooks lisp-float-type mwheel dos-w32 ls-lisp
w32-common-fns disp-table w32-win w32-vars tool-bar dnd fontset image
regexp-opt fringe tabulated-list newcomment lisp-mode register page
menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core frame cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer loaddefs
button faces cus-face macroexp files text-properties overlay sha1 md5
base64 format env code-pages mule custom widget hashtable-print-readable
backquote make-network-process w32 multi-tty emacs)

In GNU Emacs 24.3.1 (i386-mingw-nt6.1.7601)
 of 2013-03-17 on MARVIN
Windowing system distributor `Microsoft Corp.', version 6.1.7601
Configured using:
 `configure --with-gcc (4.7) --cflags
 -ID:/devel/emacs/libs/libXpm-3.5.8/include
 -ID:/devel/emacs/libs/libXpm-3.5.8/src
 -ID:/devel/emacs/libs/libpng-dev_1.4.3-1/include
 -ID:/devel/emacs/libs/zlib-dev_1.2.5-2/include
 -ID:/devel/emacs/libs/giflib-4.1.4-1/include
 -ID:/devel/emacs/libs/jpeg-6b-4/include
 -ID:/devel/emacs/libs/tiff-3.8.2-1/include
 -ID:/devel/emacs/libs/gnutls-3.0.9/include
 -ID:/devel/emacs/libs/libiconv-1.13.1-1-dev/include
 -ID:/devel/emacs/libs/libxml2-2.7.8/include/libxml2'

Important settings:
  value of $LANG: ENU
  locale-coding-system: cp1252
  default enable-multibyte-characters: t

Major mode: Text

Minor modes in effect:
  shell-dirtrack-mode: t
  display-time-mode: t
  tooltip-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  auto-fill-function: do-auto-fill
  transient-mark-mode: t
  abbrev-mode: t

Recent input:
<tab> r <tab> <return>

Recent messages:
Quit
Deleting...done
Undo!
Mark saved where search started [2 times]
Making completion list... [3 times]
delete-backward-char: Text is read-only [2 times]
Making completion list...

Load-path shadows:
None found.

Features:
(shadow sort emacsbug echistory chistory solar cal-dst cal-julian
cal-hebrew holidays hol-loaddefs cal-move cal-tex jjk-calendar
cal-menu calendar cal-loaddefs dired-aux browse-url url-util url-parse
url-vars ruler-mode hl-line hexl eldoc mule-util tramp-cmds noutline
outline easy-mmode tramp-cache tramp-sh tramp tramp-compat
tramp-loaddefs shell pcomplete find-func ebuff-menu pp misearch
multi-isearch nxml-uchnm rng-xsd xsd-regexp rng-cmpct rng-nxml
rng-valid rng-loc rng-uri rng-parse nxml-parse rng-match rng-dt
rng-util rng-pttrn nxml-ns nxml-mode nxml-outln nxml-rap nxml-util
nxml-glyph nxml-enc xmltok network-stream starttls tls message idna
format-spec mml mml-sec mm-decode mm-bodies mm-encode gmm-utils
mailheader vm-imap bbdb-gui help-mode flyspell ispell cl-macs gv
vm-reply easymenu jjk-vm dired vm-mime-display-internal-application
vm-ps-print bbdb-vm vm-autoload bbdb-snarf mail-extr rfc822
bbdb-autoloads bbdb-hooks mail-parse rfc2231 bbdb-com mailabbrev cl
vcard vm-vcard vm-pine smtpmail bbdb timezone sendmail rfc2047 rfc2045
ietf-drums mail-utils vm-rfaddons vm-menu vm-window vm-toolbar
vm-folder vm-mime vm-undo vm-virtual vm-summary-faces vm-summary
vm-mouse vm-page vm-motion vm-minibuf vm-message vm-misc vm-macro
vm-autoloads vm-vars vm-version vm ehelp electric uniquify warnings
arc-mode archive-mode epa-file epa derived epg epg-config advice
help-fns cl-lib advice-preload auth-source eieio byte-opt bytecomp
byte-compile cconv gnus-util mm-util mail-prsvr password-cache
cygwin-mount ange-ftp comint ansi-color ring server time time-date
tooltip ediff-hook vc-hooks lisp-float-type mwheel dos-w32 ls-lisp
w32-common-fns disp-table w32-win w32-vars tool-bar dnd fontset image
regexp-opt fringe tabulated-list newcomment lisp-mode register page
menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core frame cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer
loaddefs button faces cus-face macroexp files text-properties overlay
sha1 md5 base64 format env code-pages mule custom widget
hashtable-print-readable backquote make-network-process w32 multi-tty
emacs)