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