unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
From: lux <lx@shellcodes.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 61709@debbugs.gnu.org
Subject: bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
Date: Thu, 23 Feb 2023 21:17:12 +0800	[thread overview]
Message-ID: <tencent_84BAE1E5C1009C08331835C035527704F208@qq.com> (raw)
In-Reply-To: <83y1opra5o.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 2700 bytes --]

On Wed, 2023-02-22 at 17:29 +0200, Eli Zaretskii wrote:
> > Cc: Xi Lu <lx@shellcodes.org>
> > From: Xi Lu <lx@shellcodes.org>
> > Date: Wed, 22 Feb 2023 22:35:54 +0800
> > 
> >  (defun filesets-which-command-p (cmd)
> >    "Call \"which CMD\" and return non-nil if the command was
> > found."
> > @@ -1264,9 +1265,11 @@ filesets-spawn-external-viewer
> >                   (funcall vwr file)
> >                   nil)
> >                  (co-flag
> > -                 (shell-command-to-string (format "%s %s" vwr
> > args)))
> > +                 (shell-command-to-string (shell-quote-argument
> > +                                            (format "%s %s" vwr
> > args))))
> >                  (t
> > -                 (shell-command (format "%s %s&" vwr args))
> > +                 (shell-command (shell-quote-argument
> > +                                  (format "%s %s&" vwr args)))
> >                   nil))))
> 
> These two cannot be right: you are quoting several separate
> command-line arguments.
> 
> >           (if co-flag
> >               (progn
> > @@ -1578,7 +1581,7 @@ filesets-run-cmd
> >                                    " "))
> >                                  (cmd (concat fn " " args)))
> >                             (filesets-cmd-show-result
> > -                            cmd (shell-command-to-string cmd))))
> > +                            cmd (shell-command-to-string (shell-
> > quote-argument cmd)))))
> >                          ((symbolp fn)
> >                           (apply fn
> >                                  (mapcan (lambda (this)
> 
> I think this is also wrong: cmd is not a single word.
> 
> In general, you cannot quote arbitrary parts of a shell command, you
> can only quote each command-line argument separately.
> 
> 
> 

You're right, thank you. I rewrited this patch.

Let me briefly explain this patch:

1. I think `filesets-select-command' not need fixed, because it not
used, and I cleaned up relevant old comments in `filesets-external-
viewers'.

2. Using `shell-quote-argument' to replace `filesets-quote' and
`(format "%S" ...)'. Because in the shell, double quotation marks can
still execute unexpected code, such as $(), `command` and $var.




[-- Attachment #2: 0001-Security-hardening-safely-invoke-shell-command-funct.patch --]
[-- Type: text/x-patch, Size: 3960 bytes --]

From 6b85abb2de545094a3725d003a4ddb744b1e1eec Mon Sep 17 00:00:00 2001
From: Xi Lu <lx@shellcodes.org>
Date: Thu, 23 Feb 2023 20:58:00 +0800
Subject: [PATCH] Security hardening: safely invoke `shell-command*' function.

* lisp/filesets.el:
(filesets-select-command, filesets-quote): Remove unused function.
(filesets-external-viewers): Remove old comments.
(filesets-which-command, filesets-get-quoted-selection,
filesets-spawn-external-viewer): Add `shell-quote-argument'.
---
 lisp/filesets.el | 40 +++++++++-------------------------------
 1 file changed, 9 insertions(+), 31 deletions(-)

diff --git a/lisp/filesets.el b/lisp/filesets.el
index 1b7e6ffa81f..c4d51ccaf4a 100644
--- a/lisp/filesets.el
+++ b/lisp/filesets.el
@@ -161,18 +161,9 @@ 'filesets-some
 (define-obsolete-function-alias 'filesets-member #'cl-member "28.1")
 (define-obsolete-function-alias 'filesets-sublist #'seq-subseq "28.1")
 
-(defun filesets-select-command (cmd-list)
-  "Select one command from CMD-LIST -- a string with space separated names."
-  (let ((this (shell-command-to-string
-	       (format "which --skip-alias %s 2> %s | head -n 1"
-		       cmd-list null-device))))
-    (if (equal this "")
-	nil
-      (file-name-nondirectory (substring this 0 (- (length this) 1))))))
-
 (defun filesets-which-command (cmd)
   "Call \"which CMD\"."
-  (shell-command-to-string (format "which %s" cmd)))
+  (shell-command-to-string (format "which %s" (shell-quote-argument cmd))))
 
 (defun filesets-which-command-p (cmd)
   "Call \"which CMD\" and return non-nil if the command was found."
@@ -551,16 +542,6 @@ filesets-commands
 
 (defcustom filesets-external-viewers
   (let
-      ;; ((ps-cmd  (or (and (boundp 'my-ps-viewer) my-ps-viewer)
-      ;;    	    (filesets-select-command "ggv gv")))
-      ;;  (pdf-cmd (or (and (boundp 'my-ps-viewer) my-pdf-viewer)
-      ;;    	    (filesets-select-command "xpdf acroread")))
-      ;;  (dvi-cmd (or (and (boundp 'my-ps-viewer) my-dvi-viewer)
-      ;;    	    (filesets-select-command "xdvi tkdvi")))
-      ;;  (doc-cmd (or (and (boundp 'my-ps-viewer) my-doc-viewer)
-      ;;    	    (filesets-select-command "antiword")))
-      ;;  (pic-cmd (or (and (boundp 'my-ps-viewer) my-pic-viewer)
-      ;;    	    (filesets-select-command "gqview ee display"))))
       ((ps-cmd  "ggv")
        (pdf-cmd "xpdf")
        (dvi-cmd "xdvi")
@@ -1089,10 +1070,6 @@ filesets-directory-files
    (t
     (error "Filesets: %s does not exist" dir))))
 
-(defun filesets-quote (txt)
-  "Return TXT in quotes."
-  (concat "\"" txt "\""))
-
 (defun filesets-get-selection ()
   "Get the text between mark and point -- i.e. the selection or region."
   (let ((m (mark))
@@ -1103,7 +1080,7 @@ filesets-get-selection
 
 (defun filesets-get-quoted-selection ()
   "Return the currently selected text in quotes."
-  (filesets-quote (filesets-get-selection)))
+  (shell-quote-argument (filesets-get-selection)))
 
 (defun filesets-get-shortcut (n)
   "Create menu shortcuts based on number N."
@@ -1250,12 +1227,13 @@ filesets-spawn-external-viewer
 		       (if fmt
 			   (mapconcat
 			    (lambda (this)
-			      (if (stringp this) (format this file)
-				(format "%S" (if (functionp this)
-				                 (funcall this)
-				               this))))
+			      (if (stringp this)
+                                  (format this (shell-quote-argument file))
+				(shell-quote-argument (if (functionp this)
+				                          (funcall this)
+				                        this))))
 			    fmt "")
-			 (format "%S" file))))
+			 (shell-quote-argument file))))
 	       (output
 		(cond
 		 ((and (functionp vwr) co-flag)
@@ -1264,7 +1242,7 @@ filesets-spawn-external-viewer
 		  (funcall vwr file)
 		  nil)
 		 (co-flag
-		  (shell-command-to-string (format "%s %s" vwr args)))
+                  (shell-command-to-string (format "%s %s" vwr args)))
 		 (t
 		  (shell-command (format "%s %s&" vwr args))
 		  nil))))
-- 
2.39.2


  reply	other threads:[~2023-02-23 13:17 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-22 14:35 bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function Xi Lu
2023-02-22 15:29 ` Eli Zaretskii
2023-02-23 13:17   ` lux [this message]
2023-02-23 15:58     ` Eli Zaretskii
2024-02-05  7:29       ` Stefan Kangas
2024-02-05  6:13   ` lux

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=tencent_84BAE1E5C1009C08331835C035527704F208@qq.com \
    --to=lx@shellcodes.org \
    --cc=61709@debbugs.gnu.org \
    --cc=eliz@gnu.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).