unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Robert Pluim <rpluim@gmail.com>
To: Ulrich Mueller <ulm@gentoo.org>
Cc: Po Lu <luangruo@yahoo.com>,  emacs-devel@gnu.org
Subject: Re: emacs-29 3c1693d08b0: Fix Elisp code injection vulnerability in emacsclient-mail.desktop
Date: Wed, 08 Mar 2023 11:37:06 +0100	[thread overview]
Message-ID: <87ilfbpm0d.fsf@gmail.com> (raw)
In-Reply-To: <ucz5jsogr@gentoo.org> (Ulrich Mueller's message of "Wed, 08 Mar 2023 08:15:48 +0100")

>>>>> On Wed, 08 Mar 2023 08:15:48 +0100, Ulrich Mueller <ulm@gentoo.org> said:

>>>>> On Wed, 08 Mar 2023, Po Lu wrote:
    >> Ulrich Mueller <ulm@gentoo.org> writes:
    >>> Then the desktop file won't work, obviously. The problem is that
    >>> ${PARAMETER//PATTERN/STRING} substitution is not available in POSIX
    >>> parameter expansion. So with POSIX sh, an external program (e.g. sed)
    >>> would have to be called.
    >>> 
    >>> The long term solution (suggested by Stefan Monnier) might be to add
    >>> a --funcall option to emacsclient. Then there would be no need for a
    >>> shell wrapper, in the first place.
    >>> 
    >>> Should the Makefile skip installation of emacsclient-mail.desktop
    >>> when bash isn't available on the system?

Then youʼd require every distro builder to have bash available in
their build setup

    >> Could we install this change not on emacs-29, but on master?

    >> I don't think the problem it solves is severe, nor a regression from
    >> Emacs 28.  It is rather a minor nusiance with certain URLs.

    Ulrich> Seriously? It is a vulnerability that allows remote injection of
    Ulrich> arbitrary Elisp code through a crafted "mailto" URI.

Itʼs certainly not a regression, but it is fairly serious. We could
mitigate it somewhat by adding '--funcall', I guess.

The last time --funcall was discussed, there was no consensus on how
arguments should be handled, so Iʼve just gone ahead and implemented
one variant. We could add any restrictions we like on the server side,
it currently just disallows direct `eval'

Not for emacs-29, I think.

Robert
-- 

diff --git c/lib-src/emacsclient.c i/lib-src/emacsclient.c
index 698bf9b50ae..d408af6658f 100644
--- c/lib-src/emacsclient.c
+++ i/lib-src/emacsclient.c
@@ -113,6 +113,9 @@ #define DEFAULT_TIMEOUT (30)
 /* True means don't print values returned from emacs. --suppress-output.  */
 static bool suppress_output;
 
+/* True means arg is a function to be called.  --funcall.  */
+static bool funcall;
+
 /* True means args are expressions to be evaluated.  --eval.  */
 static bool eval;
 
@@ -168,6 +171,7 @@ #define DEFAULT_TIMEOUT (30)
   { "no-wait",	no_argument,	   NULL, 'n' },
   { "quiet",	no_argument,	   NULL, 'q' },
   { "suppress-output", no_argument, NULL, 'u' },
+  { "funcall",	no_argument,	   NULL, 'l' },
   { "eval",	no_argument,	   NULL, 'e' },
   { "help",	no_argument,	   NULL, 'H' },
   { "version",	no_argument,	   NULL, 'V' },
@@ -191,7 +195,7 @@ #define DEFAULT_TIMEOUT (30)
 /* Short options, in the same order as the corresponding long options.
    There is no '-p' short option.  */
 static char const shortopts[] =
-  "nqueHVtca:F:w:"
+  "nquleHVtca:F:w:"
 #ifdef SOCKETS_IN_FILE_SYSTEM
   "s:"
 #endif
@@ -548,6 +552,10 @@ decode_options (int argc, char **argv)
 	    }
 	  break;
 
+	case 'l':
+	  funcall = true;
+	  break;
+
 	case 'e':
 	  eval = true;
 	  break;
@@ -689,6 +697,7 @@ print_help_and_exit (void)
 ", "\
 -F ALIST, --frame-parameters=ALIST\n\
 			Set the parameters of a new frame\n\
+-l, --funcall    	Evaluate the FILE argument as function to call\n\
 -e, --eval    		Evaluate the FILE arguments as ELisp expressions\n\
 -n, --no-wait		Don't wait for the server to return\n\
 -w, --timeout=SECONDS	Seconds to wait before timing out\n\
@@ -2067,11 +2076,28 @@ main (int argc, char **argv)
   if (create_frame && !tty)
     send_to_emacs (emacs_socket, "-window-system ");
 
+  bool funcall_sent = false;
+
   if (optind < argc)
     {
       for (int i = optind; i < argc; i++)
 	{
 
+	  if (funcall)
+            {
+	      /* funcall applies the function to all subsequent
+		 arguments, unlike eval, which evaluates each
+		 expression individually.  */
+	      if (!funcall_sent)
+		{
+		  send_to_emacs (emacs_socket, "-funcall ");
+		  funcall_sent = true;
+		}
+              quote_argument (emacs_socket, argv[i]);
+              send_to_emacs (emacs_socket, " ");
+              continue;
+            }
+
 	  if (eval)
             {
               /* Don't prepend cwd or anything like that.  */
@@ -2139,7 +2165,7 @@ main (int argc, char **argv)
   send_to_emacs (emacs_socket, "\n");
 
   /* Wait for an answer. */
-  if (!eval && !tty && !nowait && !quiet && 0 <= process_grouping ())
+  if (!funcall && !eval && !tty && !nowait && !quiet && 0 <= process_grouping ())
     {
       printf ("Waiting for Emacs...");
       skiplf = false;
diff --git c/lisp/server.el i/lisp/server.el
index eaf24a770e4..e5ea2b14b3b 100644
--- c/lisp/server.el
+++ i/lisp/server.el
@@ -1295,6 +1295,29 @@ server-process-filter
                                proc))
                  (setq filepos nil))
 
+                ;; -funcall FUNCTION:  Call the function, and pass it any subsequent command line args
+                ("-funcall"
+                 (if use-current-frame
+                     (setq use-current-frame 'always))
+                 (let ((fun (pop args-left))
+                       args real-fun)
+                   (if coding-system
+                       (setq fun (decode-coding-string fun coding-system)))
+                   (when fun
+                     (setq real-fun (intern-soft fun))
+                     (when (and (fboundp real-fun)
+                                (not (eq real-fun 'eval)))
+                       (setq args (mapcar
+                                   (lambda (a)
+                                     (if coding-system
+                                         (setq a (decode-coding-string a coding-system)))
+                                     a)
+                                   args-left))
+                       (setq args-left nil)
+                       (push (lambda () (apply real-fun args))
+                             commands))))
+                 (setq filepos nil))
+
                 ;; -eval EXPR:  Evaluate a Lisp expression.
                 ("-eval"
                  (if use-current-frame



  parent reply	other threads:[~2023-03-08 10:37 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <167821009581.14664.5608674978571454819@vcs2.savannah.gnu.org>
     [not found] ` <20230307172816.2D56BC13915@vcs2.savannah.gnu.org>
2023-03-08  0:27   ` emacs-29 3c1693d08b0: Fix Elisp code injection vulnerability in emacsclient-mail.desktop Po Lu
2023-03-08  2:14     ` Ulrich Mueller
2023-03-08  2:24       ` Po Lu
2023-03-08  7:15         ` Ulrich Mueller
2023-03-08  8:09           ` Po Lu
2023-03-08  8:32             ` Ulrich Mueller
2023-03-08 10:29               ` Po Lu
2023-03-08 10:39                 ` Ulrich Mueller
2023-03-08 10:44                   ` Robert Pluim
2023-03-08 11:08                     ` Ulrich Mueller
2023-03-08 11:29                       ` Ulrich Mueller
2023-03-08 11:47                         ` Robert Pluim
2023-03-08 14:17                           ` Eli Zaretskii
2023-03-08 15:47                             ` Robert Pluim
2023-03-08 17:03                             ` Jim Porter
2023-03-08 17:20                               ` Robert Pluim
2023-03-08 17:41                                 ` Eli Zaretskii
2023-03-08 18:54                                 ` Jim Porter
2023-03-09  9:30                                   ` Robert Pluim
2023-03-09 10:22                                     ` Po Lu
2023-03-09 10:50                                       ` Robert Pluim
2023-03-09 18:36                                       ` Jim Porter
2023-03-08 11:44                       ` Po Lu
2023-03-08 14:14                       ` Eli Zaretskii
2023-03-09  0:50                         ` Po Lu
2023-03-09  7:19                           ` Eli Zaretskii
2023-03-09  7:25                             ` Po Lu
2023-03-09  7:49                               ` Manuel Giraud via Emacs development discussions.
2023-03-09  8:20                             ` tomas
2023-03-08 10:58                   ` Po Lu
2023-03-08 11:44                     ` Ulrich Mueller
2023-03-08 14:13                     ` Eli Zaretskii
2023-03-08 14:05                   ` Eli Zaretskii
2023-03-08 10:37           ` Robert Pluim [this message]
2023-03-08 12:14             ` Ulrich Mueller
2023-03-08 15:49               ` Robert Pluim
2023-03-08 14:04             ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87ilfbpm0d.fsf@gmail.com \
    --to=rpluim@gmail.com \
    --cc=emacs-devel@gnu.org \
    --cc=luangruo@yahoo.com \
    --cc=ulm@gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).