public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/emacs] f44: Fix CVE-2026-79992: Local shell command injection through the user field in emacs tramp
@ 2026-08-28 11:32 Peter Oliver
  0 siblings, 0 replies; only message in thread
From: Peter Oliver @ 2026-08-28 11:32 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/emacs
Branch : f44
Commit : 9a5991bf86bf4efbcf874d753ee3831a3cf924c5
Author : Peter Oliver <git@mavit.org.uk>
Date   : 2026-08-28T12:31:11+01:00
Stats  : +358/-0 in 2 file(s)
URL    : https://src.fedoraproject.org/rpms/emacs/c/9a5991bf86bf4efbcf874d753ee3831a3cf924c5?branch=f44

Log:
Fix CVE-2026-79992: Local shell command injection through the user field in emacs tramp

---
diff --git a/05_all_tramp.patch b/05_all_tramp.patch
new file mode 100644
index 0000000..2e5a6a8
--- /dev/null
+++ b/05_all_tramp.patch
@@ -0,0 +1,353 @@
+Fix local command execution vulnerability in tramp
+Original patch by Michael Albinus <michael.albinus@gmx.de>,
+backported from Emacs 31
+
+--- emacs-30.2/doc/misc/tramp.texi
++++ emacs-30.2/doc/misc/tramp.texi
+@@ -3601,7 +3601,9 @@
+ By default, @value{tramp} will use the current local user name as the
+ remote user name for log in to the remote host.  Specifying a
+ different name using the proper syntax will override this default
+-behavior: @file{@trampfn{method,user@@host,path/to/file}}.
++behavior: @file{@trampfn{method,user@@host,path/to/file}}.  The user
++name can also be taken from an environment variable, like
++@file{@trampfn{method,@env{$MY_REMOTE_USER}@@host,path/to/file}}.
+ 
+ @file{@trampfn{ssh,daniel@@melancholia,.emacs}} is for file
+ @file{.emacs} in @samp{daniel}'s home directory on the host,
+--- emacs-30.2/lisp/net/tramp-gvfs.el
++++ emacs-30.2/lisp/net/tramp-gvfs.el
+@@ -1241,7 +1241,7 @@
+ 	  (when (string-match
+ 		 (rx bos "/" (+ (not "/")) (group "/.." (? "/"))) localname)
+ 	    (setq localname (replace-match "/" t t localname 1)))
+-	(when (string-match (rx bol "/.." (? "/")) localname)
++	(when (string-match (rx bos "/.." (? "/")) localname)
+ 	  (setq localname (replace-match "/" t t localname))))
+       ;; There might be a double slash.  Remove this.
+       (while (string-match "//" localname)
+@@ -1335,8 +1335,8 @@
+   (with-parsed-tramp-file-name filename nil
+     (setq localname (file-name-unquote localname))
+     (if (or (and (string-match-p
+-		  (rx bol (| "afp" (: "dav" (? "s")) "smb") eol) method)
+-		 (string-match-p (rx bol (? "/") (+ (not "/")) eol) localname))
++		  (rx bos (| "afp" (: "dav" (? "s")) "smb") eos) method)
++		 (string-match-p (rx bos (? "/") (+ (not "/")) eos) localname))
+ 	    (string-equal localname "/"))
+ 	(tramp-gvfs-get-root-attributes filename)
+       (assoc
+@@ -1773,14 +1773,14 @@
+   "Retrieve file name from D-Bus OBJECT-PATH."
+   (dbus-unescape-from-identifier
+    (replace-regexp-in-string
+-    (rx bol (* nonl) "/" (group (+ (not "/"))) eol) "\\1" object-path)))
++    (rx bos (* nonl) "/" (group (+ (not "/"))) eos) "\\1" object-path)))
+ 
+ (defun tramp-gvfs-url-host (url)
+   "Return the host name part of URL, a string.
+ We cannot use `url-host', because `url-generic-parse-url' returns
+ a downcased host name only."
+   (and (stringp url)
+-       (string-match (rx bol (+ alnum) "://" (group (+ (not (any "/:"))))) url)
++       (string-match (rx bos (+ alnum) "://" (group (+ (not (any "/:"))))) url)
+        (match-string 1 url)))
+ 
+ ;; This is used in GNU ELPA package tramp-locproc.el.
+@@ -1934,7 +1934,7 @@
+ 		   (cadr (assoc "ssl" (cadr mount-spec)))))
+ 	     (uri (tramp-gvfs-dbus-byte-array-to-string
+ 		   (cadr (assoc "uri" (cadr mount-spec))))))
+-	(when (string-match (rx bol (group (| "afp" "smb"))) method)
++	(when (string-match (rx bos (group (| "afp" "smb"))) method)
+ 	  (setq method (match-string 1 method)))
+ 	(when (and (string-equal "dav" method) (string-equal "true" ssl))
+ 	  (setq method "davs"))
+@@ -2034,7 +2034,7 @@
+ 		      (or
+ 		       (cadr (assoc "share" (cadr mount-spec)))
+ 		       (cadr (assoc "volume" (cadr mount-spec)))))))
+-	 (when (string-match (rx bol (group (| "afp" "smb"))) method)
++	 (when (string-match (rx bos (group (| "afp" "smb"))) method)
+ 	   (setq method (match-string 1 method)))
+ 	 (when (and (string-equal "dav" method) (string-equal "true" ssl))
+ 	   (setq method "davs"))
+@@ -2067,7 +2067,7 @@
+ 		(string-equal host (tramp-file-name-host vec))
+ 		(string-equal port (tramp-file-name-port vec))
+ 		(string-match-p
+-		 (rx bol "/" (literal (or share "")))
++		 (rx bos "/" (literal (or share "")))
+ 		 (tramp-file-name-unquote-localname vec)))
+ 	   ;; Set mountpoint and location.
+ 	   (tramp-set-file-property vec "/" "fuse-mountpoint" fuse-mountpoint)
+@@ -2093,7 +2093,7 @@
+ (defun tramp-gvfs-mount-spec-entry (key value)
+   "Construct a mount-spec entry to be used in a mount_spec.
+ It was \"a(say)\", but has changed to \"a{sv})\"."
+-  (if (string-match-p (rx bol "(aya{sv})") tramp-gvfs-mountlocation-signature)
++  (if (string-match-p (rx bos "(aya{sv})") tramp-gvfs-mountlocation-signature)
+       (list :dict-entry key
+ 	    (list :variant (tramp-gvfs-dbus-string-to-byte-array value)))
+     (list :struct key (tramp-gvfs-dbus-string-to-byte-array value))))
+@@ -2112,9 +2112,9 @@
+ 		   (tramp-media-device-port media) (tramp-file-name-port vec)))
+ 	 (localname (tramp-file-name-unquote-localname vec))
+ 	 (share (when (string-match
+-		       (rx bol (? "/") (group (+ (not "/")))) localname)
++		       (rx bos (? "/") (group (+ (not "/")))) localname)
+ 		  (match-string 1 localname)))
+-	 (ssl (if (string-match-p (rx bol (| "davs" "nextcloud")) method)
++	 (ssl (if (string-match-p (rx bos (| "davs" "nextcloud")) method)
+ 		  "true" "false"))
+ 	 (mount-spec
+           `(:array
+@@ -2123,7 +2123,7 @@
+                 (list (tramp-gvfs-mount-spec-entry "type" "smb-share")
+                       (tramp-gvfs-mount-spec-entry "server" host)
+                       (tramp-gvfs-mount-spec-entry "share" share)))
+-               ((string-match-p (rx bol (| "davs" "nextcloud")) method)
++               ((string-match-p (rx bos (| "davs" "nextcloud")) method)
+                 (list (tramp-gvfs-mount-spec-entry "type" "dav")
+                       (tramp-gvfs-mount-spec-entry "host" host)
+                       (tramp-gvfs-mount-spec-entry "ssl" ssl)))
+@@ -2137,7 +2137,7 @@
+                ((string-equal "nextcloud" method)
+                 (list (tramp-gvfs-mount-spec-entry "type" "owncloud")
+                       (tramp-gvfs-mount-spec-entry "host" host)))
+-               ((string-match-p (rx bol "http") method)
++               ((string-match-p (rx bos "http") method)
+                 (list (tramp-gvfs-mount-spec-entry "type" "http")
+                       (tramp-gvfs-mount-spec-entry
+ 		       "uri"
+@@ -2154,8 +2154,8 @@
+             ,@(when port
+                 (list (tramp-gvfs-mount-spec-entry "port" port)))))
+ 	 (mount-pref
+-          (if (and (string-match-p (rx bol "dav") method)
+-                   (string-match (rx bol (? "/") (+ (not "/"))) localname))
++          (if (and (string-match-p (rx bos "dav") method)
++                   (string-match (rx bos (? "/") (+ (not "/"))) localname))
+               (match-string 0 localname)
+ 	    (tramp-gvfs-get-remote-prefix vec))))
+ 
+--- emacs-30.2/lisp/net/tramp-rclone.el
++++ emacs-30.2/lisp/net/tramp-rclone.el
+@@ -191,7 +191,7 @@
+   (with-tramp-connection-property nil "rclone-device-names"
+     (tramp-compat-seq-keep
+      (lambda (line)
+-       (when (string-match (rx bol (group (+ (not blank))) ":" eol) line)
++       (when (string-match (rx bos (group (+ (not blank))) ":" eos) line)
+ 	 `(nil ,(match-string 1 line))))
+      (tramp-process-lines nil tramp-rclone-program "listremotes"))))
+ 
+@@ -365,7 +365,7 @@
+ 	  (tramp-rclone-maybe-open-connection v)
+ 	  ;; TODO: This shall be handled by `expand-file-name'.
+ 	  (setq localname
+-		(replace-regexp-in-string (rx bol ".") "" (or localname "")))
++		(replace-regexp-in-string (rx bos ".") "" (or localname "")))
+ 	  (format "%s%s" (tramp-fuse-mounted-p v) localname)))
+     ;; It is a local file name.
+     filename))
+--- emacs-30.2/lisp/net/tramp-smb.el
++++ emacs-30.2/lisp/net/tramp-smb.el
+@@ -1550,7 +1550,7 @@
+   "Return the share name of LOCALNAME."
+   (save-match-data
+     (let ((localname (tramp-file-name-unquote-localname vec)))
+-      (when (string-match (rx bol (? "/") (group (+ (not "/"))) "/") localname)
++      (when (string-match (rx bos (? "/") (group (+ (not "/"))) "/") localname)
+ 	(match-string 1 localname)))))
+ 
+ (defun tramp-smb-get-localname (vec)
+@@ -1561,7 +1561,7 @@
+       (setq
+        localname
+        (if (string-match
+-	    (rx bol (? "/") (+ (not "/")) (group "/" (* nonl))) localname)
++	    (rx bos (? "/") (+ (not "/")) (group "/" (* nonl))) localname)
+ 	   ;; There is a share, separated by "/".
+ 	   (if (not (tramp-smb-get-cifs-capabilities vec))
+ 	       (mapconcat
+@@ -1569,7 +1569,7 @@
+ 		(match-string 1 localname) "")
+ 	     (match-string 1 localname))
+ 	 ;; There is just a share.
+-	 (if (string-match (rx bol (? "/") (group (+ (not "/"))) eol) localname)
++	 (if (string-match (rx bos (? "/") (group (+ (not "/"))) eos) localname)
+ 	     (match-string 1 localname)
+ 	   "")))
+ 
+--- emacs-30.2/lisp/net/tramp.el
++++ emacs-30.2/lisp/net/tramp.el
+@@ -973,11 +973,11 @@
+ 
+ (defun tramp-build-prefix-regexp ()
+   "Return `tramp-prefix-regexp'."
+-  (rx bol (literal (tramp-build-prefix-format))))
++  (rx bos (literal (tramp-build-prefix-format))))
+ 
+ (defvar tramp-prefix-regexp nil ; Initialized when defining `tramp-syntax'!
+   "Regexp matching the very beginning of Tramp file names.
+-Should always start with \"^\".  Derived from `tramp-prefix-format'.")
++Should always start with \"\\\\=`\".  Derived from `tramp-prefix-format'.")
+ 
+ (defconst tramp-method-regexp-alist
+   `((default . ,(rx (| (literal tramp-default-method-marker) (>= 2 alnum))))
+@@ -1019,7 +1019,10 @@
+   "Regexp matching delimiter between method and user or host names.
+ Derived from `tramp-postfix-method-format'.")
+ 
+-(defconst tramp-user-regexp (rx (+ (not (any "/:|" blank))))
++(defconst tramp-user-regexp
++  (rx (| (+ (not (any "/\\^$?*:;|[]{}()<>`'\"" blank)))
++	 ;; Environment variable.
++	 (: "$" (+ (any "_" alnum)))))
+   "Regexp matching user names.")
+ 
+ (defconst tramp-prefix-domain-format "%"
+@@ -1801,6 +1804,8 @@
+ 	    (hop       (match-string (nth 5 tramp-file-name-structure) name))
+ 	    domain port v)
+ 	(when user
++	  (while (string-match (rx bos "$" (group (+ (any "_" alnum))) eos) user)
++	    (setq user (getenv (match-string 1 user))))
+ 	  (when (string-match tramp-user-with-domain-regexp user)
+ 	    (setq domain (match-string 2 user)
+ 		  user (match-string 1 user))))
+@@ -2491,9 +2496,9 @@
+ 	;; `file-remote-p' is called for everything, even for symbolic
+ 	;; links which look remote.  We don't want to get an error.
+ 	(non-essential (or non-essential (eq operation 'file-remote-p))))
++    (setq filename (tramp-replace-environment-variables filename))
+     (if (tramp-tramp-file-p filename)
+ 	(save-match-data
+-          (setq filename (tramp-replace-environment-variables filename))
+           (with-parsed-tramp-file-name filename nil
+             (let ((current-connection tramp-current-connection)
+ 		  (foreign
+@@ -6537,6 +6542,9 @@
+ 			       (caar attr))
+ 			      (decode-coding-string
+ 			       (match-string 1 (caar attr)) 'utf-8))))
++	       ;; Quote remote-like symlink.
++	       (when (and (stringp (car attr)) (tramp-tramp-file-p (car attr)))
++		 (setcar attr (file-name-quote (car attr) 'top)))
+ 	       ;; Set file's gid change bit.
+ 	       (setcar
+ 		(nthcdr 9 attr)
+--- emacs-30.2/test/lisp/net/tramp-tests.el
++++ emacs-30.2/test/lisp/net/tramp-tests.el
+@@ -325,6 +325,7 @@
+ 	  (should (tramp-tramp-file-p "/method:user@:"))
+ 	  (should (tramp-tramp-file-p "/method:user@host:"))
+ 	  (should (tramp-tramp-file-p "/method:user@email@host:"))
++	  (should (tramp-tramp-file-p "/method:$USER@host:"))
+ 
+ 	  ;; Using a port.
+ 	  (should (tramp-tramp-file-p "/method:host#1234:"))
+@@ -421,6 +422,7 @@
+ 	  (should (tramp-tramp-file-p "/user@:"))
+ 	  (should (tramp-tramp-file-p "/user@host:"))
+ 	  (should (tramp-tramp-file-p "/user@email@host:"))
++	  (should (tramp-tramp-file-p "/$USER@host:"))
+ 
+ 	  ;; Using a port.
+ 	  (should (tramp-tramp-file-p "/host#1234:"))
+@@ -483,6 +485,7 @@
+ 	  (should (tramp-tramp-file-p "/[method/user@]"))
+ 	  (should (tramp-tramp-file-p "/[method/user@host]"))
+ 	  (should (tramp-tramp-file-p "/[method/user@email@host]"))
++	  (should (tramp-tramp-file-p "/[method/$USER@host]"))
+ 
+ 	  ;; Using a port.
+ 	  (should (tramp-tramp-file-p "/[method/host#1234]"))
+@@ -671,6 +674,28 @@
+ 	  (should (string-equal
+ 		   (file-remote-p "/method:user@email@host:" 'hop) nil))
+ 
++	  ;; Expand environment variable.  It can be cascaded.
++	  (with-environment-variables
++	      (("REMOTE_USER" "$REMOTE_USER1") ("REMOTE_USER1" "remote-user"))
++	    (should (string-equal
++		     (file-remote-p "/method:$REMOTE_USER@host:")
++		     (format "/%s:%s@%s:" "method" "remote-user" "host")))
++	    (should
++	     (string-equal
++	      (file-remote-p "/method:$REMOTE_USER@host:" 'method) "method"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/method:$REMOTE_USER@host:" 'user) "remote-user"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/method:$REMOTE_USER@host:" 'host) "host"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/method:$REMOTE_USER@host:" 'localname) ""))
++	    (should
++	     (string-equal
++	      (file-remote-p "/method:$REMOTE_USER@host:" 'hop) nil)))
++
+ 	  ;; Expand `tramp-default-method' and `tramp-default-user'.
+ 	  (should
+ 	   (string-equal
+@@ -1151,6 +1176,28 @@
+ 	  (should (string-equal
+ 		   (file-remote-p "/user@email@host:" 'hop) nil))
+ 
++	  ;; Expand environment variable.  It can be cascaded.
++	  (with-environment-variables
++	      (("REMOTE_USER" "$REMOTE_USER1") ("REMOTE_USER1" "remote-user"))
++	    (should (string-equal
++		     (file-remote-p "/$REMOTE_USER@host:")
++		     (format "/%s@%s:" "remote-user" "host")))
++	    (should
++	     (string-equal
++	      (file-remote-p "/$REMOTE_USER@host:" 'method) "default-method"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/$REMOTE_USER@host:" 'user) "remote-user"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/$REMOTE_USER@host:" 'host) "host"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/$REMOTE_USER@host:" 'localname) ""))
++	    (should
++	     (string-equal
++	      (file-remote-p "/$REMOTE_USER@host:" 'hop) nil)))
++
+ 	  ;; Expand `tramp-default-method' and `tramp-default-user'.
+ 	  (should (string-equal
+ 		   (file-remote-p "/host#1234:")
+@@ -1617,6 +1664,28 @@
+ 	  (should (string-equal
+ 		   (file-remote-p "/[method/user@email@host]" 'hop) nil))
+ 
++	  ;; Expand environment variable.  It can be cascaded.
++	  (with-environment-variables
++	      (("REMOTE_USER" "$REMOTE_USER1") ("REMOTE_USER1" "remote-user"))
++	    (should (string-equal
++		     (file-remote-p "/[method/$REMOTE_USER@host]")
++		     (format "/[%s/%s@%s]" "method" "remote-user" "host")))
++	    (should
++	     (string-equal
++	      (file-remote-p "/[method/$REMOTE_USER@host]" 'method) "method"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/[method/$REMOTE_USER@host]" 'user) "remote-user"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/[method/$REMOTE_USER@host]" 'host) "host"))
++	    (should
++	     (string-equal
++	      (file-remote-p "/[method/$REMOTE_USER@host]" 'localname) ""))
++	    (should
++	     (string-equal
++	      (file-remote-p "/[method/$REMOTE_USER@host]" 'hop) nil)))
++
+ 	  ;; Expand `tramp-default-method' and `tramp-default-user'.
+ 	  (should (string-equal
+ 		   (file-remote-p "/[/host#1234]")

diff --git a/emacs.spec b/emacs.spec
index e7579f0..dd7867a 100644
--- a/emacs.spec
+++ b/emacs.spec
@@ -71,6 +71,11 @@ Patch:         0001-Mitigate-arbitrary-code-execution-vulnerability.patch
 # https://bugzilla.redhat.com/show_bug.cgi?id=2523273
 Patch:         0001-Fix-undefined-behavior-in-pbm_load.patch
 
+# CVE-2026-79992
+# https://bugzilla.redhat.com/show_bug.cgi?id=2523674
+# https://gitweb.gentoo.org/proj/emacs-patches.git/tree/emacs/30.2/05_all_tramp.patch
+Patch:         05_all_tramp.patch
+
 BuildRequires: alsa-lib-devel
 BuildRequires: atk-devel
 BuildRequires: autoconf

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-28 11:32 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-28 11:32 [rpms/emacs] f44: Fix CVE-2026-79992: Local shell command injection through the user field in emacs tramp Peter Oliver

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox