unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
@ 2023-02-22 14:35 Xi Lu
  2023-02-22 15:29 ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: Xi Lu @ 2023-02-22 14:35 UTC (permalink / raw)
  To: 61709; +Cc: Xi Lu

* lisp/filesets.el:
(filesets-select-command, filesets-which-command,
filesets-spawn-external-viewer, filesets-run-cmd): Add `shell-quote-argument'
---
 lisp/filesets.el | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/lisp/filesets.el b/lisp/filesets.el
index 1b7e6ffa81f..96ac11bb40b 100644
--- a/lisp/filesets.el
+++ b/lisp/filesets.el
@@ -165,14 +165,15 @@ filesets-select-command
   "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))))
+		       (shell-quote-argument cmd-list)
+                       (shell-quote-argument 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."
@@ -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))))
 	  (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)
-- 
2.39.2






^ permalink raw reply related	[flat|nested] 6+ messages in thread

* bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
  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
  2024-02-05  6:13   ` lux
  0 siblings, 2 replies; 6+ messages in thread
From: Eli Zaretskii @ 2023-02-22 15:29 UTC (permalink / raw)
  To: Xi Lu; +Cc: 61709

> 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.





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
  2023-02-22 15:29 ` Eli Zaretskii
@ 2023-02-23 13:17   ` lux
  2023-02-23 15:58     ` Eli Zaretskii
  2024-02-05  6:13   ` lux
  1 sibling, 1 reply; 6+ messages in thread
From: lux @ 2023-02-23 13:17 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 61709

[-- 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


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
  2023-02-23 13:17   ` lux
@ 2023-02-23 15:58     ` Eli Zaretskii
  2024-02-05  7:29       ` Stefan Kangas
  0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2023-02-23 15:58 UTC (permalink / raw)
  To: lux; +Cc: 61709

> From: lux <lx@shellcodes.org>
> Cc: 61709@debbugs.gnu.org
> Date: Thu, 23 Feb 2023 21:17:12 +0800
> 
> 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.

Thanks.  I hesitate installing this because I don't myself use
filesets, and we don't have tests for it.  So I'm not sure how to
ensure that we don't break this package.

Does someone else here use filesets?





^ permalink raw reply	[flat|nested] 6+ messages in thread

* bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
  2023-02-22 15:29 ` Eli Zaretskii
  2023-02-23 13:17   ` lux
@ 2024-02-05  6:13   ` lux
  1 sibling, 0 replies; 6+ messages in thread
From: lux @ 2024-02-05  6:13 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 61709

[-- Attachment #1: Type: text/plain, Size: 1782 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.
> 
> 
> 

This patch went unaddressed for a long time, so just to be on the safe side, I
only remove the `filesets-select-command' function.


[-- Attachment #2: 0001-Removed-the-filesets-select-command-which-was-unused.patch --]
[-- Type: text/x-patch, Size: 2110 bytes --]

From 8f8db0851e9fd265a6bb106f3adf0168195162b8 Mon Sep 17 00:00:00 2001
From: Xi Lu <lx@shellcodes.org>
Date: Mon, 5 Feb 2024 13:41:13 +0800
Subject: [PATCH] Removed the `filesets-select-command', which was unused and
 unsafe.

* lisp/filesets.el: Removed the `filesets-select-command'.
---
 lisp/filesets.el | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/lisp/filesets.el b/lisp/filesets.el
index 4e2de8fed1b..23a8dbc4e85 100644
--- a/lisp/filesets.el
+++ b/lisp/filesets.el
@@ -161,15 +161,6 @@ '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)))
@@ -546,18 +537,7 @@ filesets-commands
                                        (function :tag "Function"))))))
 
 (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")
+  (let ((ps-cmd  "ggv")
        (pdf-cmd "xpdf")
        (dvi-cmd "xdvi")
        (doc-cmd "antiword")
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* bug#61709: [PATCH] Security hardening: safely invoke `shell-command*' function.
  2023-02-23 15:58     ` Eli Zaretskii
@ 2024-02-05  7:29       ` Stefan Kangas
  0 siblings, 0 replies; 6+ messages in thread
From: Stefan Kangas @ 2024-02-05  7:29 UTC (permalink / raw)
  To: Eli Zaretskii, lux; +Cc: 61709-done

Version: 30.1

Eli Zaretskii <eliz@gnu.org> writes:

>> From: lux <lx@shellcodes.org>
>> Cc: 61709@debbugs.gnu.org
>> Date: Thu, 23 Feb 2023 21:17:12 +0800
>>
>> 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.

Thank you for paying attention to these issues.

Pushed to master as commit 7756e9c7361, and closing the bug.

> Thanks.  I hesitate installing this because I don't myself use
> filesets, and we don't have tests for it.  So I'm not sure how to
> ensure that we don't break this package.
>
> Does someone else here use filesets?

Let's hope that if it breaks something, someone will report a bug.  :-/





^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-02-05  7:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
2023-02-23 15:58     ` Eli Zaretskii
2024-02-05  7:29       ` Stefan Kangas
2024-02-05  6:13   ` lux

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).